summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitlab-ci-coverage-runners.yml8
-rw-r--r--.gitlab-ci-default-runners.yml44
-rw-r--r--.gitlab-ci-main.yml9
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW.txt86
-rw-r--r--auth/credentials/credentials.c5
-rw-r--r--auth/credentials/credentials.h1
-rw-r--r--auth/credentials/credentials_secrets.c31
-rw-r--r--auth/credentials/tests/test_creds.c37
-rw-r--r--auth/gensec/gensec_start.c2
-rw-r--r--bootstrap/.gitlab-ci.yml6
-rw-r--r--bootstrap/config.py3
-rwxr-xr-xbootstrap/generated-dists/centos8s/bootstrap.sh3
-rw-r--r--bootstrap/sha1sum.txt2
-rw-r--r--buildtools/wafsamba/samba_pidl.py4
-rw-r--r--buildtools/wafsamba/samba_third_party.py4
-rw-r--r--buildtools/wafsamba/samba_version.py5
-rw-r--r--ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml4
-rw-r--r--ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c50
-rw-r--r--examples/winexe/wscript21
-rw-r--r--examples/winexe/wscript_build4
-rwxr-xr-xlib/fuzzing/decode_ndr_X_crash12
-rw-r--r--lib/ldb-samba/ldif_handlers.c94
-rw-r--r--lib/ldb/ABI/ldb-2.9.1.sigs305
-rw-r--r--lib/ldb/ABI/pyldb-util-2.9.1.sigs3
-rw-r--r--lib/ldb/common/attrib_handlers.c53
-rw-r--r--lib/ldb/common/ldb_dn.c30
-rw-r--r--lib/ldb/common/ldb_msg.c13
-rw-r--r--lib/ldb/common/qsort.c2
-rw-r--r--lib/ldb/include/ldb.h16
-rw-r--r--lib/ldb/modules/sort.c19
-rw-r--r--lib/ldb/wscript2
-rw-r--r--lib/socket/interfaces.c22
-rw-r--r--lib/torture/torture.h20
-rw-r--r--lib/util/charset/codepoints.c15
-rw-r--r--lib/util/charset/tests/charset.c31
-rw-r--r--lib/util/charset/util_str.c9
-rw-r--r--lib/util/data_blob.c5
-rw-r--r--lib/util/tests/binsearch.c6
-rw-r--r--lib/util/tests/test_ms_fnmatch.c2
-rw-r--r--lib/util/tsort.h19
-rw-r--r--libcli/nbt/libnbt.h3
-rw-r--r--libcli/nbt/nbtsocket.c44
-rw-r--r--libcli/security/dom_sid.c14
-rw-r--r--libcli/smb/smbXcli_base.c104
-rw-r--r--libcli/smb/smbXcli_base.h5
-rw-r--r--pidl/lib/Parse/Pidl/Typelist.pm14
-rw-r--r--python/samba/gp/gpclass.py4
-rw-r--r--python/samba/tests/blackbox/misc_dfs_widelink.py86
-rw-r--r--python/samba/tests/dns_base.py213
-rw-r--r--python/samba/tests/dns_tkey.py325
-rw-r--r--python/samba/tests/join.py2
-rw-r--r--python/samba/tests/ntacls.py2
-rwxr-xr-xscript/autobuild.py3
-rw-r--r--selftest/flapping.d/gitlab-setxattr-security18
-rw-r--r--selftest/knownfail-32bit8
-rwxr-xr-xselftest/target/Samba4.pm2
-rw-r--r--source3/include/fstring.h27
-rw-r--r--source3/include/includes.h5
-rw-r--r--source3/include/nameserv.h380
-rw-r--r--source3/include/session.h1
-rw-r--r--source3/include/smb.h26
-rw-r--r--source3/lib/sessionid_tdb.c8
-rw-r--r--source3/lib/util_tdb.c4
-rw-r--r--source3/libads/kerberos.c32
-rw-r--r--source3/libads/ldap.c16
-rw-r--r--source3/librpc/idl/ads.idl1
-rw-r--r--source3/libsmb/clidgram.c6
-rw-r--r--source3/libsmb/dsgetdcname.c29
-rw-r--r--source3/libsmb/libsmb_xattr.c14
-rw-r--r--source3/libsmb/namequery.c21
-rw-r--r--source3/libsmb/nmblib.c12
-rw-r--r--source3/libsmb/nmblib.h2
-rw-r--r--source3/libsmb/unexpected.c18
-rw-r--r--source3/libsmb/unexpected.h2
-rw-r--r--source3/locking/brlock.c7
-rw-r--r--source3/modules/posixacl_xattr.c6
-rw-r--r--source3/modules/vfs_default.c6
-rw-r--r--source3/modules/vfs_recycle.c176
-rw-r--r--source3/modules/vfs_vxfs.c6
-rw-r--r--source3/modules/vfs_widelinks.c13
-rw-r--r--source3/nmbd/nmbd.h382
-rw-r--r--source3/nmbd/nmbd_packets.c1
-rw-r--r--source3/rpc_server/wkssvc/srv_wkssvc_nt.c2
-rwxr-xr-xsource3/script/tests/test_recycle.sh5
-rwxr-xr-xsource3/script/tests/test_widelink_dfs_ci.sh72
-rwxr-xr-xsource3/selftest/tests.py11
-rw-r--r--source3/smbd/files.c18
-rw-r--r--source3/smbd/globals.h5
-rw-r--r--source3/smbd/smb2_server.c11
-rw-r--r--source3/smbd/smb2_sesssetup.c18
-rw-r--r--source3/smbd/smb2_tcon.c4
-rw-r--r--source3/utils/conn_tdb.c12
-rw-r--r--source3/utils/conn_tdb.h1
-rw-r--r--source3/utils/net_ads.c6
-rw-r--r--source3/utils/net_registry.c2
-rw-r--r--source3/utils/sharesec.c8
-rw-r--r--source3/utils/smbcacls.c15
-rw-r--r--source3/utils/status.c82
-rw-r--r--source3/utils/status.h1
-rw-r--r--source3/utils/status_json.c2
-rw-r--r--source3/winbindd/idmap_ad.c11
-rw-r--r--source3/wscript_build1
-rw-r--r--source4/dns_server/dns_crypto.c49
-rw-r--r--source4/dns_server/dns_query.c27
-rw-r--r--source4/dns_server/dns_update.c11
-rw-r--r--source4/dns_server/dnsserver_common.c8
-rw-r--r--source4/dsdb/repl/drepl_out_helpers.c26
-rw-r--r--source4/dsdb/samdb/ldb_modules/operational.c2
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c17
-rw-r--r--source4/dsdb/schema/schema_set.c14
-rw-r--r--source4/libcli/dgram/dgramsocket.c40
-rw-r--r--source4/libcli/dgram/libdgram.h3
-rw-r--r--source4/libcli/smb2/session.c16
-rw-r--r--source4/libcli/smb2/smb2.h2
-rw-r--r--source4/nbt_server/dgram/request.c56
-rw-r--r--source4/nbt_server/interfaces.c29
-rw-r--r--source4/nbt_server/nbt_server.c143
-rw-r--r--source4/nbt_server/nbt_server.h2
-rw-r--r--source4/nbt_server/wins/winsdb.c5
-rw-r--r--source4/nbt_server/wins/winsserver.c3
-rw-r--r--source4/nbt_server/wscript_build2
-rw-r--r--source4/ntvfs/posix/pvfs_streams.c3
-rw-r--r--source4/rpc_server/dnsserver/dnsdata.c16
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c7
-rwxr-xr-xsource4/selftest/tests.py14
-rw-r--r--source4/torture/smb2/ioctl.c64
-rw-r--r--source4/torture/smb2/session.c629
-rwxr-xr-xtestprogs/blackbox/test_ldap_token.sh115
-rwxr-xr-xtestprogs/blackbox/test_trust_token.sh5
-rw-r--r--third_party/socket_wrapper/socket_wrapper.c45
-rw-r--r--third_party/socket_wrapper/wscript3
-rw-r--r--third_party/uid_wrapper/uid_wrapper.c58
-rw-r--r--third_party/uid_wrapper/wscript4
-rw-r--r--wscript20
135 files changed, 3881 insertions, 901 deletions
diff --git a/.gitlab-ci-coverage-runners.yml b/.gitlab-ci-coverage-runners.yml
index 0f6b2ec..331c5d2 100644
--- a/.gitlab-ci-coverage-runners.yml
+++ b/.gitlab-ci-coverage-runners.yml
@@ -1,10 +1,4 @@
include:
- /.gitlab-ci-default-runners.yml
-.shared_runner_test:
- # We need the more powerful n1-standard-2 runners
- # in order to handle the lcov overhead.
- #
- # See .gitlab-ci-default-runners.yml for more details
- tags:
- - gitlab-org-docker
+# Currently we're happy with the defaults
diff --git a/.gitlab-ci-default-runners.yml b/.gitlab-ci-default-runners.yml
index f73f868..bdc504a 100644
--- a/.gitlab-ci-default-runners.yml
+++ b/.gitlab-ci-default-runners.yml
@@ -1,48 +1,26 @@
-# From https://docs.gitlab.com/ee/user/gitlab_com/#shared-runners:
+# From https://docs.gitlab.com/ee/ci/runners/hosted_runners/linux.html
#
# ...
#
-# All your CI/CD jobs run on n1-standard-1 instances with 3.75GB of RAM, CoreOS
-# and the latest Docker Engine installed. Instances provide 1 vCPU and 25GB of
-# HDD disk space. The default region of the VMs is US East1. Each instance is
-# used only for one job, this ensures any sensitive data left on the system can’t
-# be accessed by other people their CI jobs.
-#
-# The gitlab-shared-runners-manager-X.gitlab.com fleet of runners are dedicated
-# for GitLab projects as well as community forks of them. They use a slightly
-# larger machine type (n1-standard-2) and have a bigger SSD disk size. They don’t
-# run untagged jobs and unlike the general fleet of shared runners, the instances
-# are re-used up to 40 times.
-#
-# ...
-#
-# The n1-standard-1 runners seem to be tagged with 'docker' together with 'gce'.
-#
-# The more powerful n1-standard-2 runners seem to be tagged with
-# 'gitlab-org-docker' or some with just 'gitlab-org'.
-#
+# Runner Tag vCPUs Memory Storage
+# saas-linux-small-amd64 2 8 GB 25 GB
#
# Our current private runner 'docker', 'samba-ci-private', 'shared' and
# 'ubuntu2204'. It runs with an ubuntu2204 kernel (5.15) and provides an
-# ext4 filesystem and similar RAM as the n1-standard-2 runners.
+# ext4 filesystem, 2 CPU and 4 GB (shared tag) 8G (samba-ci-private tag) RAM.
#
.shared_runner_build:
- # We use n1-standard-1 shared runners by default.
- #
- # There are currently 5 shared runners with 'docker' and 'gce',
- # while there are only 2 provising 'docker' together with 'shared'.
+ # We use saas-linux-small-amd64 shared runners by default.
+ # We avoid adding explicit tags for them in order
+ # to work with potential changes in future
#
- # We used to fallback to our private runner if the docker+shared runners
- # were busy, but now that we use the 5 docker+gce runners, we try to only
- # use shared runners without a fallback to our private runner!
- # Lets see how that will work out.
- tags:
- - docker
- - gce
+ # In order to generate valid yaml, we define a dummy variable...
+ variables:
+ SAMBA_SHARED_RUNNER_BUILD_DUMMY_VARIABLE: shared_runner_build
.shared_runner_test:
- # Currently we're fine using the n1-standard-1 runners also for testing
+ # We use saas-linux-small-amd64 shared runners by default.
extends: .shared_runner_build
.private_runner_test:
diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml
index add5f32..face210 100644
--- a/.gitlab-ci-main.yml
+++ b/.gitlab-ci-main.yml
@@ -47,7 +47,7 @@ variables:
# Set this to the contents of bootstrap/sha1sum.txt
# which is generated by bootstrap/template.py --render
#
- SAMBA_CI_CONTAINER_TAG: 9a406973474a7903fe7fd6215226660911ed73c0
+ SAMBA_CI_CONTAINER_TAG: b078783e082ead539940faaa644567bf4ed67f67
#
# We use the ubuntu2204 image as default as
# it matches what we have on atb-devel-224
@@ -112,8 +112,14 @@ include:
before_script:
- uname -a
+ - ls -l /sys/module/
+ - ls -l /sys/kernel/security/
+ - if [ -e /sys/kernel/security/lsm ]; then cat /sys/kernel/security/lsm ; echo; fi
+ - if [ -e /proc/config.gz ]; then sudo zcat /proc/config.gz; echo; fi
- lsb_release -a
- cat /etc/os-release
+ - id
+ - cat /proc/self/status
- lscpu
- cat /proc/cpuinfo
- mount
@@ -141,6 +147,7 @@ include:
- ccache -s
# We are already running .gitlab-ci directives from this repo, remove additional checks that break our CI
- git config --global --add safe.directory `pwd`
+ - git config --global --add safe.directory /builds/samba-team/devel/samba/.git
after_script:
- mount
- df -h
diff --git a/VERSION b/VERSION
index cfa7539..200f6cc 100644
--- a/VERSION
+++ b/VERSION
@@ -27,7 +27,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew Tridgell and the Samba Team 1992-2024"
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=20
-SAMBA_VERSION_RELEASE=1
+SAMBA_VERSION_RELEASE=2
########################################################
# If a official release has a serious bug #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 8249e93..fb964d7 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,87 @@
==============================
+ Release Notes for Samba 4.20.2
+ June 19, 2024
+ ==============================
+
+
+This is the latest stable release of the Samba 4.20 release series.
+
+
+Changes since 4.20.1
+--------------------
+
+o Jeremy Allison <jra@samba.org>
+ * BUG 15662: vfs_widelinks with DFS shares breaks case insensitivity.
+
+o Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+ * BUG 13213: Samba build is not reproducible.
+ * BUG 15569: ldb qsort might r/w out of bounds with an intransitive compare
+ function.
+ * BUG 15625: Many qsort() comparison functions are non-transitive, which can
+ lead to out-of-bounds access in some circumstances.
+
+o Andrew Bartlett <abartlet@samba.org>
+ * BUG 15638: Need to change gitlab-ci.yml tags in all branches to avoid CI
+ bill.
+ * BUG 15654: We have added new options --vendor-name and --vendor-patch-
+ revision arguments to ./configure to allow distributions and packagers to
+ put their name in the Samba version string so that when debugging Samba the
+ source of the binary is obvious.
+
+o Günther Deschner <gd@samba.org>
+ * BUG 15665: CTDB RADOS mutex helper misses namespace support.
+
+o Stefan Metzmacher <metze@samba.org>
+ * BUG 13019: Dynamic DNS updates with the internal DNS are not working.
+ * BUG 14981: netr_LogonSamLogonEx returns NR_STATUS_ACCESS_DENIED with
+ SysvolReady=0.
+ * BUG 15412: Anonymous smb3 signing/encryption should be allowed (similar to
+ Windows Server 2022).
+ * BUG 15573: Panic in dreplsrv_op_pull_source_apply_changes_trigger.
+ * BUG 15620: s4:nbt_server: does not provide unexpected handling, so winbindd
+ can't use nmb requests instead cldap.
+ * BUG 15642: winbindd, net ads join and other things don't work on an ipv6
+ only host.
+ * BUG 15659: Segmentation fault when deleting files in vfs_recycle.
+ * BUG 15664: Panic in vfs_offload_token_db_fetch_fsp().
+ * BUG 15666: "client use kerberos" and --use-kerberos is ignored for the
+ machine account.
+
+o Noel Power <noel.power@suse.com>
+ * BUG 15435: Regression DFS not working with widelinks = true.
+
+o Andreas Schneider <asn@samba.org>
+ * BUG 15633: samba-gpupdate - Invalid NtVer in netlogon_samlogon_response.
+ * BUG 15653: idmap_ad creates an incorrect local krb5.conf in case of trusted
+ domain lookups.
+ * BUG 15660: The images don't build after the git security release and CentOS
+ 8 Stream is EOL.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical:matrix.org matrix room, or
+#samba-technical IRC channel on irc.libera.chat.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+ ==============================
Release Notes for Samba 4.20.1
May 08, 2024
==============================
@@ -51,8 +134,7 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
==============================
Release Notes for Samba 4.20.0
March 27, 2024
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index 20ab858..e563be3 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -146,6 +146,11 @@ _PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct
return creds->kerberos_state;
}
+_PUBLIC_ enum credentials_obtained cli_credentials_get_kerberos_state_obtained(struct cli_credentials *creds)
+{
+ return creds->kerberos_state_obtained;
+}
+
_PUBLIC_ const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *creds)
{
return creds->forced_sasl_mech;
diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h
index 341c984..16eddcc 100644
--- a/auth/credentials/credentials.h
+++ b/auth/credentials/credentials.h
@@ -267,6 +267,7 @@ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cr
const char *cli_credentials_get_self_service(struct cli_credentials *cred);
const char *cli_credentials_get_target_service(struct cli_credentials *cred);
enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds);
+enum credentials_obtained cli_credentials_get_kerberos_state_obtained(struct cli_credentials *creds);
const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *cred);
enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds);
NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
diff --git a/auth/credentials/credentials_secrets.c b/auth/credentials/credentials_secrets.c
index 8469d6e..906f3ff 100644
--- a/auth/credentials/credentials_secrets.c
+++ b/auth/credentials/credentials_secrets.c
@@ -370,13 +370,17 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credenti
}
if (secrets_tdb_password_more_recent) {
- enum credentials_use_kerberos use_kerberos =
- CRED_USE_KERBEROS_DISABLED;
char *machine_account = talloc_asprintf(tmp_ctx, "%s$", lpcfg_netbios_name(lp_ctx));
cli_credentials_set_password(cred, secrets_tdb_password, CRED_SPECIFIED);
cli_credentials_set_old_password(cred, secrets_tdb_old_password, CRED_SPECIFIED);
cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
if (strequal(domain, lpcfg_workgroup(lp_ctx))) {
+ enum credentials_use_kerberos use_kerberos =
+ cli_credentials_get_kerberos_state(cred);
+ enum credentials_obtained use_kerberos_obtained =
+ cli_credentials_get_kerberos_state_obtained(cred);
+ bool is_ad = false;
+
cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_SPECIFIED);
switch (server_role) {
@@ -388,13 +392,28 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credenti
FALL_THROUGH;
case ROLE_ACTIVE_DIRECTORY_DC:
case ROLE_IPA_DC:
- use_kerberos = CRED_USE_KERBEROS_DESIRED;
+ is_ad = true;
break;
}
+
+ if (use_kerberos != CRED_USE_KERBEROS_DESIRED || is_ad) {
+ /*
+ * Keep an explicit selection
+ *
+ * For AD domains we also keep
+ * CRED_USE_KERBEROS_DESIRED
+ */
+ } else if (use_kerberos_obtained <= CRED_SMB_CONF) {
+ /*
+ * Disable kerberos by default within
+ * an NT4 domain.
+ */
+ cli_credentials_set_kerberos_state(cred,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SMB_CONF);
+ }
}
- cli_credentials_set_kerberos_state(cred,
- use_kerberos,
- CRED_SPECIFIED);
+
cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
cli_credentials_set_password_last_changed_time(cred, secrets_tdb_lct);
cli_credentials_set_secure_channel_type(cred, secrets_tdb_secure_channel_type);
diff --git a/auth/credentials/tests/test_creds.c b/auth/credentials/tests/test_creds.c
index 2cb2e6d..e79f089 100644
--- a/auth/credentials/tests/test_creds.c
+++ b/auth/credentials/tests/test_creds.c
@@ -227,6 +227,8 @@ static void torture_creds_krb5_state(void **state)
TALLOC_CTX *mem_ctx = *state;
struct cli_credentials *creds = NULL;
struct loadparm_context *lp_ctx = NULL;
+ enum credentials_obtained kerberos_state_obtained;
+ enum credentials_use_kerberos kerberos_state;
bool ok;
lp_ctx = loadparm_init_global(true);
@@ -234,18 +236,27 @@ static void torture_creds_krb5_state(void **state)
creds = cli_credentials_init(mem_ctx);
assert_non_null(creds);
- assert_int_equal(creds->kerberos_state_obtained, CRED_UNINITIALISED);
- assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
+ kerberos_state_obtained =
+ cli_credentials_get_kerberos_state_obtained(creds);
+ kerberos_state = cli_credentials_get_kerberos_state(creds);
+ assert_int_equal(kerberos_state_obtained, CRED_UNINITIALISED);
+ assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
ok = cli_credentials_set_conf(creds, lp_ctx);
assert_true(ok);
- assert_int_equal(creds->kerberos_state_obtained, CRED_SMB_CONF);
- assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
+ kerberos_state_obtained =
+ cli_credentials_get_kerberos_state_obtained(creds);
+ kerberos_state = cli_credentials_get_kerberos_state(creds);
+ assert_int_equal(kerberos_state_obtained, CRED_SMB_CONF);
+ assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
ok = cli_credentials_guess(creds, lp_ctx);
assert_true(ok);
- assert_int_equal(creds->kerberos_state_obtained, CRED_SMB_CONF);
- assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
+ kerberos_state_obtained =
+ cli_credentials_get_kerberos_state_obtained(creds);
+ kerberos_state = cli_credentials_get_kerberos_state(creds);
+ assert_int_equal(kerberos_state_obtained, CRED_SMB_CONF);
+ assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
assert_int_equal(creds->ccache_obtained, CRED_GUESS_FILE);
assert_non_null(creds->ccache);
@@ -253,15 +264,21 @@ static void torture_creds_krb5_state(void **state)
CRED_USE_KERBEROS_REQUIRED,
CRED_SPECIFIED);
assert_true(ok);
- assert_int_equal(creds->kerberos_state_obtained, CRED_SPECIFIED);
- assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_REQUIRED);
+ kerberos_state_obtained =
+ cli_credentials_get_kerberos_state_obtained(creds);
+ kerberos_state = cli_credentials_get_kerberos_state(creds);
+ assert_int_equal(kerberos_state_obtained, CRED_SPECIFIED);
+ assert_int_equal(kerberos_state, CRED_USE_KERBEROS_REQUIRED);
ok = cli_credentials_set_kerberos_state(creds,
CRED_USE_KERBEROS_DISABLED,
CRED_SMB_CONF);
assert_false(ok);
- assert_int_equal(creds->kerberos_state_obtained, CRED_SPECIFIED);
- assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_REQUIRED);
+ kerberos_state_obtained =
+ cli_credentials_get_kerberos_state_obtained(creds);
+ kerberos_state = cli_credentials_get_kerberos_state(creds);
+ assert_int_equal(kerberos_state_obtained, CRED_SPECIFIED);
+ assert_int_equal(kerberos_state, CRED_USE_KERBEROS_REQUIRED);
}
diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c
index 072188a..bcf98bd 100644
--- a/auth/gensec/gensec_start.c
+++ b/auth/gensec/gensec_start.c
@@ -1103,7 +1103,7 @@ _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
}
static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
- return (*gs2)->priority - (*gs1)->priority;
+ return NUMERIC_CMP((*gs2)->priority, (*gs1)->priority);
}
int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
diff --git a/bootstrap/.gitlab-ci.yml b/bootstrap/.gitlab-ci.yml
index ba82cdc..77b4e4f 100644
--- a/bootstrap/.gitlab-ci.yml
+++ b/bootstrap/.gitlab-ci.yml
@@ -6,9 +6,7 @@
# We need to make sure we only use gitlab.com
# runners and not our own runners, as our current runners
# don't allow 'docker build ...' to run.
- - docker
- - gce
- - shared
+ - saas-linux-small-amd64
variables:
SAMBA_CI_IS_BROKEN_IMAGE: "no"
SAMBA_CI_TEST_JOB: "samba-o3"
@@ -47,7 +45,7 @@
diff -u bootstrap/sha1sum.txt /tmp/sha1sum-template.txt
# run smoke test with samba-o3 or samba-fuzz
podman run --volume $(pwd):/src:ro ${ci_image_name} \
- /bin/bash -c "git clone /src samba && cd samba && export PKG_CONFIG_PATH=/usr/lib64/compat-gnutls34/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig && script/autobuild.py ${SAMBA_CI_TEST_JOB} --verbose --nocleanup --keeplogs --tail --testbase /tmp/samba-testbase"
+ /bin/bash -c "git config --global --add safe.directory /src/.git && git clone /src samba && cd samba && export PKG_CONFIG_PATH=/usr/lib64/compat-gnutls34/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig && script/autobuild.py ${SAMBA_CI_TEST_JOB} --verbose --nocleanup --keeplogs --tail --testbase /tmp/samba-testbase"
podman tag ${ci_image_name} ${ci_image_path}:${SAMBA_CI_CONTAINER_TAG}
podman tag ${ci_image_name} ${ci_image_path}:${timestamp_tag}
# We build all images, but only upload is it's not marked as broken
diff --git a/bootstrap/config.py b/bootstrap/config.py
index 11d8314..a5a7366 100644
--- a/bootstrap/config.py
+++ b/bootstrap/config.py
@@ -241,6 +241,9 @@ CENTOS8S_YUM_BOOTSTRAP = r"""
{GENERATED_MARKER}
set -xueo pipefail
+sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
+sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
+
yum update -y
yum install -y dnf-plugins-core
yum install -y epel-release
diff --git a/bootstrap/generated-dists/centos8s/bootstrap.sh b/bootstrap/generated-dists/centos8s/bootstrap.sh
index 4b2c62c..9e0aabb 100755
--- a/bootstrap/generated-dists/centos8s/bootstrap.sh
+++ b/bootstrap/generated-dists/centos8s/bootstrap.sh
@@ -7,6 +7,9 @@
set -xueo pipefail
+sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
+sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
+
yum update -y
yum install -y dnf-plugins-core
yum install -y epel-release
diff --git a/bootstrap/sha1sum.txt b/bootstrap/sha1sum.txt
index 61ecaf0..1bb5e92 100644
--- a/bootstrap/sha1sum.txt
+++ b/bootstrap/sha1sum.txt
@@ -1 +1 @@
-9a406973474a7903fe7fd6215226660911ed73c0
+b078783e082ead539940faaa644567bf4ed67f67
diff --git a/buildtools/wafsamba/samba_pidl.py b/buildtools/wafsamba/samba_pidl.py
index 72997c8..e101086 100644
--- a/buildtools/wafsamba/samba_pidl.py
+++ b/buildtools/wafsamba/samba_pidl.py
@@ -81,7 +81,9 @@ def SAMBA_PIDL(bld, pname, source,
else:
cc = 'CC="%s"' % bld.CONFIG_GET("CC")
- t = bld(rule='cd ${PIDL_LAUNCH_DIR} && %s%s %s ${PERL} ${PIDL} --quiet ${OPTIONS} --outputdir ${OUTPUTDIR} -- "${IDLSRC}"' % (pidl_dev, cpp, cc),
+ t = bld(rule=('cd ${PIDL_LAUNCH_DIR} && PERL_HASH_SEED=0 %s%s %s ${PERL} '
+ '${PIDL} --quiet ${OPTIONS} --outputdir ${OUTPUTDIR} -- "${IDLSRC}"' %
+ (pidl_dev, cpp, cc)),
ext_out = '.c',
before = 'c',
update_outputs = True,
diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py
index 5289848..a42bb2d 100644
--- a/buildtools/wafsamba/samba_third_party.py
+++ b/buildtools/wafsamba/samba_third_party.py
@@ -24,7 +24,7 @@ Build.BuildContext.CHECK_CMOCKA = CHECK_CMOCKA
@conf
def CHECK_SOCKET_WRAPPER(conf):
- return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.4.2')
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.4.3')
Build.BuildContext.CHECK_SOCKET_WRAPPER = CHECK_SOCKET_WRAPPER
@conf
@@ -39,7 +39,7 @@ Build.BuildContext.CHECK_RESOLV_WRAPPER = CHECK_RESOLV_WRAPPER
@conf
def CHECK_UID_WRAPPER(conf):
- return conf.CHECK_BUNDLED_SYSTEM_PKG('uid_wrapper', minversion='1.3.0')
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('uid_wrapper', minversion='1.3.1')
Build.BuildContext.CHECK_UID_WRAPPER = CHECK_UID_WRAPPER
@conf
diff --git a/buildtools/wafsamba/samba_version.py b/buildtools/wafsamba/samba_version.py
index 31103e0..576168f 100644
--- a/buildtools/wafsamba/samba_version.py
+++ b/buildtools/wafsamba/samba_version.py
@@ -253,6 +253,11 @@ def samba_version_file(version_file, path, env=None, is_install=True):
print("Failed to parse line %s from %s" % (line, version_file))
raise
+ if "SAMBA_VERSION_VENDOR_SUFFIX" in env:
+ version_dict["SAMBA_VERSION_VENDOR_SUFFIX"] = env.SAMBA_VERSION_VENDOR_SUFFIX
+ if "SAMBA_VERSION_VENDOR_PATCH" in env:
+ version_dict["SAMBA_VERSION_VENDOR_PATCH"] = str(env.SAMBA_VERSION_VENDOR_PATCH)
+
return SambaVersion(version_dict, path, env=env, is_install=is_install)
diff --git a/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml b/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
index f558f87..93d79ce 100644
--- a/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
+++ b/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
@@ -29,12 +29,14 @@
<manvolnum>5</manvolnum></citerefentry>:
</para>
<screen format="linespecific">
-cluster lock = !ctdb_mutex_ceph_rados_helper [Cluster] [User] [Pool] [Object]
+cluster lock = !ctdb_mutex_ceph_rados_helper [Cluster] [User] [Pool] [Object] [Timeout] [-n Namespace]
Cluster: Ceph cluster name (e.g. ceph)
User: Ceph cluster user name (e.g. client.admin)
Pool: Ceph RADOS pool name
Object: Ceph RADOS object name
+Timeout: Ceph RADOS lock duration in seconds (optional)
+Namespace: Ceph RADOS pool namespace (optional)
</screen>
<para>
The Ceph cluster <parameter>Cluster</parameter> must be up and running,
diff --git a/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c b/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
index 7d868a3..46566c9 100644
--- a/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
+++ b/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
@@ -42,9 +42,18 @@
static char *progname = NULL;
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s <Ceph Cluster> <Ceph user> "
+ "<RADOS pool> <RADOS object> "
+ "[lock duration secs] [-n RADOS namespace]\n",
+ progname);
+}
+
static int ctdb_mutex_rados_ctx_create(const char *ceph_cluster_name,
const char *ceph_auth_name,
const char *pool_name,
+ const char *namespace,
rados_t *_ceph_cluster,
rados_ioctx_t *_ioctx)
{
@@ -87,6 +96,10 @@ static int ctdb_mutex_rados_ctx_create(const char *ceph_cluster_name,
return ret;
}
+ if (namespace != NULL) {
+ rados_ioctx_set_namespace(ioctx, namespace);
+ }
+
*_ceph_cluster = ceph_cluster;
*_ioctx = ioctx;
@@ -145,6 +158,7 @@ struct ctdb_mutex_rados_state {
const char *ceph_cluster_name;
const char *ceph_auth_name;
const char *pool_name;
+ const char *namespace;
const char *object;
uint64_t lock_duration_s;
int ppid;
@@ -295,15 +309,13 @@ static int ctdb_mutex_rados_mgr_reg(rados_t ceph_cluster)
int main(int argc, char *argv[])
{
int ret;
+ int opt;
struct ctdb_mutex_rados_state *cmr_state;
progname = argv[0];
- if ((argc != 5) && (argc != 6)) {
- fprintf(stderr, "Usage: %s <Ceph Cluster> <Ceph user> "
- "<RADOS pool> <RADOS object> "
- "[lock duration secs]\n",
- progname);
+ if (argc < 5) {
+ usage();
ret = -EINVAL;
goto err_out;
}
@@ -325,15 +337,36 @@ int main(int argc, char *argv[])
cmr_state->ceph_auth_name = argv[2];
cmr_state->pool_name = argv[3];
cmr_state->object = argv[4];
- if (argc == 6) {
+
+ optind = 5;
+ while ((opt = getopt(argc, argv, "n:")) != -1) {
+ switch(opt) {
+ case 'n':
+ cmr_state->namespace = optarg;
+ break;
+ default:
+ usage();
+ ret = -EINVAL;
+ goto err_ctx_cleanup;
+ }
+ }
+
+ if (argv[optind] != NULL) {
/* optional lock duration provided */
char *endptr = NULL;
- cmr_state->lock_duration_s = strtoull(argv[5], &endptr, 0);
- if ((endptr == argv[5]) || (*endptr != '\0')) {
+ cmr_state->lock_duration_s = strtoull(argv[optind], &endptr, 0);
+ if ((endptr == argv[optind]) || (*endptr != '\0')) {
fprintf(stdout, CTDB_MUTEX_STATUS_ERROR);
ret = -EINVAL;
goto err_ctx_cleanup;
}
+ if (argv[++optind] != NULL) {
+ /* incorrect count or format for optional arguments */
+ usage();
+ ret = -EINVAL;
+ goto err_ctx_cleanup;
+ }
+
} else {
cmr_state->lock_duration_s
= CTDB_MUTEX_CEPH_LOCK_DURATION_SECS_DEFAULT;
@@ -398,6 +431,7 @@ int main(int argc, char *argv[])
ret = ctdb_mutex_rados_ctx_create(cmr_state->ceph_cluster_name,
cmr_state->ceph_auth_name,
cmr_state->pool_name,
+ cmr_state->namespace,
&cmr_state->ceph_cluster,
&cmr_state->ioctx);
if (ret < 0) {
diff --git a/examples/winexe/wscript b/examples/winexe/wscript
index 6b311b1..c4f13b8 100644
--- a/examples/winexe/wscript
+++ b/examples/winexe/wscript
@@ -1,4 +1,6 @@
#!/usr/bin/env python
+import os
+
def configure(conf):
AR32 = ['i386', 'i586', 'i686']
@@ -27,5 +29,24 @@ def configure(conf):
conf.DEFINE('HAVE_WINEXE_CC_WIN64', 1);
break
+ source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
+ if source_date_epoch is None:
+ # We use the version to make up the timestamp that will be
+ # embedded in winexe.exe, to keep the build reproducible.
+ #
+ # This is less evil than it sounds. According to Raymond Chen in
+ # https://devblogs.microsoft.com/oldnewthing/20180103-00/?p=97705
+ # since Windows 10 the timestamp has been randomised.
+ #
+ # The purpose of the timestamp in Windows PE files seems to be
+ # to make spotting ABI changes in DLLs quicker, for which a
+ # random number is just as good as a real time. The timestamp
+ # in .exe files is not used.
+ import samba_version
+ v = samba_version.load_version(env=conf.env)
+ version = (v.MAJOR << 16) | (v.MINOR << 8) | v.RELEASE
+ source_date_epoch = str(version)
+
+ conf.env.SOURCE_DATE_EPOCH = source_date_epoch
conf.DEFINE("WINEXE_LDFLAGS",
"-s -Wall -Wl,-Bstatic -Wl,-Bdynamic -luserenv")
diff --git a/examples/winexe/wscript_build b/examples/winexe/wscript_build
index 3646834..1fe019c 100644
--- a/examples/winexe/wscript_build
+++ b/examples/winexe/wscript_build
@@ -69,7 +69,7 @@ bld.SAMBA_GENERATOR(
'winexesvc32_exe',
source='winexesvc.c',
target='winexesvc32.exe',
- rule='${WINEXE_CC_WIN32} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
+ rule='SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} ${WINEXE_CC_WIN32} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN32)
vars = {"WINEXE_FN": "winexesvc32_exe_binary"}
@@ -89,7 +89,7 @@ bld.SAMBA_GENERATOR(
'winexesvc64_exe',
source='winexesvc.c',
target='winexesvc64.exe',
- rule='${WINEXE_CC_WIN64} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
+ rule='SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} ${WINEXE_CC_WIN64} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN64)
vars = {"WINEXE_FN": "winexesvc64_exe_binary"}
diff --git a/lib/fuzzing/decode_ndr_X_crash b/lib/fuzzing/decode_ndr_X_crash
index 63c3cd7..d90e7ef 100755
--- a/lib/fuzzing/decode_ndr_X_crash
+++ b/lib/fuzzing/decode_ndr_X_crash
@@ -61,8 +61,9 @@ def process_one_file(f):
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('-p', '--pipe', default='$PIPE',
- help='pipe name (for output command line)')
+ parser.add_argument('-p', '--pipe', default=None,
+ help=('pipe name (for output command line, '
+ 'default is a guess or "$PIPE")'))
parser.add_argument('-t', '--type', default=None, choices=TYPES,
help='restrict to this type')
parser.add_argument('-o', '--opnum', default=None, type=int,
@@ -91,6 +92,13 @@ def main():
sys.exit(1)
for fn in args.FILES:
+ if pipe is None:
+ m = re.search(r'clusterfuzz-testcase.+-fuzz_ndr_([a-z]+)', fn)
+ if m is None:
+ pipe = '$PIPE'
+ else:
+ pipe = m.group(1)
+
if args.crash_filter is not None:
if not re.search(args.crash_filter, fn):
print_if_verbose(f"skipping {fn}")
diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
index c30fd63..4f9d67e 100644
--- a/lib/ldb-samba/ldif_handlers.c
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -150,36 +150,47 @@ bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
/*
compare two objectSids
+
+ If the SIDs seem to be strings, they are converted to binary form.
*/
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);
+ bool v1_is_string = ldif_comparision_objectSid_isString(v1);
+ bool v2_is_string = ldif_comparision_objectSid_isString(v2);
+ struct ldb_val parsed_1 = {};
+ struct ldb_val parsed_2 = {};
+ int ret;
+ /*
+ * If the ldb_vals look like SID strings (i.e. start with "S-"
+ * or "s-"), we try to parse them as such. If that fails, we
+ * assume they are binary SIDs, even though that's not really
+ * possible -- the first two bytes of a struct dom_sid are the
+ * version (1), and the number of sub-auths (<= 15), neither
+ * of which are close to 'S' or '-'.
+ */
+ if (v1_is_string) {
+ int r = ldif_read_objectSid(ldb, mem_ctx, v1, &parsed_1);
+ if (r == 0) {
+ v1 = &parsed_1;
}
- 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);
+ }
+ if (v2_is_string) {
+ int r = ldif_read_objectSid(ldb, mem_ctx, v2, &parsed_2);
+ if (r == 0) {
+ v2 = &parsed_2;
}
- ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
- talloc_free(v.data);
- return ret;
}
- return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+
+ if (v1_is_string) {
+ TALLOC_FREE(parsed_1.data);
+ }
+ if (v2_is_string) {
+ TALLOC_FREE(parsed_2.data);
+ }
+ return ret;
}
/*
@@ -1148,22 +1159,41 @@ static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
int ret;
+ /*
+ * In a sort context, Deleted DNs get shifted to the end.
+ * They never match in an equality
+ */
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 */
+ if (! dsdb_dn_is_deleted_val(v2)) {
+ return 1;
+ }
+ /*
+ * They are both deleted!
+ *
+ * The soundest thing to do at this point is carry on
+ * and compare the DNs normally. This matches the
+ * behaviour of samba_dn_extended_match() below.
+ */
+ } else if (dsdb_dn_is_deleted_val(v2)) {
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(dn1)) {
+ TALLOC_FREE(dn1);
+ if ( ! ldb_dn_validate(dn2)) {
+ TALLOC_FREE(dn2);
+ return 0;
+ }
+ TALLOC_FREE(dn2);
+ return 1;
+ }
+
if ( ! ldb_dn_validate(dn2)) {
- talloc_free(dn1);
+ TALLOC_FREE(dn1);
+ TALLOC_FREE(dn2);
return -1;
}
diff --git a/lib/ldb/ABI/ldb-2.9.1.sigs b/lib/ldb/ABI/ldb-2.9.1.sigs
new file mode 100644
index 0000000..759659a
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.9.1.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/pyldb-util-2.9.1.sigs b/lib/ldb/ABI/pyldb-util-2.9.1.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.9.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/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c
index 15470cf..3d13e4b 100644
--- a/lib/ldb/common/attrib_handlers.c
+++ b/lib/ldb/common/attrib_handlers.c
@@ -281,15 +281,36 @@ static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
}
/*
- compare two Booleans
-*/
+ * compare two Booleans.
+ *
+ * According to RFC4517 4.2.2, "the booleanMatch rule is an equality matching
+ * rule", meaning it isn't used for ordering.
+ *
+ * However, it seems conceivable that Samba could be coerced into sorting on a
+ * field with Boolean syntax, so we might as well have consistent behaviour in
+ * that case.
+ *
+ * The most probably values are {"FALSE", 5} and {"TRUE", 4}. To save time we
+ * compare first by length, which makes FALSE > TRUE. This is somewhat
+ * contrary to convention, but is how Samba has worked forever.
+ *
+ * If somehow we are comparing incompletely normalised values where the length
+ * is the same (for example {"false", 5} and {"TRUE\0", 5}), the length is the
+ * same, and we fall back to a strncasecmp. In this case, since "FALSE" is
+ * alphabetically lower, we swap the order, so that "TRUE\0" again comes
+ * before "FALSE".
+ *
+ * ldb_canonicalise_Boolean (just above) gives us a clue as to what we might
+ * expect to cope with by way of invalid values.
+ */
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 NUMERIC_CMP(v2->length, v1->length);
}
- return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
+ /* reversed, see long comment above */
+ return strncasecmp((char *)v2->data, (char *)v1->data, v1->length);
}
@@ -300,7 +321,7 @@ 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 NUMERIC_CMP(v1->length, v2->length);
}
return memcmp(v1->data, v2->data, v1->length);
}
@@ -372,17 +393,27 @@ utf8str:
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 */
+ /*
+ * 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 0;
+ }
if (n1 > n2) {
- return (int)ldb_ascii_toupper(s1[n2]);
+ if (s1[n2] == '\0') {
+ return 0;
+ }
+ return 1;
} else {
- return -(int)ldb_ascii_toupper(s2[n1]);
+ if (s2[n1] == '\0') {
+ return 0;
+ }
+ return -1;
}
}
return ret;
@@ -404,7 +435,7 @@ utf8str:
while (*u1 == ' ') u1++;
while (*u2 == ' ') u2++;
}
- ret = (int)(*u1 - *u2);
+ ret = NUMERIC_CMP(*u1, *u2);
talloc_free(b1);
talloc_free(b2);
diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c
index 601da57..8388fdb 100644
--- a/lib/ldb/common/ldb_dn.c
+++ b/lib/ldb/common/ldb_dn.c
@@ -1111,7 +1111,7 @@ int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
/* compare attr.cf_value. */
if (b_vlen != dn_vlen) {
- return b_vlen - dn_vlen;
+ return NUMERIC_CMP(b_vlen, dn_vlen);
}
ret = strncmp(b_vdata, dn_vdata, b_vlen);
if (ret != 0) return ret;
@@ -1132,8 +1132,32 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
{
unsigned int i;
int ret;
+ /*
+ * If used in sort, we shift NULL and invalid DNs to the end.
+ *
+ * If ldb_dn_casefold_internal() fails, that goes to the end too, so
+ * we end up with:
+ *
+ * | normal DNs, sorted | casefold failed DNs | invalid DNs | NULLs |
+ */
- if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) {
+ if (dn0 == dn1) {
+ /* this includes the both-NULL case */
+ return 0;
+ }
+ if (dn0 == NULL) {
+ return 1;
+ }
+ if (dn1 == NULL) {
+ return -1;
+ }
+ if (dn0->invalid && dn1->invalid) {
+ return 0;
+ }
+ if (dn0->invalid) {
+ return 1;
+ }
+ if (dn1->invalid) {
return -1;
}
@@ -1190,7 +1214,7 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
/* compare attr.cf_value. */
if (dn0_vlen != dn1_vlen) {
- return dn0_vlen - dn1_vlen;
+ return NUMERIC_CMP(dn0_vlen, dn1_vlen);
}
ret = strncmp(dn0_vdata, dn1_vdata, dn0_vlen);
if (ret != 0) {
diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
index afddbe4..c334d70 100644
--- a/lib/ldb/common/ldb_msg.c
+++ b/lib/ldb/common/ldb_msg.c
@@ -93,7 +93,7 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
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 NUMERIC_CMP(v1->length, v2->length);
}
return memcmp(v1->data, v2->data, v1->length);
}
@@ -749,9 +749,16 @@ int ldb_msg_element_compare(struct ldb_message_element *el1,
unsigned int i;
if (el1->num_values != el2->num_values) {
- return el1->num_values - el2->num_values;
+ return NUMERIC_CMP(el1->num_values, el2->num_values);
}
-
+ /*
+ * Note this is an inconsistent comparison, unsuitable for
+ * sorting. If A has values {a, b} and B has values {b, c},
+ * then
+ *
+ * ldb_msg_element_compare(A, B) returns -1, meaning A < B
+ * ldb_msg_element_compare(B, A) returns -1, meaning B < A
+ */
for (i=0;i<el1->num_values;i++) {
if (!ldb_msg_find_val(el2, &el1->values[i])) {
return -1;
diff --git a/lib/ldb/common/qsort.c b/lib/ldb/common/qsort.c
index 012aaf3..bae35e6 100644
--- a/lib/ldb/common/qsort.c
+++ b/lib/ldb/common/qsort.c
@@ -227,7 +227,7 @@ void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
- while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ while (tmp_ptr > base_ptr && (*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr -= size;
tmp_ptr += size;
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index 5d83a27..98859d4 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -2326,6 +2326,22 @@ do { \
} while (0)
#endif
+#ifndef NUMERIC_CMP
+/*
+ * NUMERIC_CMP is a safe replacement for `a - b` in comparison
+ * functions. It will work on integers, pointers, and floats.
+ *
+ * Rather than
+ *
+ * return a - b;
+ *
+ * use
+ *
+ * return NUMERIC_CMP(a, b);
+ */
+#define NUMERIC_CMP(a, b) (((a) > (b)) - ((a) < (b)))
+#endif
+
/**
diff --git a/lib/ldb/modules/sort.c b/lib/ldb/modules/sort.c
index cb6f8df..72c60fc 100644
--- a/lib/ldb/modules/sort.c
+++ b/lib/ldb/modules/sort.c
@@ -121,15 +121,28 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo
el1 = ldb_msg_find_element(*msg1, ac->attributeName);
el2 = ldb_msg_find_element(*msg2, ac->attributeName);
- if (!el1 && el2) {
+ /*
+ * NULL and empty elements sort at the end (regardless of ac->reverse flag).
+ * NULL elements come after empty ones.
+ */
+ if (el1 == el2) {
+ return 0;
+ }
+ if (el1 == NULL) {
return 1;
}
- if (el1 && !el2) {
+ if (el2 == NULL) {
return -1;
}
- if (!el1 && !el2) {
+ if (unlikely(el1->num_values == 0 && el2->num_values == 0)) {
return 0;
}
+ if (unlikely(el1->num_values == 0)) {
+ return 1;
+ }
+ if (unlikely(el2->num_values == 0)) {
+ return -1;
+ }
if (ac->reverse)
return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index c249a82..936abe7 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -2,7 +2,7 @@
APPNAME = 'ldb'
# For Samba 4.20.x !
-VERSION = '2.9.0'
+VERSION = '2.9.1'
import sys, os
diff --git a/lib/socket/interfaces.c b/lib/socket/interfaces.c
index 4908b0f..2426ce2 100644
--- a/lib/socket/interfaces.c
+++ b/lib/socket/interfaces.c
@@ -386,18 +386,18 @@ static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
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;
+ uint32_t a1 = ntohl(s1->sin_addr.s_addr);
+ uint32_t a2 = ntohl(s2->sin_addr.s_addr);
+ r = NUMERIC_CMP(a1, a2);
+ if (r == 0) {
+ /* compare netmasks as a tiebreaker */
+ s1 = (struct sockaddr_in *)&i1->netmask;
+ s2 = (struct sockaddr_in *)&i2->netmask;
+ a1 = ntohl(s1->sin_addr.s_addr);
+ a2 = ntohl(s2->sin_addr.s_addr);
+ r = NUMERIC_CMP(a1, a2);
}
-
- 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 r;
}
return 0;
}
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
index 2e86e31..2194703 100644
--- a/lib/torture/torture.h
+++ b/lib/torture/torture.h
@@ -534,6 +534,26 @@ static inline void torture_dump_data_str_cb(const char *buf, void *private_data)
} \
} while(0)
+#define torture_assert_int_less(torture_ctx,got,limit,cmt)\
+ do { int __got = (got), __limit = (limit); \
+ if (__got >= __limit) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected < %d (0x%X): %s", \
+ __got, __got, __limit, __limit, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_int_greater(torture_ctx,got,limit,cmt)\
+ do { int __got = (got), __limit = (limit); \
+ if (__got <= __limit) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected > %d (0x%X): %s", \
+ __got, __got, __limit, __limit, 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) { \
diff --git a/lib/util/charset/codepoints.c b/lib/util/charset/codepoints.c
index ea2c4be..8022627 100644
--- a/lib/util/charset/codepoints.c
+++ b/lib/util/charset/codepoints.c
@@ -26,6 +26,7 @@
#include "dynconfig/dynconfig.h"
#include "lib/util/debug.h"
#include "lib/util/byteorder.h"
+#include "lib/util/tsort.h"
#ifdef strcasecmp
#undef strcasecmp
@@ -16479,11 +16480,23 @@ _PUBLIC_ bool isupper_m(codepoint_t val)
*/
_PUBLIC_ int codepoint_cmpi(codepoint_t c1, codepoint_t c2)
{
+ /*
+ * FIXME: this is unsuitable for use in a sort, as the
+ * comparison is intransitive.
+ *
+ * The problem is toupper_m() is only called on equality case,
+ * which has strange effects.
+ *
+ * Consider {'a', 'A', 'B'}.
+ * 'a' == 'A'
+ * 'a' > 'B' (lowercase letters come after upper)
+ * 'A' < 'B'
+ */
if (c1 == c2 ||
toupper_m(c1) == toupper_m(c2)) {
return 0;
}
- return c1 - c2;
+ return NUMERIC_CMP(c1, c2);
}
diff --git a/lib/util/charset/tests/charset.c b/lib/util/charset/tests/charset.c
index 547dc51..bca5449 100644
--- a/lib/util/charset/tests/charset.c
+++ b/lib/util/charset/tests/charset.c
@@ -72,16 +72,19 @@ static bool test_strcasecmp_m(struct torture_context *tctx)
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_greater(tctx, strcasecmp_m("foo", "bar"), 0, "different strings both lower");
+ torture_assert_int_less(tctx, strcasecmp_m("bar", "foo"), 0, "different strings both lower");
+ torture_assert_int_greater(tctx, strcasecmp_m("foo", "Bar"), 0, "different strings lower/upper");
+ torture_assert_int_greater(tctx, strcasecmp_m("Foo", "bar"), 0, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strcasecmp_m("AFoo", "_bar"), 0, "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_greater(tctx, strcasecmp_m("food", "Foo"), 0, "strings differ towards the end");
+ torture_assert_int_less(tctx, strcasecmp_m("food", "Fool"), 0, "strings differ towards the end");
+ torture_assert_int_less(tctx, strcasecmp_m(NULL, "Foo"), 0, "one NULL");
+ torture_assert_int_greater(tctx, strcasecmp_m("foo", NULL), 0, "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,
+ torture_assert_int_greater(tctx, strcasecmp_m(file_iso8859_1, file_utf8), 0,
"file.{accented e} should differ");
return true;
}
@@ -151,19 +154,19 @@ static bool test_strncasecmp_m(struct torture_context *tctx)
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_greater(tctx, strncasecmp_m("foo", "bar", 3), 0, "different strings both lower");
+ torture_assert_int_greater(tctx, strncasecmp_m("foo", "Bar", 3), 0, "different strings lower/upper");
+ torture_assert_int_greater(tctx, strncasecmp_m("Foo", "bar", 3), 0, "different strings upper/lower");
+ torture_assert_int_greater(tctx, strncasecmp_m("AFoo", "_bar", 4), 0, "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_less(tctx, strncasecmp_m(NULL, "Foo", 3), 0, "one NULL");
+ torture_assert_int_greater(tctx, strncasecmp_m("foo", NULL, 3), 0, "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,
+ torture_assert_int_greater(tctx, strncasecmp_m(file_iso8859_1, file_utf8, 6), 0,
"file.{accented e} should differ");
return true;
}
diff --git a/lib/util/charset/util_str.c b/lib/util/charset/util_str.c
index 1650c9b..c52b773 100644
--- a/lib/util/charset/util_str.c
+++ b/lib/util/charset/util_str.c
@@ -26,6 +26,7 @@
#include "system/locale.h"
#include "charset.h"
#include "lib/util/fault.h"
+#include "lib/util/tsort.h"
#ifdef strcasecmp
#undef strcasecmp
@@ -79,10 +80,10 @@ _PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
- return *s1 - *s2;
+ return NUMERIC_CMP(*s1, *s2);
}
/**
@@ -156,14 +157,14 @@ _PUBLIC_ int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
continue;
}
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
if (n == 0) {
return 0;
}
- return *s1 - *s2;
+ return NUMERIC_CMP(*s1, *s2);
}
/**
diff --git a/lib/util/data_blob.c b/lib/util/data_blob.c
index 69a340c..1558200 100644
--- a/lib/util/data_blob.c
+++ b/lib/util/data_blob.c
@@ -22,6 +22,7 @@
#include "attr.h"
#include "data_blob.h"
#include "lib/util/samba_util.h"
+#include "lib/util/tsort.h"
const DATA_BLOB data_blob_null = { NULL, 0 };
@@ -121,12 +122,12 @@ _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
return 1;
}
if (d1->data == d2->data) {
- return d1->length - d2->length;
+ return NUMERIC_CMP(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 NUMERIC_CMP(d1->length, d2->length);
}
return ret;
}
diff --git a/lib/util/tests/binsearch.c b/lib/util/tests/binsearch.c
index b3ecda1..2484015 100644
--- a/lib/util/tests/binsearch.c
+++ b/lib/util/tests/binsearch.c
@@ -23,17 +23,19 @@
#include "includes.h"
#include "lib/util/binsearch.h"
+#include "lib/util/tsort.h"
#include "torture/torture.h"
#include "torture/local/proto.h"
static int int_cmp(int a, int b)
{
- return a - b;
+ return NUMERIC_CMP(a, b);
}
static int int_cmp_p(int a, int *b)
{
- return a - *b;
+ int _b = *b;
+ return NUMERIC_CMP(a, _b);
}
static bool test_binsearch_v(struct torture_context *tctx)
diff --git a/lib/util/tests/test_ms_fnmatch.c b/lib/util/tests/test_ms_fnmatch.c
index d11c7be..2261f9b 100644
--- a/lib/util/tests/test_ms_fnmatch.c
+++ b/lib/util/tests/test_ms_fnmatch.c
@@ -36,7 +36,7 @@ static void test_ms_fn_match_protocol_no_wildcard(void **state)
/* no wildcards in pattern, a simple strcasecmp_m */
cmp = ms_fnmatch_protocol("pattern", "string", PROTOCOL_COREPLUS,
true); /* case sensitive */
- assert_int_equal(cmp, -3);
+ assert_true(cmp < 0);
}
static void test_ms_fn_match_protocol_pattern_upgraded(void **state)
diff --git a/lib/util/tsort.h b/lib/util/tsort.h
index 811d6cd..18e82d6 100644
--- a/lib/util/tsort.h
+++ b/lib/util/tsort.h
@@ -37,4 +37,23 @@ do { \
} while (0)
#endif
+
+#ifndef NUMERIC_CMP
+/*
+ * NUMERIC_CMP is a safe replacement for `a - b` in comparison
+ * functions. It will work on integers, pointers, and floats.
+ *
+ * Rather than
+ *
+ * return a - b;
+ *
+ * use
+ *
+ * return NUMERIC_CMP(a, b);
+ *
+ * and you won't have any troubles if a - b would overflow.
+ */
+#define NUMERIC_CMP(a, b) (((a) > (b)) - ((a) < (b)))
+#endif
+
#endif
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
index 204484b..6a30c9f 100644
--- a/libcli/nbt/libnbt.h
+++ b/libcli/nbt/libnbt.h
@@ -331,6 +331,9 @@ 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_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob);
NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
struct socket_address *dest,
struct nbt_name_packet *request);
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
index 47e73cf..b2945ad 100644
--- a/libcli/nbt/nbtsocket.c
+++ b/libcli/nbt/nbtsocket.c
@@ -448,6 +448,50 @@ failed:
return NULL;
}
+/*
+ send off a nbt name packet
+*/
+_PUBLIC_ NTSTATUS nbt_name_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob)
+{
+ struct nbt_name_request *req;
+
+ 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;
+ /*
+ * We don't expect a response so
+ * just pretent it is a request,
+ * but we really don't care about the
+ * content.
+ */
+ req->is_reply = true;
+
+ req->encoded = data_blob_dup_talloc(req, pkt_blob);
+ if (req->encoded.length != pkt_blob.length) {
+ goto failed;
+ }
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ 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;
+}
+
/*
send off a nbt name reply
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
index eaece2a..21012b7 100644
--- a/libcli/security/dom_sid.c
+++ b/libcli/security/dom_sid.c
@@ -28,6 +28,7 @@
#include "librpc/gen_ndr/security.h"
#include "dom_sid.h"
#include "lib/util/smb_strtox.h"
+#include "lib/util/tsort.h"
/*****************************************************************
Compare the auth portion of two sids.
@@ -46,11 +47,12 @@ int dom_sid_compare_auth(const struct dom_sid *sid1,
return 1;
if (sid1->sid_rev_num != sid2->sid_rev_num)
- return sid1->sid_rev_num - sid2->sid_rev_num;
+ return NUMERIC_CMP(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];
+ if (sid1->id_auth[i] != sid2->id_auth[i]) {
+ return NUMERIC_CMP(sid1->id_auth[i], sid2->id_auth[i]);
+ }
return 0;
}
@@ -71,9 +73,9 @@ int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *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;
-
+ if (sid1->num_auths != sid2->num_auths) {
+ return NUMERIC_CMP(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;
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index a52a615..87acddf 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -166,6 +166,13 @@ struct smb2cli_session {
uint16_t channel_sequence;
bool replay_active;
bool require_signed_response;
+
+ /*
+ * The following are just for torture tests
+ */
+ bool anonymous_signing;
+ bool anonymous_encryption;
+ bool no_signing_disconnect;
};
struct smbXcli_session {
@@ -3999,6 +4006,9 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||
NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ session != NULL &&
+ session->smb2->no_signing_disconnect) ||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
/*
* if the server returns
@@ -4042,8 +4052,29 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
/*
* If the signing check fails, we disconnect
* the connection.
+ *
+ * Unless
+ * smb2cli_session_torture_no_signing_disconnect
+ * was called in torture tests
*/
- return signing_status;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return signing_status;
+ }
+
+ if (!NT_STATUS_EQUAL(status, signing_status)) {
+ return signing_status;
+ }
+
+ if (session == NULL) {
+ return signing_status;
+ }
+
+ if (!session->smb2->no_signing_disconnect) {
+ return signing_status;
+ }
+
+ state->smb2.signing_skipped = true;
}
}
@@ -6332,6 +6363,23 @@ void smb2cli_session_require_signed_response(struct smbXcli_session *session,
session->smb2->require_signed_response = require_signed_response;
}
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing)
+{
+ session->smb2->anonymous_signing = anonymous_signing;
+}
+
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption)
+{
+ session->smb2->anonymous_encryption = anonymous_encryption;
+}
+
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session)
+{
+ session->smb2->no_signing_disconnect = true;
+}
+
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov)
{
@@ -6432,6 +6480,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
conn->protocol,
preauth_hash);
+ if (session->smb2->anonymous_encryption) {
+ goto skip_signing_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6441,6 +6493,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_signing) {
+ /*
+ * skip encryption and application keys
+ */
+ goto skip_application_key;
+ }
+
+skip_signing_key:
+
status = smb2_signing_key_cipher_create(session->smb2,
conn->smb2.server.cipher,
&_session_key,
@@ -6459,6 +6520,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_encryption) {
+ goto skip_application_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6468,6 +6533,8 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+skip_application_key:
+
status = smb2_signing_key_copy(session,
session->smb2->signing_key,
&session->smb2_channel.signing_key);
@@ -6477,6 +6544,18 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
check_signature = conn->mandatory_signing;
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ check_signature = true;
+ }
+
+ if (session->smb2->anonymous_signing) {
+ check_signature = false;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ check_signature = false;
+ }
+
hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS);
if (hdr_flags & SMB2_HDR_FLAG_SIGNED) {
/*
@@ -6492,10 +6571,6 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
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);
@@ -6527,6 +6602,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
session->smb2->should_encrypt = false;
}
+ if (session->smb2->anonymous_signing) {
+ session->smb2->should_sign = true;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ session->smb2->should_encrypt = true;
+ session->smb2->should_sign = false;
+ }
+
/*
* CCM and GCM algorithms must never have their
* nonce wrap, or the security of the whole
@@ -6698,6 +6782,16 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
{
+ if (session->smb2->anonymous_signing) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ SMB_ASSERT(session->smb2->should_encrypt);
+ SMB_ASSERT(!session->smb2->should_sign);
+ return NT_STATUS_OK;
+ }
+
if (!session->smb2->should_sign) {
/*
* We need required signing on the session
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index 25ccd84..69fa131 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -535,6 +535,11 @@ 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);
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing);
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption);
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session);
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov);
NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
diff --git a/pidl/lib/Parse/Pidl/Typelist.pm b/pidl/lib/Parse/Pidl/Typelist.pm
index 31ea19e..2a98a16 100644
--- a/pidl/lib/Parse/Pidl/Typelist.pm
+++ b/pidl/lib/Parse/Pidl/Typelist.pm
@@ -138,8 +138,18 @@ sub resolveType($)
my ($ctype) = @_;
if (not hasType($ctype)) {
- # assume struct typedef
- return { TYPE => "TYPEDEF", NAME => $ctype, DATA => { TYPE => "STRUCT" } };
+ if (! ref $ctype) {
+ # it looks like a name.
+ # assume struct typedef
+ return { TYPE => "TYPEDEF", NAME => $ctype, DATA => { TYPE => "STRUCT" } };
+ }
+ if ($ctype->{NAME} && ($ctype->{TYPE} eq "STRUCT")) {
+ return {
+ TYPE => "TYPEDEF",
+ NAME => $ctype->{NAME},
+ DATA => $ctype
+ };
+ }
} else {
return getType($ctype);
}
diff --git a/python/samba/gp/gpclass.py b/python/samba/gp/gpclass.py
index 08be472..d86aace 100644
--- a/python/samba/gp/gpclass.py
+++ b/python/samba/gp/gpclass.py
@@ -805,9 +805,7 @@ def site_dn_for_machine(samdb, dc_hostname, lp, creds, hostname):
samlogon_response = ndr_unpack(nbt.netlogon_samlogon_response,
bytes(res.msgs[0]['Netlogon'][0]))
- if samlogon_response.ntver not in [nbt.NETLOGON_NT_VERSION_5EX,
- (nbt.NETLOGON_NT_VERSION_1
- | nbt.NETLOGON_NT_VERSION_5EX)]:
+ if not (samlogon_response.ntver & nbt.NETLOGON_NT_VERSION_5EX):
raise RuntimeError('site_dn_for_machine: Invalid NtVer in '
+ 'netlogon_samlogon_response')
diff --git a/python/samba/tests/blackbox/misc_dfs_widelink.py b/python/samba/tests/blackbox/misc_dfs_widelink.py
new file mode 100644
index 0000000..7948590
--- /dev/null
+++ b/python/samba/tests/blackbox/misc_dfs_widelink.py
@@ -0,0 +1,86 @@
+# Blackbox tests for DFS (widelink)
+#
+# Copyright (C) Noel Power noel.power@suse.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/>.
+#
+from samba.tests import BlackboxTestCase, BlackboxProcessError
+from samba.samba3 import param as s3param
+
+from samba.credentials import Credentials
+
+import os
+
+class DfsWidelinkBlockboxTestBase(BlackboxTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.lp = s3param.get_context()
+ self.server = os.environ["SERVER"]
+ self.user = os.environ["USER"]
+ self.passwd = os.environ["PASSWORD"]
+ self.creds = Credentials()
+ self.creds.guess(self.lp)
+ self.creds.set_username(self.user)
+ self.creds.set_password(self.passwd)
+ self.testdir = os.getenv("TESTDIR", "msdfs-share-wl")
+ self.share = os.getenv("SHARE", "msdfs-share-wl")
+ self.dirpath = os.path.join(os.environ["LOCAL_PATH"],self.testdir)
+ # allow a custom teardown function to be defined
+ self.cleanup = None
+ self.cleanup_args = []
+
+ def tearDown(self):
+ try:
+ if (self.cleanup):
+ self.cleanup(self.cleanup_args)
+ except Exception as e:
+ print("remote remove failed: %s" % str(e))
+
+ def build_test_cmd(self, cmd, args):
+ cmd = [cmd, "-U%s%%%s" % (self.user, self.passwd)]
+ cmd.extend(args)
+ return cmd
+
+ def test_ci_chdir(self):
+ parent_dir = "msdfs-src1"
+ dirs = [parent_dir, parent_dir.upper()]
+ # try as named dir first then try upper-cased version
+ for adir in dirs:
+ smbclient_args = self.build_test_cmd("smbclient", ["//%s/%s" % (self.server, self.share), "-c", "cd %s" % (adir)])
+ try:
+ out_str = self.check_output(smbclient_args)
+ except BlackboxProcessError as e:
+ print(str(e))
+ self.fail(str(e))
+
+ def test_nested_chdir(self):
+ parent_dir = "dfshop1"
+ child_dir = "dfshop2"
+ smbclient_args = self.build_test_cmd("smbclient", ["//%s/%s" % (self.server, self.share), "-c", "cd %s/%s" % (parent_dir,child_dir)])
+ try:
+ out_str = self.check_output(smbclient_args)
+ except BlackboxProcessError as e:
+ print(str(e))
+ self.fail(str(e))
+
+ def test_enumerate_dfs_link(self):
+ smbclient_args = self.build_test_cmd("smbclient", ["//%s/%s" % (self.server, self.share), "-c", "dir"])
+ try:
+ out_str = self.check_output(smbclient_args)
+ except BlackboxProcessError as e:
+ print(str(e))
+ self.fail(str(e))
+ out_str = out_str.decode()
+ self.assertIn("msdfs-src1", out_str)
diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py
index d320a0e..43a62b1 100644
--- a/python/samba/tests/dns_base.py
+++ b/python/samba/tests/dns_base.py
@@ -20,6 +20,7 @@ from samba.tests import TestCaseInTempDir
from samba.dcerpc import dns, dnsp
from samba import gensec, tests
from samba import credentials
+from samba import NTSTATUSError
import struct
import samba.ndr as ndr
import random
@@ -76,6 +77,24 @@ class DNSTest(TestCaseInTempDir):
self.assertEqual(p_opcode, opcode, "Expected OPCODE %s, got %s" %
(opcode, p_opcode))
+ def assert_dns_flags_equals(self, packet, flags):
+ "Helper function to check opcode"
+ p_flags = packet.operation & (~(dns.DNS_OPCODE|dns.DNS_RCODE))
+ self.assertEqual(p_flags, flags, "Expected FLAGS %02x, got %02x" %
+ (flags, p_flags))
+
+ def assert_echoed_dns_error(self, request, response, response_p, rcode):
+
+ request_p = ndr.ndr_pack(request)
+
+ self.assertEqual(response.id, request.id)
+ self.assert_dns_rcode_equals(response, rcode)
+ self.assert_dns_opcode_equals(response, request.operation & dns.DNS_OPCODE)
+ self.assert_dns_flags_equals(response,
+ (request.operation | dns.DNS_FLAG_REPLY) & (~(dns.DNS_OPCODE|dns.DNS_RCODE)))
+ self.assertEqual(len(response_p), len(request_p))
+ self.assertEqual(response_p[4:], request_p[4:])
+
def make_name_packet(self, opcode, qid=None):
"Helper creating a dns.name_packet"
p = dns.name_packet()
@@ -112,6 +131,8 @@ class DNSTest(TestCaseInTempDir):
return self.creds.get_realm().lower()
def dns_transaction_udp(self, packet, host,
+ allow_remaining=False,
+ allow_truncated=False,
dump=False, timeout=None):
"send a DNS query and read the reply"
s = None
@@ -128,8 +149,22 @@ class DNSTest(TestCaseInTempDir):
recv_packet = s.recv(2048, 0)
if dump:
print(self.hexdump(recv_packet))
- response = ndr.ndr_unpack(dns.name_packet, recv_packet)
+ if allow_truncated:
+ # with allow_remaining
+ # we add some zero bytes
+ # in order to also parse truncated
+ # responses
+ recv_packet_p = recv_packet + 32*b"\x00"
+ allow_remaining = True
+ else:
+ recv_packet_p = recv_packet
+ response = ndr.ndr_unpack(dns.name_packet, recv_packet_p,
+ allow_remaining=allow_remaining)
return (response, recv_packet)
+ except RuntimeError as re:
+ if s is not None:
+ s.close()
+ raise AssertionError(re)
finally:
if s is not None:
s.close()
@@ -151,11 +186,26 @@ class DNSTest(TestCaseInTempDir):
tcp_packet += send_packet
s.sendall(tcp_packet)
- recv_packet = s.recv(0xffff + 2, 0)
+ recv_packet = b''
+ length = None
+ for i in range(0, 2 + 0xffff):
+ if len(recv_packet) >= 2:
+ length, = struct.unpack('!H', recv_packet[0:2])
+ remaining = 2 + length
+ else:
+ remaining = 2 + 12
+ remaining -= len(recv_packet)
+ if remaining == 0:
+ break
+ recv_packet += s.recv(remaining, 0)
if dump:
print(self.hexdump(recv_packet))
response = ndr.ndr_unpack(dns.name_packet, recv_packet[2:])
+ except RuntimeError as re:
+ if s is not None:
+ s.close()
+ raise AssertionError(re)
finally:
if s is not None:
s.close()
@@ -217,18 +267,41 @@ class DNSTKeyTest(DNSTest):
self.creds.set_username(tests.env_get_var_value('USERNAME'))
self.creds.set_password(tests.env_get_var_value('PASSWORD'))
self.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
+
+ self.unpriv_creds = None
+
self.newrecname = "tkeytsig.%s" % self.get_dns_domain()
- def tkey_trans(self, creds=None):
+ def get_unpriv_creds(self):
+ if self.unpriv_creds is not None:
+ return self.unpriv_creds
+
+ self.unpriv_creds = credentials.Credentials()
+ self.unpriv_creds.guess(self.lp_ctx)
+ self.unpriv_creds.set_username(tests.env_get_var_value('USERNAME_UNPRIV'))
+ self.unpriv_creds.set_password(tests.env_get_var_value('PASSWORD_UNPRIV'))
+ self.unpriv_creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
+
+ return self.unpriv_creds
+
+ def tkey_trans(self, creds=None, algorithm_name="gss-tsig",
+ tkey_req_in_answers=False,
+ expected_rcode=dns.DNS_RCODE_OK):
"Do a TKEY transaction and establish a gensec context"
if creds is None:
creds = self.creds
- self.key_name = "%s.%s" % (uuid.uuid4(), self.get_dns_domain())
+ mech = 'spnego'
+
+ tkey = {}
+ tkey['name'] = "%s.%s" % (uuid.uuid4(), self.get_dns_domain())
+ tkey['creds'] = creds
+ tkey['mech'] = mech
+ tkey['algorithm'] = algorithm_name
p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
- q = self.make_name_question(self.key_name,
+ q = self.make_name_question(tkey['name'],
dns.DNS_QTYPE_TKEY,
dns.DNS_QCLASS_IN)
questions = []
@@ -236,30 +309,30 @@ class DNSTKeyTest(DNSTest):
self.finish_name_packet(p, questions)
r = dns.res_rec()
- r.name = self.key_name
+ r.name = tkey['name']
r.rr_type = dns.DNS_QTYPE_TKEY
r.rr_class = dns.DNS_QCLASS_IN
r.ttl = 0
r.length = 0xffff
rdata = dns.tkey_record()
- rdata.algorithm = "gss-tsig"
+ rdata.algorithm = algorithm_name
rdata.inception = int(time.time())
rdata.expiration = int(time.time()) + 60 * 60
rdata.mode = dns.DNS_TKEY_MODE_GSSAPI
rdata.error = 0
rdata.other_size = 0
- self.g = gensec.Security.start_client(self.settings)
- self.g.set_credentials(creds)
- self.g.set_target_service("dns")
- self.g.set_target_hostname(self.server)
- self.g.want_feature(gensec.FEATURE_SIGN)
- self.g.start_mech_by_name("spnego")
+ tkey['gensec'] = gensec.Security.start_client(self.settings)
+ tkey['gensec'].set_credentials(creds)
+ tkey['gensec'].set_target_service("dns")
+ tkey['gensec'].set_target_hostname(self.server)
+ tkey['gensec'].want_feature(gensec.FEATURE_SIGN)
+ tkey['gensec'].start_mech_by_name(tkey['mech'])
finished = False
client_to_server = b""
- (finished, server_to_client) = self.g.update(client_to_server)
+ (finished, server_to_client) = tkey['gensec'].update(client_to_server)
self.assertFalse(finished)
data = [x if isinstance(x, int) else ord(x) for x in list(server_to_client)]
@@ -268,56 +341,76 @@ class DNSTKeyTest(DNSTest):
r.rdata = rdata
additional = [r]
- p.arcount = 1
- p.additional = additional
+ if tkey_req_in_answers:
+ p.ancount = 1
+ p.answers = additional
+ else:
+ p.arcount = 1
+ p.additional = additional
(response, response_packet) =\
self.dns_transaction_tcp(p, self.server_ip)
+ if expected_rcode != dns.DNS_RCODE_OK:
+ self.assert_echoed_dns_error(p, response, response_packet, expected_rcode)
+ return
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
tkey_record = response.answers[0].rdata
server_to_client = bytes(tkey_record.key_data)
- (finished, client_to_server) = self.g.update(server_to_client)
+ (finished, client_to_server) = tkey['gensec'].update(server_to_client)
self.assertTrue(finished)
+ self.tkey = tkey
+
self.verify_packet(response, response_packet)
def verify_packet(self, response, response_packet, request_mac=b""):
+ self.assertEqual(response.arcount, 1)
self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG)
+ if self.tkey['algorithm'] == "gss-tsig":
+ gss_tsig = True
+ else:
+ gss_tsig = False
+
+ request_mac_len = b""
+ if len(request_mac) > 0 and gss_tsig:
+ request_mac_len = struct.pack('!H', len(request_mac))
+
tsig_record = response.additional[0].rdata
mac = bytes(tsig_record.mac)
+ self.assertEqual(tsig_record.original_id, response.id)
+ self.assertEqual(tsig_record.mac_size, len(mac))
+
# Cut off tsig record from dns response packet for MAC verification
# and reset additional record count.
- key_name_len = len(self.key_name) + 2
- tsig_record_len = len(ndr.ndr_pack(tsig_record)) + key_name_len + 10
-
- # convert str/bytes to a list (of string char or int)
- # so it can be modified
- response_packet_list = [x if isinstance(x, int) else ord(x) for x in response_packet]
- del response_packet_list[-tsig_record_len:]
- response_packet_list[11] = 0
-
- # convert modified list (of string char or int) to str/bytes
- response_packet_wo_tsig = bytes(response_packet_list)
+ response_copy = ndr.ndr_deepcopy(response)
+ response_copy.arcount = 0
+ response_packet_wo_tsig = ndr.ndr_pack(response_copy)
fake_tsig = dns.fake_tsig_rec()
- fake_tsig.name = self.key_name
+ fake_tsig.name = self.tkey['name']
fake_tsig.rr_class = dns.DNS_QCLASS_ANY
fake_tsig.ttl = 0
fake_tsig.time_prefix = tsig_record.time_prefix
fake_tsig.time = tsig_record.time
fake_tsig.algorithm_name = tsig_record.algorithm_name
fake_tsig.fudge = tsig_record.fudge
- fake_tsig.error = 0
- fake_tsig.other_size = 0
+ fake_tsig.error = tsig_record.error
+ fake_tsig.other_size = tsig_record.other_size
+ fake_tsig.other_data = tsig_record.other_data
fake_tsig_packet = ndr.ndr_pack(fake_tsig)
- data = request_mac + response_packet_wo_tsig + fake_tsig_packet
- self.g.check_packet(data, data, mac)
+ data = request_mac_len + request_mac + response_packet_wo_tsig + fake_tsig_packet
+ try:
+ self.tkey['gensec'].check_packet(data, data, mac)
+ except NTSTATUSError as nt:
+ raise AssertionError(nt)
- def sign_packet(self, packet, key_name):
+ def sign_packet(self, packet, key_name,
+ algorithm_name="gss-tsig",
+ bad_sig=False):
"Sign a packet, calculate a MAC and add TSIG record"
packet_data = ndr.ndr_pack(packet)
@@ -327,18 +420,35 @@ class DNSTKeyTest(DNSTest):
fake_tsig.ttl = 0
fake_tsig.time_prefix = 0
fake_tsig.time = int(time.time())
- fake_tsig.algorithm_name = "gss-tsig"
+ fake_tsig.algorithm_name = algorithm_name
fake_tsig.fudge = 300
fake_tsig.error = 0
fake_tsig.other_size = 0
fake_tsig_packet = ndr.ndr_pack(fake_tsig)
data = packet_data + fake_tsig_packet
- mac = self.g.sign_packet(data, data)
+ mac = self.tkey['gensec'].sign_packet(data, data)
mac_list = [x if isinstance(x, int) else ord(x) for x in list(mac)]
+ if bad_sig:
+ if len(mac) > 8:
+ mac_list[-8] = mac_list[-8] ^ 0xff
+ if len(mac) > 7:
+ mac_list[-7] = ord('b')
+ if len(mac) > 6:
+ mac_list[-6] = ord('a')
+ if len(mac) > 5:
+ mac_list[-5] = ord('d')
+ if len(mac) > 4:
+ mac_list[-4] = ord('m')
+ if len(mac) > 3:
+ mac_list[-3] = ord('a')
+ if len(mac) > 2:
+ mac_list[-2] = ord('c')
+ if len(mac) > 1:
+ mac_list[-1] = mac_list[-1] ^ 0xff
rdata = dns.tsig_record()
- rdata.algorithm_name = "gss-tsig"
+ rdata.algorithm_name = algorithm_name
rdata.time_prefix = 0
rdata.time = fake_tsig.time
rdata.fudge = 300
@@ -363,33 +473,10 @@ class DNSTKeyTest(DNSTest):
return mac
def bad_sign_packet(self, packet, key_name):
- """Add bad signature for a packet by bitflipping
- the final byte in the MAC"""
-
- mac_list = [x if isinstance(x, int) else ord(x) for x in list("badmac")]
-
- rdata = dns.tsig_record()
- rdata.algorithm_name = "gss-tsig"
- rdata.time_prefix = 0
- rdata.time = int(time.time())
- rdata.fudge = 300
- rdata.original_id = packet.id
- rdata.error = 0
- rdata.other_size = 0
- rdata.mac = mac_list
- rdata.mac_size = len(mac_list)
+ """Add bad signature for a packet by
+ bitflipping and hardcoding bytes at the end of the MAC"""
- r = dns.res_rec()
- r.name = key_name
- r.rr_type = dns.DNS_QTYPE_TSIG
- r.rr_class = dns.DNS_QCLASS_ANY
- r.ttl = 0
- r.length = 0xffff
- r.rdata = rdata
-
- additional = [r]
- packet.additional = additional
- packet.arcount = 1
+ return self.sign_packet(packet, key_name, bad_sig=True)
def search_record(self, name):
p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
diff --git a/python/samba/tests/dns_tkey.py b/python/samba/tests/dns_tkey.py
index 69af14d..f8417ea 100644
--- a/python/samba/tests/dns_tkey.py
+++ b/python/samba/tests/dns_tkey.py
@@ -19,6 +19,7 @@
import sys
import optparse
import samba.getopt as options
+import samba.ndr as ndr
from samba.dcerpc import dns
from samba.tests.subunitrun import SubunitOptions, TestProgram
from samba.tests.dns_base import DNSTKeyTest
@@ -55,17 +56,34 @@ class TestDNSUpdates(DNSTKeyTest):
self.server_ip = server_ip
super().setUp()
- def test_tkey(self):
- "test DNS TKEY handshake"
+ def test_tkey_gss_tsig(self):
+ "test DNS TKEY handshake with gss-tsig"
self.tkey_trans()
+ def test_tkey_gss_microsoft_com(self):
+ "test DNS TKEY handshake with gss.microsoft.com"
+
+ self.tkey_trans(algorithm_name="gss.microsoft.com")
+
+ def test_tkey_invalid_gss_TSIG(self):
+ "test DNS TKEY handshake with invalid gss-TSIG"
+
+ self.tkey_trans(algorithm_name="gss-TSIG",
+ expected_rcode=dns.DNS_RCODE_REFUSED)
+
+ def test_tkey_invalid_gss_MICROSOFT_com(self):
+ "test DNS TKEY handshake with invalid gss.MICROSOFT.com"
+
+ self.tkey_trans(algorithm_name="gss.MICROSOFT.com",
+ expected_rcode=dns.DNS_RCODE_REFUSED)
+
def test_update_wo_tsig(self):
"test DNS update without TSIG record"
p = self.make_update_request()
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
- self.assert_dns_rcode_equals(response, dns.DNS_RCODE_REFUSED)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
rcode = self.search_record(self.newrecname)
self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
@@ -78,10 +96,7 @@ class TestDNSUpdates(DNSTKeyTest):
p = self.make_update_request()
self.sign_packet(p, "badkey")
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
- self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTAUTH)
- tsig_record = response.additional[0].rdata
- self.assertEqual(tsig_record.error, dns.DNS_RCODE_BADKEY)
- self.assertEqual(tsig_record.mac_size, 0)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
rcode = self.search_record(self.newrecname)
self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
@@ -92,23 +107,149 @@ class TestDNSUpdates(DNSTKeyTest):
self.tkey_trans()
p = self.make_update_request()
- self.bad_sign_packet(p, self.key_name)
+ self.bad_sign_packet(p, self.tkey['name'])
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
- self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTAUTH)
- tsig_record = response.additional[0].rdata
- self.assertEqual(tsig_record.error, dns.DNS_RCODE_BADSIG)
- self.assertEqual(tsig_record.mac_size, 0)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
rcode = self.search_record(self.newrecname)
self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
- def test_update_tsig(self):
- "test DNS update with correct TSIG record"
+ def test_update_tsig_bad_algorithm(self):
+ "test DNS update with a TSIG record with a bad algorithm"
self.tkey_trans()
+ algorithm_name = "gss-TSIG"
p = self.make_update_request()
- mac = self.sign_packet(p, self.key_name)
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
+
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_tsig_changed_algorithm1(self):
+ "test DNS update with a TSIG record with a changed algorithm"
+
+ algorithm_name = "gss-tsig"
+ self.tkey_trans(algorithm_name=algorithm_name)
+
+ # Now delete the record, it's most likely
+ # a no-op as it should not be there if the test
+ # runs the first time
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Now do an update with the algorithm_name
+ # changed in the requests TSIG message.
+ p = self.make_update_request()
+ algorithm_name = "gss.microsoft.com"
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ algorithm_name = "gss-tsig"
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip,
+ allow_remaining=True)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record, with the original
+ # algorithm_name used in the tkey exchange
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_tsig_changed_algorithm2(self):
+ "test DNS update with a TSIG record with a changed algorithm"
+
+ algorithm_name = "gss.microsoft.com"
+ self.tkey_trans(algorithm_name=algorithm_name)
+
+ # Now delete the record, it's most likely
+ # a no-op as it should not be there if the test
+ # runs the first time
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Now do an update with the algorithm_name
+ # changed in the requests TSIG message.
+ p = self.make_update_request()
+ algorithm_name = "gss-tsig"
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ algorithm_name = "gss.microsoft.com"
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip,
+ allow_truncated=True)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ response_p_pack = ndr.ndr_pack(response)
+ if len(response_p_pack) == len(response_p):
+ self.verify_packet(response, response_p, mac)
+ else:
+ pass # Windows bug
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record, with the original
+ # algorithm_name used in the tkey exchange
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'], algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_gss_tsig_tkey_req_additional(self):
+ "test DNS update with correct gss-tsig record tkey req in additional"
+
+ self.tkey_trans()
+
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # check it's gone
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_gss_tsig_tkey_req_answers(self):
+ "test DNS update with correct gss-tsig record tsig req in answers"
+
+ self.tkey_trans(tkey_req_in_answers=True)
+
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'])
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.verify_packet(response, response_p, mac)
@@ -119,7 +260,66 @@ class TestDNSUpdates(DNSTKeyTest):
# Now delete the record
p = self.make_update_request(delete=True)
- mac = self.sign_packet(p, self.key_name)
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # check it's gone
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_gss_microsoft_com_tkey_req_additional(self):
+ "test DNS update with correct gss.microsoft.com record tsig req in additional"
+
+ algorithm_name = "gss.microsoft.com"
+ self.tkey_trans(algorithm_name=algorithm_name)
+
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # check it's gone
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_gss_microsoft_com_tkey_req_answers(self):
+ "test DNS update with correct gss.microsoft.com record tsig req in answers"
+
+ algorithm_name = "gss.microsoft.com"
+ self.tkey_trans(algorithm_name=algorithm_name,
+ tkey_req_in_answers=True)
+
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'],
+ algorithm_name=algorithm_name)
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.verify_packet(response, response_p, mac)
@@ -131,35 +331,28 @@ class TestDNSUpdates(DNSTKeyTest):
def test_update_tsig_windows(self):
"test DNS update with correct TSIG record (follow Windows pattern)"
- newrecname = "win" + self.newrecname
+ p = self.make_update_request()
+
rr_class = dns.DNS_QCLASS_IN
ttl = 1200
- p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
- q = self.make_name_question(self.get_dns_domain(),
- dns.DNS_QTYPE_SOA,
- dns.DNS_QCLASS_IN)
- questions = []
- questions.append(q)
- self.finish_name_packet(p, questions)
-
updates = []
r = dns.res_rec()
- r.name = newrecname
+ r.name = self.newrecname
r.rr_type = dns.DNS_QTYPE_A
r.rr_class = dns.DNS_QCLASS_ANY
r.ttl = 0
r.length = 0
updates.append(r)
r = dns.res_rec()
- r.name = newrecname
+ r.name = self.newrecname
r.rr_type = dns.DNS_QTYPE_AAAA
r.rr_class = dns.DNS_QCLASS_ANY
r.ttl = 0
r.length = 0
updates.append(r)
r = dns.res_rec()
- r.name = newrecname
+ r.name = self.newrecname
r.rr_type = dns.DNS_QTYPE_A
r.rr_class = rr_class
r.ttl = ttl
@@ -171,7 +364,7 @@ class TestDNSUpdates(DNSTKeyTest):
prereqs = []
r = dns.res_rec()
- r.name = newrecname
+ r.name = self.newrecname
r.rr_type = dns.DNS_QTYPE_CNAME
r.rr_class = dns.DNS_QCLASS_NONE
r.ttl = 0
@@ -181,21 +374,87 @@ class TestDNSUpdates(DNSTKeyTest):
p.answers = prereqs
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
- self.assert_dns_rcode_equals(response, dns.DNS_RCODE_REFUSED)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
self.tkey_trans()
- mac = self.sign_packet(p, self.key_name)
+ mac = self.sign_packet(p, self.tkey['name'])
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.verify_packet(response, response_p, mac)
# Check the record is around
- rcode = self.search_record(newrecname)
+ rcode = self.search_record(self.newrecname)
self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
# Now delete the record
+ delete_updates = []
+ r = dns.res_rec()
+ r.name = self.newrecname
+ r.rr_type = dns.DNS_QTYPE_A
+ r.rr_class = dns.DNS_QCLASS_NONE
+ r.ttl = 0
+ r.length = 0xffff
+ r.rdata = "10.1.45.64"
+ delete_updates.append(r)
+ p = self.make_update_request(delete=True)
+ p.nscount = len(delete_updates)
+ p.nsrecs = delete_updates
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # check it's gone
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_NXDOMAIN)
+
+ def test_update_tsig_record_access_denied(self):
+ """test DNS update with a TSIG record where the user does not have
+ permissions to change the record"""
+
+ self.tkey_trans()
+ adm_tkey = self.tkey
+
+ # First create the record as admin
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now update the same values as normal user
+ # should work without error
+ self.tkey_trans(creds=self.get_unpriv_creds())
+ unpriv_tkey = self.tkey
+
+ p = self.make_update_request()
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
+ self.verify_packet(response, response_p, mac)
+
+ # Check the record is still around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now try to delete the record a normal user (should fail)
+ p = self.make_update_request(delete=True)
+ mac = self.sign_packet(p, self.tkey['name'])
+ (response, response_p) = self.dns_transaction_udp(p, self.server_ip)
+ self.assert_echoed_dns_error(p, response, response_p, dns.DNS_RCODE_REFUSED)
+
+ # Check the record is still around
+ rcode = self.search_record(self.newrecname)
+ self.assert_rcode_equals(rcode, dns.DNS_RCODE_OK)
+
+ # Now delete the record as admin
+ self.tkey = adm_tkey
p = self.make_update_request(delete=True)
- mac = self.sign_packet(p, self.key_name)
+ mac = self.sign_packet(p, self.tkey['name'])
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.verify_packet(response, response_p, mac)
diff --git a/python/samba/tests/join.py b/python/samba/tests/join.py
index b47bc70..b04cb4a 100644
--- a/python/samba/tests/join.py
+++ b/python/samba/tests/join.py
@@ -156,7 +156,7 @@ class JoinTestCase(DNSTKeyTest):
p.nscount = len(updates)
p.nsrecs = updates
- mac = self.sign_packet(p, self.key_name)
+ mac = self.sign_packet(p, self.tkey['name'])
(response, response_p) = self.dns_transaction_udp(p, self.server_ip)
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
self.verify_packet(response, response_p, mac)
diff --git a/python/samba/tests/ntacls.py b/python/samba/tests/ntacls.py
index 0b7963d..6e2adda 100644
--- a/python/samba/tests/ntacls.py
+++ b/python/samba/tests/ntacls.py
@@ -83,5 +83,5 @@ class NtaclsTests(TestCaseInTempDir):
lp = LoadParm()
open(self.tempf, 'w').write("empty")
lp.set("posix:eadb", os.path.join(self.tempdir, "eadbtest.tdb"))
- self.assertRaises(Exception, setntacl, lp, self.tempf, NTACL_SDDL,
+ self.assertRaises(PermissionError, setntacl, lp, self.tempf, NTACL_SDDL,
DOMAIN_SID, self.session_info, "native")
diff --git a/script/autobuild.py b/script/autobuild.py
index ecec352..7291522 100755
--- a/script/autobuild.py
+++ b/script/autobuild.py
@@ -892,9 +892,10 @@ tasks = {
("ldb-make", "cd lib/ldb && make"),
("ldb-install", "cd lib/ldb && make install"),
- ("nondevel-configure", samba_libs_envvars + " ./configure ${PREFIX}"),
+ ("nondevel-configure", samba_libs_envvars + " ./configure --vendor-name=autobuild-TEST-STRING --vendor-patch-revision=5 ${PREFIX}"),
("nondevel-make", "make -j"),
("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
+ ("nondevel-check", "./bin/smbd --version | grep -e '-autobuild-TEST-STRING-5' && exit 0; exit 1"),
("nondevel-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
("nondevel-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
("nondevel-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
diff --git a/selftest/flapping.d/gitlab-setxattr-security b/selftest/flapping.d/gitlab-setxattr-security
new file mode 100644
index 0000000..d7d2403
--- /dev/null
+++ b/selftest/flapping.d/gitlab-setxattr-security
@@ -0,0 +1,18 @@
+# gitlab runners with kernel 5.15.109+
+# allow setxattr() on security.NTACL
+#
+# It's not clear in detail why there's a difference
+# between various systems, one reason could be that
+# with selinux inode_owner_or_capable() is used to check
+# setxattr() permissions:
+# it checks for the fileowner too, as well as CAP_FOWNER.
+# Otherwise cap_inode_setxattr() is used, which checks for
+# CAP_SYS_ADMIN.
+#
+# But the kernel doesn't have selinux only apparmor...
+#
+# test_setntacl_forcenative expects
+# PermissionError: [Errno 1] Operation not permitted
+#
+# So for now we allow this to fail...
+^samba.tests.ntacls.samba.tests.ntacls.NtaclsTests.test_setntacl_forcenative.none
diff --git a/selftest/knownfail-32bit b/selftest/knownfail-32bit
index 2946f3e..8ab625d 100644
--- a/selftest/knownfail-32bit
+++ b/selftest/knownfail-32bit
@@ -65,14 +65,8 @@
# [171(1386)/261 at 6m24s, 4 errors] samba4.local.charset
# UNEXPECTED(failure): samba4.local.charset.strcasecmp(none)
# REASON: Exception: Exception: ../../lib/util/charset/tests/charset.c:56: strcasecmp("foo", "bar") was 1 (0x1), expected 4 (0x4): different strings both lower
-# UNEXPECTED(failure): samba4.local.charset.strcasecmp_m(none)
-# REASON: Exception: Exception: ../../lib/util/charset/tests/charset.c:85: strcasecmp_m(file_iso8859_1, file_utf8) was 1 (0x1), expected 38 (0x26): file.{accented e}
-# should differ
# UNEXPECTED(failure): samba4.local.charset.strncasecmp(none)
# REASON: Exception: Exception: ../../lib/util/charset/tests/charset.c:132: strncasecmp("foo", "bar", 3) was 1 (0x1), expected 4 (0x4): different strings both lower
-# UNEXPECTED(failure): samba4.local.charset.strncasecmp_m(none)
-# REASON: Exception: Exception: ../../lib/util/charset/tests/charset.c:167: strncasecmp_m(file_iso8859_1, file_utf8, 6) was 1 (0x1), expected 38 (0x26): file.{accent
-# ed e} should differ
# command: /home/samba/samba.git/bin/smbtorture $LOADLIST --configfile=$SMB_CONF_PATH --option='fss:sequence timeout=1' --maximum-runtime=$SELFTEST_MAXTIME --based
# ir=$SELFTEST_TMPDIR --format=subunit --option=torture:progress=no --target=samba4 ncalrpc:localhost local.charset 2>&1 | python3 /home/samba/samba.git/selftest/fi
# lter-subunit --fail-on-empty --prefix="samba4.local.charset." --suffix="(none)"
@@ -82,9 +76,7 @@
# ERROR: Testsuite[samba4.local.charset]
# REASON: Exit code was 1
^samba4.local.charset.strcasecmp.none
-^samba4.local.charset.strcasecmp_m.none
^samba4.local.charset.strncasecmp.none
-^samba4.local.charset.strncasecmp_m.none
#
# [229(2702)/261 at 8m44s, 5 errors] samba.tests.samba_tool.provision_lmdb_size
# UNEXPECTED(failure): samba.tests.samba_tool.provision_lmdb_size.samba.tests.samba_tool.provision_lmdb_size.ProvisionLmdbSizeTestCase.test_134217728b(none)
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 2d449e4..f2b84b4 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -618,6 +618,7 @@ sub provision_raw_prepare($$$$$$$$$$$$$$)
$ctx->{statedir} = "$prefix_abs/statedir";
$ctx->{cachedir} = "$prefix_abs/cachedir";
$ctx->{winbindd_socket_dir} = "$prefix_abs/wbsock";
+ $ctx->{nmbd_socket_dir} = "$prefix_abs/nmbsock";
$ctx->{ntp_signd_socket_dir} = "$prefix_abs/ntp_signd_socket";
$ctx->{nsswrap_passwd} = "$ctx->{etcdir}/passwd";
$ctx->{nsswrap_group} = "$ctx->{etcdir}/group";
@@ -774,6 +775,7 @@ sub provision_raw_step1($$)
state directory = $ctx->{statedir}
cache directory = $ctx->{cachedir}
winbindd socket directory = $ctx->{winbindd_socket_dir}
+ nmbd:socket dir = $ctx->{nmbd_socket_dir}
ntp signd socket directory = $ctx->{ntp_signd_socket_dir}
winbind separator = /
interfaces = $interfaces
diff --git a/source3/include/fstring.h b/source3/include/fstring.h
new file mode 100644
index 0000000..dfc8f17
--- /dev/null
+++ b/source3/include/fstring.h
@@ -0,0 +1,27 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) 2002 by Martin Pool <mbp@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_FSTRING_H
+#define _SAMBA_FSTRING_H
+
+#ifndef FSTRING_LEN
+#define FSTRING_LEN 256
+typedef char fstring[FSTRING_LEN];
+#endif
+
+#endif /* _SAMBA_FSTRING_H */
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 1e7b79b..ee05b93 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -237,10 +237,7 @@ enum timestamp_set_resolution {
_________)/\\_//(\/(/\)/\//\/\///|_)_______
*/
-#ifndef FSTRING_LEN
-#define FSTRING_LEN 256
-typedef char fstring[FSTRING_LEN];
-#endif
+#include "fstring.h"
/* debug.h need to be included before samba_util.h for the macro SMB_ASSERT */
#include "../lib/util/debug.h"
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h
index 8fbe5a3..51efe82 100644
--- a/source3/include/nameserv.h
+++ b/source3/include/nameserv.h
@@ -20,18 +20,6 @@
*/
-#define INFO_VERSION "INFO/version"
-#define INFO_COUNT "INFO/num_entries"
-#define INFO_ID_HIGH "INFO/id_high"
-#define INFO_ID_LOW "INFO/id_low"
-#define ENTRY_PREFIX "ENTRY/"
-
-#define PERMANENT_TTL 0
-
-/* NTAS uses 2, NT uses 1, WfWg uses 0 */
-#define MAINTAIN_LIST 2
-#define ELECTION_VERSION 1
-
#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
@@ -140,12 +128,6 @@ enum netbios_reply_type_code { NMB_QUERY, NMB_STATUS, NMB_REG, NMB_REG_REFRESH,
#define NAME_POLL_REFRESH_TIME (5*60)
#define NAME_POLL_INTERVAL 15
-/* Workgroup state identifiers. */
-#define AM_POTENTIAL_MASTER_BROWSER(work) ((work)->mst_state == MST_POTENTIAL)
-#define AM_LOCAL_MASTER_BROWSER(work) ((work)->mst_state == MST_BROWSER)
-#define AM_DOMAIN_MASTER_BROWSER(work) ((work)->dom_state == DOMAIN_MST)
-#define AM_DOMAIN_MEMBER(work) ((work)->log_state == LOGON_SRV)
-
/* Microsoft browser NetBIOS name. */
#define MSBROWSE "\001\002__MSBROWSE__\002"
@@ -159,293 +141,33 @@ enum netbios_reply_type_code { NMB_QUERY, NMB_STATUS, NMB_REG, NMB_REG_REFRESH,
#define FIND_ANY_NAME 0
#define FIND_SELF_NAME 1
-/*
- * The different name types that can be in namelists.
- *
- * SELF_NAME should only be on the broadcast and unicast subnets.
- * LMHOSTS_NAME should only be in the remote_broadcast_subnet.
- * REGISTER_NAME, DNS_NAME, DNSFAIL_NAME should only be in the wins_server_subnet.
- * WINS_PROXY_NAME should only be on the broadcast subnets.
- * PERMANENT_NAME can be on all subnets except remote_broadcast_subnet.
- *
- */
-
-enum name_source {LMHOSTS_NAME, REGISTER_NAME, SELF_NAME, DNS_NAME,
- DNSFAIL_NAME, PERMANENT_NAME, WINS_PROXY_NAME};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
-enum master_state {
- MST_NONE,
- MST_POTENTIAL,
- MST_BACKUP,
- MST_MSB,
- MST_BROWSER,
- MST_UNBECOMING_MASTER
-};
-
-enum domain_state {
- DOMAIN_NONE,
- DOMAIN_WAIT,
- DOMAIN_MST
-};
-
-enum logon_state {
- LOGON_NONE,
- LOGON_WAIT,
- LOGON_SRV
-};
-
-struct subnet_record;
-
-struct nmb_data {
- uint16_t nb_flags; /* Netbios flags. */
- int num_ips; /* Number of ip entries. */
- struct in_addr *ip; /* The ip list for this name. */
-
- enum name_source source; /* Where the name came from. */
-
- time_t death_time; /* The time the record must be removed (do not remove if 0). */
- time_t refresh_time; /* The time the record should be refreshed. */
-
- uint64_t id; /* unique id */
- struct in_addr wins_ip; /* the address of the wins server this record comes from */
-
- int wins_flags; /* similar to the netbios flags but different ! */
-};
-
-/* This structure represents an entry in a local netbios name list. */
-struct name_record {
- struct name_record *prev, *next;
- struct subnet_record *subnet;
- struct nmb_name name; /* The netbios name. */
- struct nmb_data data; /* The netbios data. */
-};
-
-/* Browser cache for synchronising browse lists. */
-struct browse_cache_record {
- struct browse_cache_record *prev, *next;
- unstring lmb_name;
- unstring work_group;
- struct in_addr ip;
- time_t sync_time;
- time_t death_time; /* The time the record must be removed. */
-};
-
-/* used for server information: client, nameserv and ipc */
-struct server_info_struct {
- fstring name;
- uint32_t type;
- fstring comment;
- fstring domain; /* used ONLY in ipc.c NOT namework.c */
- bool server_added; /* used ONLY in ipc.c NOT namework.c */
-};
-
-/* This is used to hold the list of servers in my domain, and is
- contained within lists of domains. */
-
-struct server_record {
- struct server_record *next;
- struct server_record *prev;
-
- struct subnet_record *subnet;
-
- struct server_info_struct serv;
- time_t death_time;
-};
-
-/* A workgroup structure. It contains a list of servers. */
-struct work_record {
- struct work_record *next;
- struct work_record *prev;
-
- struct subnet_record *subnet;
-
- struct server_record *serverlist;
-
- /* Stage of development from non-local-master up to local-master browser. */
- enum master_state mst_state;
-
- /* Stage of development from non-domain-master to domain-master browser. */
- enum domain_state dom_state;
-
- /* Stage of development from non-logon-server to logon server. */
- enum logon_state log_state;
-
- /* Work group info. */
- unstring work_group;
- int token; /* Used when communicating with backup browsers. */
- unstring local_master_browser_name; /* Current local master browser. */
-
- /* Announce info. */
- time_t lastannounce_time;
- int announce_interval;
- bool needannounce;
-
- /* Timeout time for this workgroup. 0 means permanent. */
- time_t death_time;
-
- /* Election info */
- bool RunningElection;
- bool needelection;
- int ElectionCount;
- uint32_t ElectionCriterion;
-
- /* Domain master browser info. Used for efficient syncs. */
- struct nmb_name dmb_name;
- struct in_addr dmb_addr;
-};
-
-/* typedefs needed to define copy & free functions for userdata. */
-struct userdata_struct;
-
-typedef struct userdata_struct * (*userdata_copy_fn)(struct userdata_struct *);
-typedef void (*userdata_free_fn)(struct userdata_struct *);
-
-/* Structure to define any userdata passed around. */
-
-struct userdata_struct {
- userdata_copy_fn copy_fn;
- userdata_free_fn free_fn;
- unsigned int userdata_len;
- char data[16]; /* 16 is to ensure alignment/padding on all systems */
+#define MAX_NETBIOSNAME_LEN 16
+/* DOS character, NetBIOS namestring. Type used on the wire. */
+typedef char nstring[MAX_NETBIOSNAME_LEN];
+/* Unix character, NetBIOS namestring. Type used to manipulate name in nmbd. */
+typedef char unstring[MAX_NETBIOSNAME_LEN*4];
+
+/* A netbios name structure. */
+struct nmb_name {
+ nstring name;
+ char scope[64];
+ unsigned int name_type;
};
-struct response_record;
-struct packet_struct;
-struct res_rec;
-
-/* typedef to define the function called when this response packet comes in. */
-typedef void (*response_function)(struct subnet_record *, struct response_record *,
- struct packet_struct *);
-
-/* typedef to define the function called when this response record times out. */
-typedef void (*timeout_response_function)(struct subnet_record *,
- struct response_record *);
-
-/* typedef to define the function called when the request that caused this
- response record to be created is successful. */
-typedef void (*success_function)(struct subnet_record *, struct userdata_struct *, ...);
-
-/* typedef to define the function called when the request that caused this
- response record to be created is unsuccessful. */
-typedef void (*fail_function)(struct subnet_record *, struct response_record *, ...);
-
-/* List of typedefs for success and fail functions of the different query
- types. Used to catch any compile time prototype errors. */
-
-typedef void (*register_name_success_function)( struct subnet_record *,
- struct userdata_struct *,
- struct nmb_name *,
- uint16_t,
- int,
- struct in_addr);
-typedef void (*register_name_fail_function)( struct subnet_record *,
- struct response_record *,
- struct nmb_name *);
-
-typedef void (*release_name_success_function)( struct subnet_record *,
- struct userdata_struct *,
- struct nmb_name *,
- struct in_addr);
-typedef void (*release_name_fail_function)( struct subnet_record *,
- struct response_record *,
- struct nmb_name *);
-
-typedef void (*refresh_name_success_function)( struct subnet_record *,
- struct userdata_struct *,
- struct nmb_name *,
- uint16_t,
- int,
- struct in_addr);
-typedef void (*refresh_name_fail_function)( struct subnet_record *,
- struct response_record *,
- struct nmb_name *);
-
-typedef void (*query_name_success_function)( struct subnet_record *,
- struct userdata_struct *,
- struct nmb_name *,
- struct in_addr,
- struct res_rec *answers);
-
-typedef void (*query_name_fail_function)( struct subnet_record *,
- struct response_record *,
- struct nmb_name *,
- int);
-
-typedef void (*node_status_success_function)( struct subnet_record *,
- struct userdata_struct *,
- struct res_rec *,
- struct in_addr);
-typedef void (*node_status_fail_function)( struct subnet_record *,
- struct response_record *);
-
-/* Initiated name queries are recorded in this list to track any responses. */
-
-struct response_record {
- struct response_record *next;
- struct response_record *prev;
-
- uint16_t response_id;
-
- /* Callbacks for packets received or not. */
- response_function resp_fn;
- timeout_response_function timeout_fn;
-
- /* Callbacks for the request succeeding or not. */
- success_function success_fn;
- fail_function fail_fn;
-
- struct packet_struct *packet;
-
- struct userdata_struct *userdata;
-
- int num_msgs;
-
- time_t repeat_time;
- time_t repeat_interval;
- int repeat_count;
-
- /* Recursion protection. */
- bool in_expiration_processing;
+/* A netbios node status array element. */
+struct node_status {
+ nstring name;
+ unsigned char type;
+ unsigned char flags;
};
-/* A subnet structure. It contains a list of workgroups and netbios names. */
-
-/*
- B nodes will have their own, totally separate subnet record, with their
- own netbios name set. These do NOT interact with other subnet records'
- netbios names.
-*/
-
-enum subnet_type {
- NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
- UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
- REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
- WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
-};
-
-struct subnet_record {
- struct subnet_record *next;
- struct subnet_record *prev;
-
- char *subnet_name; /* For Debug identification. */
- enum subnet_type type; /* To catagorize the subnet. */
-
- struct work_record *workgrouplist; /* List of workgroups. */
- struct name_record *namelist; /* List of netbios names. */
- struct response_record *responselist; /* List of responses expected. */
-
- bool namelist_changed;
- bool work_changed;
-
- struct in_addr bcast_ip;
- struct in_addr mask_ip;
- struct in_addr myip;
- int nmb_sock; /* socket to listen for unicast 137. */
- int nmb_bcast; /* socket to listen for broadcast 137. */
- int dgram_sock; /* socket to listen for unicast 138. */
- int dgram_bcast; /* socket to listen for broadcast 138. */
+/* The extra info from a NetBIOS node status query */
+struct node_status_extra {
+ unsigned char mac_addr[6];
+ /* There really is more here ... */
};
/* A resource record. */
@@ -564,66 +286,4 @@ struct packet_struct
#define ANN_ResetBrowserState 14
#define ANN_LocalMasterAnnouncement 15
-
-/* Broadcast packet announcement intervals, in minutes. */
-
-/* Attempt to add domain logon and domain master names. */
-#define CHECK_TIME_ADD_DOM_NAMES 5
-
-/* Search for master browsers of workgroups samba knows about,
- except default. */
-#define CHECK_TIME_MST_BROWSE 5
-
-/* Request backup browser announcements from other servers. */
-#define CHECK_TIME_ANNOUNCE_BACKUP 15
-
-/* Request host announcements from other servers: min and max of interval. */
-#define CHECK_TIME_MIN_HOST_ANNCE 3
-#define CHECK_TIME_MAX_HOST_ANNCE 12
-
-/* Announce as master to WINS server and any Primary Domain Controllers. */
-#define CHECK_TIME_MST_ANNOUNCE 15
-
-/* Time between syncs from domain master browser to local master browsers. */
-#define CHECK_TIME_DMB_TO_LMB_SYNC 15
-
-/* Do all remote announcements this often. */
-#define REMOTE_ANNOUNCE_INTERVAL 180
-
-/* what is the maximum period between name refreshes. Note that this only
- affects non-permanent self names (in seconds) */
-#define MAX_REFRESH_TIME (60*20)
-
-/* The Extinction interval: 4 days, time a node will stay in released state */
-#define EXTINCTION_INTERVAL (4*24*60*60)
-
-/* The Extinction time-out: 1 day, time a node will stay in deleted state */
-#define EXTINCTION_TIMEOUT (24*60*60)
-
-/* Macro's to enumerate subnets either with or without
- the UNICAST subnet. */
-
-extern struct subnet_record *subnetlist;
-extern struct subnet_record *unicast_subnet;
-extern struct subnet_record *wins_server_subnet;
-extern struct subnet_record *remote_broadcast_subnet;
-
-#define FIRST_SUBNET subnetlist
-#define NEXT_SUBNET_EXCLUDING_UNICAST(x) ((x)->next)
-#define NEXT_SUBNET_INCLUDING_UNICAST(x) (get_next_subnet_maybe_unicast((x)))
-
-/* wins replication record used between nmbd and wrepld */
-typedef struct _WINS_RECORD {
- char name[17];
- char type;
- int nb_flags;
- int wins_flags;
- uint64_t id;
- int num_ips;
- struct in_addr ip[25];
- struct in_addr wins_ip;
-} WINS_RECORD;
-
-/* To be removed. */
-enum state_type { TEST };
#endif /* _NAMESERV_H_ */
diff --git a/source3/include/session.h b/source3/include/session.h
index 40c25e5..903208e 100644
--- a/source3/include/session.h
+++ b/source3/include/session.h
@@ -39,6 +39,7 @@ struct sessionid {
fstring ip_addr_str;
time_t connect_start;
uint16_t connection_dialect;
+ bool authenticated;
uint8_t encryption_flags;
uint16_t cipher;
uint16_t signing;
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 81d761d..ce18872 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -625,31 +625,7 @@ struct kernel_oplocks_ops {
#include "smb_macros.h"
-#define MAX_NETBIOSNAME_LEN 16
-/* DOS character, NetBIOS namestring. Type used on the wire. */
-typedef char nstring[MAX_NETBIOSNAME_LEN];
-/* Unix character, NetBIOS namestring. Type used to manipulate name in nmbd. */
-typedef char unstring[MAX_NETBIOSNAME_LEN*4];
-
-/* A netbios name structure. */
-struct nmb_name {
- nstring name;
- char scope[64];
- unsigned int name_type;
-};
-
-/* A netbios node status array element. */
-struct node_status {
- nstring name;
- unsigned char type;
- unsigned char flags;
-};
-
-/* The extra info from a NetBIOS node status query */
-struct node_status_extra {
- unsigned char mac_addr[6];
- /* There really is more here ... */
-};
+#include "nameserv.h"
#define SAFE_NETBIOS_CHARS ". -_"
diff --git a/source3/lib/sessionid_tdb.c b/source3/lib/sessionid_tdb.c
index 2376fd4..54bb895 100644
--- a/source3/lib/sessionid_tdb.c
+++ b/source3/lib/sessionid_tdb.c
@@ -24,6 +24,7 @@
#include "session.h"
#include "util_tdb.h"
#include "smbd/globals.h"
+#include "../libcli/security/session.h"
struct sessionid_traverse_read_state {
int (*fn)(const char *key, struct sessionid *session,
@@ -48,11 +49,18 @@ static int sessionid_traverse_read_fn(struct smbXsrv_session_global0 *global,
};
if (session_info != NULL) {
+ enum security_user_level ul;
+
session.uid = session_info->unix_token->uid;
session.gid = session_info->unix_token->gid;
strncpy(session.username,
session_info->unix_info->unix_name,
sizeof(fstring)-1);
+
+ ul = security_session_user_level(session_info, NULL);
+ if (ul >= SECURITY_USER) {
+ session.authenticated = true;
+ }
}
strncpy(session.remote_machine,
diff --git a/source3/lib/util_tdb.c b/source3/lib/util_tdb.c
index d85f676..3c7c194 100644
--- a/source3/lib/util_tdb.c
+++ b/source3/lib/util_tdb.c
@@ -324,11 +324,11 @@ int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
return 1;
}
if (t1.dptr == t2.dptr) {
- return t1.dsize - t2.dsize;
+ return NUMERIC_CMP(t1.dsize, t2.dsize);
}
ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
if (ret == 0) {
- return t1.dsize - t2.dsize;
+ return NUMERIC_CMP(t1.dsize, t2.dsize);
}
return ret;
}
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index f76c566..6c6d23c 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -437,23 +437,23 @@ static char *get_kdc_ip_string(char *mem_ctx,
char *kdc_str = NULL;
char *canon_sockaddr = NULL;
- SMB_ASSERT(pss != NULL);
-
- canon_sockaddr = print_canonical_sockaddr_with_port(frame, pss);
- if (canon_sockaddr == NULL) {
- goto out;
- }
+ if (pss != NULL) {
+ canon_sockaddr = print_canonical_sockaddr_with_port(frame, pss);
+ if (canon_sockaddr == NULL) {
+ goto out;
+ }
- kdc_str = talloc_asprintf(frame,
- "\t\tkdc = %s\n",
- canon_sockaddr);
- if (kdc_str == NULL) {
- goto out;
- }
+ kdc_str = talloc_asprintf(frame,
+ "\t\tkdc = %s\n",
+ canon_sockaddr);
+ if (kdc_str == NULL) {
+ goto out;
+ }
- ok = sockaddr_storage_to_samba_sockaddr(&sa, pss);
- if (!ok) {
- goto out;
+ ok = sockaddr_storage_to_samba_sockaddr(&sa, pss);
+ if (!ok) {
+ goto out;
+ }
}
/*
@@ -704,7 +704,7 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
return false;
}
- if (domain == NULL || pss == NULL) {
+ if (domain == NULL) {
return false;
}
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index b5139e5..d467079 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -275,12 +275,12 @@ static bool ads_fill_cldap_reply(ADS_STRUCT *ads,
/* Fill in the ads->config values */
+ ADS_TALLOC_CONST_FREE(ads->config.workgroup);
ADS_TALLOC_CONST_FREE(ads->config.realm);
ADS_TALLOC_CONST_FREE(ads->config.bind_path);
ADS_TALLOC_CONST_FREE(ads->config.ldap_server_name);
ADS_TALLOC_CONST_FREE(ads->config.server_site_name);
ADS_TALLOC_CONST_FREE(ads->config.client_site_name);
- ADS_TALLOC_CONST_FREE(ads->server.workgroup);
if (!check_cldap_reply_required_flags(cldap_reply->server_type,
ads->config.flags)) {
@@ -296,6 +296,13 @@ static bool ads_fill_cldap_reply(ADS_STRUCT *ads,
goto out;
}
+ ads->config.workgroup = talloc_strdup(ads, cldap_reply->domain_name);
+ if (ads->config.workgroup == NULL) {
+ DBG_WARNING("Out of memory\n");
+ ret = false;
+ goto out;
+ }
+
ads->config.realm = talloc_asprintf_strupper_m(ads,
"%s",
cldap_reply->dns_domain);
@@ -334,13 +341,6 @@ static bool ads_fill_cldap_reply(ADS_STRUCT *ads,
}
}
- ads->server.workgroup = talloc_strdup(ads, cldap_reply->domain_name);
- if (ads->server.workgroup == NULL) {
- DBG_WARNING("Out of memory\n");
- ret = false;
- goto out;
- }
-
ads->ldap.port = gc ? LDAP_GC_PORT : LDAP_PORT;
ads->ldap.ss = *ss;
diff --git a/source3/librpc/idl/ads.idl b/source3/librpc/idl/ads.idl
index 4f3a387..d10e5b4 100644
--- a/source3/librpc/idl/ads.idl
+++ b/source3/librpc/idl/ads.idl
@@ -59,6 +59,7 @@ interface ads
typedef [nopull,nopush] struct {
nbt_server_type flags; /* cldap flags identifying the services. */
+ string workgroup;
string realm;
string bind_path;
string ldap_server_name;
diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
index a45bdac..c87c870 100644
--- a/source3/libsmb/clidgram.c
+++ b/source3/libsmb/clidgram.c
@@ -349,7 +349,11 @@ struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- subreq = nb_packet_reader_send(state, ev, DGRAM_PACKET, -1,
+ subreq = nb_packet_reader_send(state,
+ ev,
+ global_nmbd_socket_dir(),
+ DGRAM_PACKET,
+ -1,
state->my_mailslot);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 09a6e66..654893c 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -196,7 +196,29 @@ static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx,
/* FIXME */
r->sockaddr_size = 0x10; /* the w32 winsock addr size */
r->sockaddr.sockaddr_family = 2; /* AF_INET */
- r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, addr);
+ if (is_ipaddress_v4(addr)) {
+ r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, addr);
+ if (r->sockaddr.pdc_ip == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ /*
+ * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX will
+ * fail with an ipv6 address.
+ *
+ * This matches windows behaviour in the CLDAP
+ * response when NETLOGON_NT_VERSION_5EX_WITH_IP
+ * is used.
+ *
+ * Windows returns the ipv4 address of the ipv6
+ * server interface and falls back to 127.0.0.1
+ * if there's no ipv4 address.
+ */
+ r->sockaddr.pdc_ip = talloc_strdup(mem_ctx, "127.0.0.1");
+ if (r->sockaddr.pdc_ip == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
ndr_err = ndr_push_struct_blob(&blob, mem_ctx, r,
(ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX);
@@ -930,6 +952,11 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
name_type = NBT_NAME_PDC;
}
+ /*
+ * It's 2024 we always want an AD style response!
+ */
+ nt_version |= NETLOGON_NT_VERSION_AVOID_NT4EMUL;
+
nt_version |= map_ds_flags_to_nt_version(flags);
snprintf(my_acct_name,
diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c
index dcb2f9e..a902341 100644
--- a/source3/libsmb/libsmb_xattr.c
+++ b/source3/libsmb/libsmb_xattr.c
@@ -121,7 +121,13 @@ ace_compare(struct security_ace *ace1,
*/
if (ace1->type != ace2->type) {
- return ace2->type - ace1->type;
+ /*
+ * ace2 and ace1 are reversed here, so that
+ * ACCESS_DENIED_ACE_TYPE (1) sorts before
+ * ACCESS_ALLOWED_ACE_TYPE (0), which is the order you
+ * usually want.
+ */
+ return NUMERIC_CMP(ace2->type, ace1->type);
}
if (dom_sid_compare(&ace1->trustee, &ace2->trustee)) {
@@ -129,15 +135,15 @@ ace_compare(struct security_ace *ace1,
}
if (ace1->flags != ace2->flags) {
- return ace1->flags - ace2->flags;
+ return NUMERIC_CMP(ace1->flags, ace2->flags);
}
if (ace1->access_mask != ace2->access_mask) {
- return ace1->access_mask - ace2->access_mask;
+ return NUMERIC_CMP(ace1->access_mask, ace2->access_mask);
}
if (ace1->size != ace2->size) {
- return ace1->size - ace2->size;
+ return NUMERIC_CMP(ace1->size, ace2->size);
}
return memcmp(ace1, ace2, sizeof(struct security_ace));
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index e6c0c7d..8f6a9b5 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -34,6 +34,7 @@
#include "lib/gencache.h"
#include "librpc/gen_ndr/dns.h"
#include "lib/util/util_net.h"
+#include "lib/util/tsort.h"
#include "lib/util/string_wrappers.h"
/* nmbd.c sets this to True. */
@@ -644,7 +645,12 @@ static struct tevent_req *nb_trans_send(
return tevent_req_post(req, ev);
}
- subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
+ subreq = nb_packet_reader_send(state,
+ ev,
+ global_nmbd_socket_dir(),
+ type,
+ state->trn_id,
+ NULL);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -1082,8 +1088,15 @@ bool name_status_find(const char *q_name,
}
/*
- comparison function used by sort_addr_list
-*/
+ * comparison function used by sort_addr_list
+ *
+ * This comparison is intransitive in sort if a socket has an invalid
+ * family (i.e., not IPv4 or IPv6), or an interface doesn't support
+ * the family. Say we have sockaddrs with IP versions {4,5,6}, of
+ * which 5 is invalid. By this function, 4 == 5 and 6 == 5, but 4 !=
+ * 6. This is of course a consequence of cmp() being unable to
+ * communicate error.
+ */
static int addr_compare(const struct sockaddr_storage *ss1,
const struct sockaddr_storage *ss2)
@@ -1171,7 +1184,7 @@ static int addr_compare(const struct sockaddr_storage *ss1,
max_bits2 += 128;
}
}
- return max_bits2 - max_bits1;
+ return NUMERIC_CMP(max_bits2, max_bits1);
}
/*
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index c90e92e..2297dd9 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -23,6 +23,12 @@
#include "libsmb/nmblib.h"
#include "lib/util/string_wrappers.h"
+const char *global_nmbd_socket_dir(void)
+{
+ return lp_parm_const_string(-1, "nmbd", "socket dir",
+ get_dyn_NMBDSOCKETDIR());
+}
+
static const struct opcode_names {
const char *nmb_opcode_name;
int opcode;
@@ -1229,8 +1235,10 @@ static unsigned char sort_ip[4];
static int name_query_comp(unsigned char *p1, unsigned char *p2)
{
- return matching_len_bits(p2+2, sort_ip, 4) -
- matching_len_bits(p1+2, sort_ip, 4);
+ int a = matching_len_bits(p1+2, sort_ip, 4);
+ int b = matching_len_bits(p2+2, sort_ip, 4);
+ /* reverse sort -- p2 derived value comes first */
+ return NUMERIC_CMP(b, a);
}
/****************************************************************************
diff --git a/source3/libsmb/nmblib.h b/source3/libsmb/nmblib.h
index 52600a4..5171a26 100644
--- a/source3/libsmb/nmblib.h
+++ b/source3/libsmb/nmblib.h
@@ -29,6 +29,8 @@
/* The following definitions come from libsmb/nmblib.c */
+const char *global_nmbd_socket_dir(void);
+
void debug_nmb_packet(struct packet_struct *p);
void put_name(char *dest, const char *name, int pad, unsigned int name_type);
char *nmb_namestr(const struct nmb_name *n);
diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index b81d379..10ceac7 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -26,12 +26,6 @@
#include "lib/tsocket/tsocket.h"
#include "lib/util/sys_rw.h"
-static const char *nmbd_socket_dir(void)
-{
- return lp_parm_const_string(-1, "nmbd", "socket dir",
- get_dyn_NMBDSOCKETDIR());
-}
-
struct nb_packet_query {
enum packet_type type;
size_t mailslot_namelen;
@@ -74,6 +68,7 @@ static void nb_packet_server_listener(struct tevent_context *ev,
NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ const char *nmbd_socket_dir,
int max_clients,
struct nb_packet_server **presult)
{
@@ -90,7 +85,7 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
result->max_clients = max_clients;
result->listen_sock = create_pipe_sock(
- nmbd_socket_dir(), "unexpected", 0755);
+ nmbd_socket_dir, "unexpected", 0755);
if (result->listen_sock == -1) {
status = map_nt_error_from_unix(errno);
goto fail;
@@ -248,7 +243,7 @@ static void nb_packet_got_query(struct tevent_req *req)
ssize_t nread;
int err;
- nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
+ nread = tstream_read_packet_recv(req, client, &buf, &err);
TALLOC_FREE(req);
if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
DEBUG(10, ("read_packet_recv returned %d (%s)\n",
@@ -280,6 +275,8 @@ static void nb_packet_got_query(struct tevent_req *req)
}
}
+ TALLOC_FREE(buf);
+
client->ack.byte = 0;
client->ack.iov[0].iov_base = &client->ack.byte;
client->ack.iov[0].iov_len = 1;
@@ -333,7 +330,7 @@ static void nb_packet_client_read_done(struct tevent_req *req)
uint8_t *buf;
int err;
- nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
+ nread = tstream_read_packet_recv(req, client, &buf, &err);
TALLOC_FREE(req);
if (nread == 1) {
DEBUG(10, ("Protocol error, received data on write-only "
@@ -495,6 +492,7 @@ static void nb_packet_reader_got_ack(struct tevent_req *subreq);
struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ const char *nmbd_socket_dir,
enum packet_type type,
int trn_id,
const char *mailslot_name)
@@ -530,7 +528,7 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
tevent_req_nterror(req, map_nt_error_from_unix(errno));
return tevent_req_post(req, ev);
}
- rpath = talloc_asprintf(state, "%s/%s", nmbd_socket_dir(),
+ rpath = talloc_asprintf(state, "%s/%s", nmbd_socket_dir,
"unexpected");
if (tevent_req_nomem(rpath, req)) {
return tevent_req_post(req, ev);
diff --git a/source3/libsmb/unexpected.h b/source3/libsmb/unexpected.h
index 270976b..4ae9b20 100644
--- a/source3/libsmb/unexpected.h
+++ b/source3/libsmb/unexpected.h
@@ -29,12 +29,14 @@ struct nb_packet_reader;
NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ const char *nmbd_socket_dir,
int max_clients,
struct nb_packet_server **presult);
void nb_packet_dispatch(struct nb_packet_server *server,
struct packet_struct *p);
struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ const char *nmbd_socket_dir,
enum packet_type type,
int trn_id,
const char *mailslot_name);
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 905da04..328a9bf 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -408,12 +408,9 @@ static int lock_compare(const struct lock_struct *lck1,
const struct lock_struct *lck2)
{
if (lck1->start != lck2->start) {
- return (lck1->start - lck2->start);
+ return NUMERIC_CMP(lck1->start, lck2->start);
}
- if (lck2->size != lck1->size) {
- return ((int)lck1->size - (int)lck2->size);
- }
- return 0;
+ return NUMERIC_CMP(lck1->size, lck2->size);
}
#endif
diff --git a/source3/modules/posixacl_xattr.c b/source3/modules/posixacl_xattr.c
index 365cdc7..5d0516c 100644
--- a/source3/modules/posixacl_xattr.c
+++ b/source3/modules/posixacl_xattr.c
@@ -226,14 +226,14 @@ static int posixacl_xattr_entry_compare(const void *left, const void *right)
tag_left = SVAL(left, 0);
tag_right = SVAL(right, 0);
- ret = (tag_left - tag_right);
- if (!ret) {
+ ret = NUMERIC_CMP(tag_left, tag_right);
+ if (ret == 0) {
/* ID is the third element in the entry, after two short
integers (tag and perm), i.e at offset 4.
*/
id_left = IVAL(left, 4);
id_right = IVAL(right, 4);
- ret = id_left - id_right;
+ ret = NUMERIC_CMP(id_left, id_right);
}
return ret;
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 62ad506..7380598 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -2147,6 +2147,12 @@ static struct tevent_req *vfswrap_offload_write_send(
.remaining = to_copy,
};
+ status = vfs_offload_token_ctx_init(handle->conn->sconn->client,
+ &vfswrap_offload_ctx);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
switch (fsctl) {
diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c
index 327a7ee..ea0417d 100644
--- a/source3/modules/vfs_recycle.c
+++ b/source3/modules/vfs_recycle.c
@@ -55,10 +55,14 @@ static int vfs_recycle_connect(struct vfs_handle_struct *handle,
const char *service,
const char *user)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
struct recycle_config_data *config = NULL;
int ret;
int t;
- const char *buff;
+ const char *buff = NULL;
+ const char **tmplist = NULL;
+ char *repository = NULL;
ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
if (ret < 0) {
@@ -75,10 +79,30 @@ static int vfs_recycle_connect(struct vfs_handle_struct *handle,
errno = ENOMEM;
return -1;
}
- config->repository = lp_parm_const_string(SNUM(handle->conn),
- "recycle",
- "repository",
- ".recycle");
+ buff = lp_parm_const_string(SNUM(handle->conn),
+ "recycle",
+ "repository",
+ ".recycle");
+ repository = talloc_sub_full(
+ config,
+ lp_servicename(talloc_tos(), lp_sub, SNUM(handle->conn)),
+ handle->conn->session_info->unix_info->unix_name,
+ handle->conn->connectpath,
+ handle->conn->session_info->unix_token->gid,
+ handle->conn->session_info->unix_info->sanitized_username,
+ handle->conn->session_info->info->domain_name,
+ buff);
+ if (repository == NULL) {
+ DBG_ERR("talloc_sub_full() failed\n");
+ TALLOC_FREE(config);
+ errno = ENOMEM;
+ return -1;
+ }
+ /* shouldn't we allow absolute path names here? --metze */
+ /* Yes :-). JRA. */
+ trim_char(repository, '\0', '/');
+ config->repository = repository;
+
config->keeptree = lp_parm_bool(SNUM(handle->conn),
"recycle",
"keeptree",
@@ -95,18 +119,48 @@ static int vfs_recycle_connect(struct vfs_handle_struct *handle,
"recycle",
"touch_mtime",
False);
- config->exclude = lp_parm_string_list(SNUM(handle->conn),
- "recycle",
- "exclude",
- NULL);
- config->exclude_dir = lp_parm_string_list(SNUM(handle->conn),
- "recycle",
- "exclude_dir",
- NULL);
- config->noversions = lp_parm_string_list(SNUM(handle->conn),
- "recycle",
- "noversions",
- NULL);
+ tmplist = lp_parm_string_list(SNUM(handle->conn),
+ "recycle",
+ "exclude",
+ NULL);
+ if (tmplist != NULL) {
+ char **tmpcpy = str_list_copy(config, tmplist);
+ if (tmpcpy == NULL) {
+ DBG_ERR("str_list_copy() failed\n");
+ TALLOC_FREE(config);
+ errno = ENOMEM;
+ return -1;
+ }
+ config->exclude = discard_const_p(const char *, tmpcpy);
+ }
+ tmplist = lp_parm_string_list(SNUM(handle->conn),
+ "recycle",
+ "exclude_dir",
+ NULL);
+ if (tmplist != NULL) {
+ char **tmpcpy = str_list_copy(config, tmplist);
+ if (tmpcpy == NULL) {
+ DBG_ERR("str_list_copy() failed\n");
+ TALLOC_FREE(config);
+ errno = ENOMEM;
+ return -1;
+ }
+ config->exclude_dir = discard_const_p(const char *, tmpcpy);
+ }
+ tmplist = lp_parm_string_list(SNUM(handle->conn),
+ "recycle",
+ "noversions",
+ NULL);
+ if (tmplist != NULL) {
+ char **tmpcpy = str_list_copy(config, tmplist);
+ if (tmpcpy == NULL) {
+ DBG_ERR("str_list_copy() failed\n");
+ TALLOC_FREE(config);
+ errno = ENOMEM;
+ return -1;
+ }
+ config->noversions = discard_const_p(const char *, tmpcpy);
+ }
config->minsize = conv_str_size(lp_parm_const_string(
SNUM(handle->conn), "recycle", "minsize", NULL));
config->maxsize = conv_str_size(lp_parm_const_string(
@@ -421,42 +475,27 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
const struct smb_filename *smb_fname,
int flags)
{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- connection_struct *conn = handle->conn;
+ TALLOC_CTX *frame = NULL;
struct smb_filename *full_fname = NULL;
char *path_name = NULL;
- char *temp_name = NULL;
- char *final_name = NULL;
+ const char *temp_name = NULL;
+ const char *final_name = NULL;
struct smb_filename *smb_fname_final = NULL;
- const char *base;
- char *repository = NULL;
+ const char *base = NULL;
int i = 1;
off_t file_size; /* space_avail; */
bool exist;
int rc = -1;
- struct recycle_config_data *config;
+ struct recycle_config_data *config = NULL;
SMB_VFS_HANDLE_GET_DATA(handle,
config,
struct recycle_config_data,
- return true);
+ return -1);
- repository = talloc_sub_full(
- NULL,
- lp_servicename(talloc_tos(), 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,
- config->repository);
- ALLOC_CHECK(repository, done);
- /* shouldn't we allow absolute path names here? --metze */
- /* Yes :-). JRA. */
- trim_char(repository, '\0', '/');
+ frame = talloc_stackframe();
- if(!repository || *(repository) == '\0') {
+ if (config->repository[0] == '\0') {
DEBUG(3, ("recycle: repository path not set, purging %s...\n",
smb_fname_str_dbg(smb_fname)));
rc = SMB_VFS_NEXT_UNLINKAT(handle,
@@ -466,16 +505,18 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
goto done;
}
- full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ full_fname = full_path_from_dirfsp_atname(frame,
dirfsp,
smb_fname);
if (full_fname == NULL) {
- return -1;
+ rc = -1;
+ errno = ENOMEM;
+ goto done;
}
/* we don't recycle the recycle bin... */
- if (strncmp(full_fname->base_name, repository,
- strlen(repository)) == 0) {
+ if (strncmp(full_fname->base_name, config->repository,
+ strlen(config->repository)) == 0) {
DEBUG(3, ("recycle: File is within recycling bin, unlinking ...\n"));
rc = SMB_VFS_NEXT_UNLINKAT(handle,
dirfsp,
@@ -539,7 +580,7 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
*/
/* extract filename and path */
- if (!parent_dirname(talloc_tos(), full_fname->base_name, &path_name, &base)) {
+ if (!parent_dirname(frame, full_fname->base_name, &path_name, &base)) {
rc = -1;
errno = ENOMEM;
goto done;
@@ -571,13 +612,16 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
}
if (config->keeptree) {
- if (asprintf(&temp_name, "%s/%s", repository, path_name) == -1) {
- ALLOC_CHECK(temp_name, done);
+ temp_name = talloc_asprintf(frame, "%s/%s",
+ config->repository,
+ path_name);
+ if (temp_name == NULL) {
+ rc = -1;
+ goto done;
}
} else {
- temp_name = SMB_STRDUP(repository);
+ temp_name = config->repository;
}
- ALLOC_CHECK(temp_name, done);
exist = recycle_directory_exist(handle, temp_name);
if (exist) {
@@ -600,12 +644,15 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
}
}
- if (asprintf(&final_name, "%s/%s", temp_name, base) == -1) {
- ALLOC_CHECK(final_name, done);
+ final_name = talloc_asprintf(frame, "%s/%s",
+ temp_name, base);
+ if (final_name == NULL) {
+ rc = -1;
+ goto done;
}
/* Create smb_fname with final base name and orig stream name. */
- smb_fname_final = synthetic_smb_fname(talloc_tos(),
+ smb_fname_final = synthetic_smb_fname(frame,
final_name,
full_fname->stream_name,
NULL,
@@ -641,20 +688,16 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
/* rename file we move to recycle bin */
i = 1;
while (recycle_file_exist(handle, smb_fname_final)) {
- SAFE_FREE(final_name);
- if (asprintf(&final_name, "%s/Copy #%d of %s", temp_name, i++, base) == -1) {
- ALLOC_CHECK(final_name, done);
- }
+ char *copy = NULL;
+
TALLOC_FREE(smb_fname_final->base_name);
- smb_fname_final->base_name = talloc_strdup(smb_fname_final,
- final_name);
- if (smb_fname_final->base_name == NULL) {
- rc = SMB_VFS_NEXT_UNLINKAT(handle,
- dirfsp,
- smb_fname,
- flags);
+ copy = talloc_asprintf(smb_fname_final, "%s/Copy #%d of %s",
+ temp_name, i++, base);
+ if (copy == NULL) {
+ rc = -1;
goto done;
}
+ smb_fname_final->base_name = copy;
}
DEBUG(10, ("recycle: Moving %s to %s\n", smb_fname_str_dbg(full_fname),
@@ -681,12 +724,7 @@ static int recycle_unlink_internal(vfs_handle_struct *handle,
recycle_do_touch(handle, smb_fname_final, config->touch_mtime);
done:
- TALLOC_FREE(path_name);
- SAFE_FREE(temp_name);
- SAFE_FREE(final_name);
- TALLOC_FREE(full_fname);
- TALLOC_FREE(smb_fname_final);
- TALLOC_FREE(repository);
+ TALLOC_FREE(frame);
return rc;
}
diff --git a/source3/modules/vfs_vxfs.c b/source3/modules/vfs_vxfs.c
index aae2ca1..ecc53d0 100644
--- a/source3/modules/vfs_vxfs.c
+++ b/source3/modules/vfs_vxfs.c
@@ -111,13 +111,13 @@ static int vxfs_ace_cmp(const void *ace1, const void *ace2)
type_a1 = SVAL(ace1, 0);
type_a2 = SVAL(ace2, 0);
- ret = (type_a1 - type_a2);
- if (!ret) {
+ ret = NUMERIC_CMP(type_a1, type_a2);
+ if (ret == 0) {
/* Compare ID under type */
/* skip perm thus take offset as 4*/
id_a1 = IVAL(ace1, 4);
id_a2 = IVAL(ace2, 4);
- ret = id_a1 - id_a2;
+ ret = NUMERIC_CMP(id_a1, id_a2);
}
return ret;
diff --git a/source3/modules/vfs_widelinks.c b/source3/modules/vfs_widelinks.c
index c5b5084..4339f6d 100644
--- a/source3/modules/vfs_widelinks.c
+++ b/source3/modules/vfs_widelinks.c
@@ -383,8 +383,17 @@ static int widelinks_openat(vfs_handle_struct *handle,
}
lstat_ret = SMB_VFS_NEXT_LSTAT(handle,
full_fname);
- if (lstat_ret != -1 &&
- VALID_STAT(full_fname->st) &&
+ if (lstat_ret == -1) {
+ /*
+ * Path doesn't exist. We must
+ * return errno from LSTAT.
+ */
+ int saved_errno = errno;
+ TALLOC_FREE(full_fname);
+ errno = saved_errno;
+ return -1;
+ }
+ if (VALID_STAT(full_fname->st) &&
S_ISLNK(full_fname->st.st_ex_mode)) {
fsp->fsp_name->st = full_fname->st;
}
diff --git a/source3/nmbd/nmbd.h b/source3/nmbd/nmbd.h
index f207eb9..0a8e345 100644
--- a/source3/nmbd/nmbd.h
+++ b/source3/nmbd/nmbd.h
@@ -26,6 +26,388 @@
#endif
#include "libsmb/nmblib.h"
+
+#define INFO_VERSION "INFO/version"
+#define INFO_COUNT "INFO/num_entries"
+#define INFO_ID_HIGH "INFO/id_high"
+#define INFO_ID_LOW "INFO/id_low"
+#define ENTRY_PREFIX "ENTRY/"
+
+#define PERMANENT_TTL 0
+
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 1
+
+#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
+
+/* Workgroup state identifiers. */
+#define AM_POTENTIAL_MASTER_BROWSER(work) ((work)->mst_state == MST_POTENTIAL)
+#define AM_LOCAL_MASTER_BROWSER(work) ((work)->mst_state == MST_BROWSER)
+#define AM_DOMAIN_MASTER_BROWSER(work) ((work)->dom_state == DOMAIN_MST)
+#define AM_DOMAIN_MEMBER(work) ((work)->log_state == LOGON_SRV)
+
+/* Microsoft browser NetBIOS name. */
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+
+/* Mail slots. */
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
+#define NT_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NTLOGON"
+#define LANMAN_MAILSLOT "\\MAILSLOT\\LANMAN"
+
+/* Samba definitions for find_name_on_subnet(). */
+#define FIND_ANY_NAME 0
+#define FIND_SELF_NAME 1
+
+/*
+ * The different name types that can be in namelists.
+ *
+ * SELF_NAME should only be on the broadcast and unicast subnets.
+ * LMHOSTS_NAME should only be in the remote_broadcast_subnet.
+ * REGISTER_NAME, DNS_NAME, DNSFAIL_NAME should only be in the wins_server_subnet.
+ * WINS_PROXY_NAME should only be on the broadcast subnets.
+ * PERMANENT_NAME can be on all subnets except remote_broadcast_subnet.
+ *
+ */
+
+enum name_source {LMHOSTS_NAME, REGISTER_NAME, SELF_NAME, DNS_NAME,
+ DNSFAIL_NAME, PERMANENT_NAME, WINS_PROXY_NAME};
+
+enum master_state {
+ MST_NONE,
+ MST_POTENTIAL,
+ MST_BACKUP,
+ MST_MSB,
+ MST_BROWSER,
+ MST_UNBECOMING_MASTER
+};
+
+enum domain_state {
+ DOMAIN_NONE,
+ DOMAIN_WAIT,
+ DOMAIN_MST
+};
+
+enum logon_state {
+ LOGON_NONE,
+ LOGON_WAIT,
+ LOGON_SRV
+};
+
+struct subnet_record;
+
+struct nmb_data {
+ uint16_t nb_flags; /* Netbios flags. */
+ int num_ips; /* Number of ip entries. */
+ struct in_addr *ip; /* The ip list for this name. */
+
+ enum name_source source; /* Where the name came from. */
+
+ time_t death_time; /* The time the record must be removed (do not remove if 0). */
+ time_t refresh_time; /* The time the record should be refreshed. */
+
+ uint64_t id; /* unique id */
+ struct in_addr wins_ip; /* the address of the wins server this record comes from */
+
+ int wins_flags; /* similar to the netbios flags but different ! */
+};
+
+/* This structure represents an entry in a local netbios name list. */
+struct name_record {
+ struct name_record *prev, *next;
+ struct subnet_record *subnet;
+ struct nmb_name name; /* The netbios name. */
+ struct nmb_data data; /* The netbios data. */
+};
+
+/* Browser cache for synchronising browse lists. */
+struct browse_cache_record {
+ struct browse_cache_record *prev, *next;
+ unstring lmb_name;
+ unstring work_group;
+ struct in_addr ip;
+ time_t sync_time;
+ time_t death_time; /* The time the record must be removed. */
+};
+
+/* used for server information: client, nameserv and ipc */
+struct server_info_struct {
+ fstring name;
+ uint32_t type;
+ fstring comment;
+ fstring domain; /* used ONLY in ipc.c NOT namework.c */
+ bool server_added; /* used ONLY in ipc.c NOT namework.c */
+};
+
+/* This is used to hold the list of servers in my domain, and is
+ contained within lists of domains. */
+
+struct server_record {
+ struct server_record *next;
+ struct server_record *prev;
+
+ struct subnet_record *subnet;
+
+ struct server_info_struct serv;
+ time_t death_time;
+};
+
+/* A workgroup structure. It contains a list of servers. */
+struct work_record {
+ struct work_record *next;
+ struct work_record *prev;
+
+ struct subnet_record *subnet;
+
+ struct server_record *serverlist;
+
+ /* Stage of development from non-local-master up to local-master browser. */
+ enum master_state mst_state;
+
+ /* Stage of development from non-domain-master to domain-master browser. */
+ enum domain_state dom_state;
+
+ /* Stage of development from non-logon-server to logon server. */
+ enum logon_state log_state;
+
+ /* Work group info. */
+ unstring work_group;
+ int token; /* Used when communicating with backup browsers. */
+ unstring local_master_browser_name; /* Current local master browser. */
+
+ /* Announce info. */
+ time_t lastannounce_time;
+ int announce_interval;
+ bool needannounce;
+
+ /* Timeout time for this workgroup. 0 means permanent. */
+ time_t death_time;
+
+ /* Election info */
+ bool RunningElection;
+ bool needelection;
+ int ElectionCount;
+ uint32_t ElectionCriterion;
+
+ /* Domain master browser info. Used for efficient syncs. */
+ struct nmb_name dmb_name;
+ struct in_addr dmb_addr;
+};
+
+/* typedefs needed to define copy & free functions for userdata. */
+struct userdata_struct;
+
+typedef struct userdata_struct * (*userdata_copy_fn)(struct userdata_struct *);
+typedef void (*userdata_free_fn)(struct userdata_struct *);
+
+/* Structure to define any userdata passed around. */
+
+struct userdata_struct {
+ userdata_copy_fn copy_fn;
+ userdata_free_fn free_fn;
+ unsigned int userdata_len;
+ char data[16]; /* 16 is to ensure alignment/padding on all systems */
+};
+
+struct response_record;
+struct packet_struct;
+struct res_rec;
+
+/* typedef to define the function called when this response packet comes in. */
+typedef void (*response_function)(struct subnet_record *, struct response_record *,
+ struct packet_struct *);
+
+/* typedef to define the function called when this response record times out. */
+typedef void (*timeout_response_function)(struct subnet_record *,
+ struct response_record *);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is successful. */
+typedef void (*success_function)(struct subnet_record *, struct userdata_struct *, ...);
+
+/* typedef to define the function called when the request that caused this
+ response record to be created is unsuccessful. */
+typedef void (*fail_function)(struct subnet_record *, struct response_record *, ...);
+
+/* List of typedefs for success and fail functions of the different query
+ types. Used to catch any compile time prototype errors. */
+
+typedef void (*register_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16_t,
+ int,
+ struct in_addr);
+typedef void (*register_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*release_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr);
+typedef void (*release_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*refresh_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ uint16_t,
+ int,
+ struct in_addr);
+typedef void (*refresh_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *);
+
+typedef void (*query_name_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct nmb_name *,
+ struct in_addr,
+ struct res_rec *answers);
+
+typedef void (*query_name_fail_function)( struct subnet_record *,
+ struct response_record *,
+ struct nmb_name *,
+ int);
+
+typedef void (*node_status_success_function)( struct subnet_record *,
+ struct userdata_struct *,
+ struct res_rec *,
+ struct in_addr);
+typedef void (*node_status_fail_function)( struct subnet_record *,
+ struct response_record *);
+
+/* Initiated name queries are recorded in this list to track any responses. */
+
+struct response_record {
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16_t response_id;
+
+ /* Callbacks for packets received or not. */
+ response_function resp_fn;
+ timeout_response_function timeout_fn;
+
+ /* Callbacks for the request succeeding or not. */
+ success_function success_fn;
+ fail_function fail_fn;
+
+ struct packet_struct *packet;
+
+ struct userdata_struct *userdata;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+
+ /* Recursion protection. */
+ bool in_expiration_processing;
+};
+
+/* A subnet structure. It contains a list of workgroups and netbios names. */
+
+/*
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. These do NOT interact with other subnet records'
+ netbios names.
+*/
+
+enum subnet_type {
+ NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
+ UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
+ REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
+ WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
+};
+
+struct subnet_record {
+ struct subnet_record *next;
+ struct subnet_record *prev;
+
+ char *subnet_name; /* For Debug identification. */
+ enum subnet_type type; /* To catagorize the subnet. */
+
+ struct work_record *workgrouplist; /* List of workgroups. */
+ struct name_record *namelist; /* List of netbios names. */
+ struct response_record *responselist; /* List of responses expected. */
+
+ bool namelist_changed;
+ bool work_changed;
+
+ struct in_addr bcast_ip;
+ struct in_addr mask_ip;
+ struct in_addr myip;
+ int nmb_sock; /* socket to listen for unicast 137. */
+ int nmb_bcast; /* socket to listen for broadcast 137. */
+ int dgram_sock; /* socket to listen for unicast 138. */
+ int dgram_bcast; /* socket to listen for broadcast 138. */
+};
+
+/* Broadcast packet announcement intervals, in minutes. */
+
+/* Attempt to add domain logon and domain master names. */
+#define CHECK_TIME_ADD_DOM_NAMES 5
+
+/* Search for master browsers of workgroups samba knows about,
+ except default. */
+#define CHECK_TIME_MST_BROWSE 5
+
+/* Request backup browser announcements from other servers. */
+#define CHECK_TIME_ANNOUNCE_BACKUP 15
+
+/* Request host announcements from other servers: min and max of interval. */
+#define CHECK_TIME_MIN_HOST_ANNCE 3
+#define CHECK_TIME_MAX_HOST_ANNCE 12
+
+/* Announce as master to WINS server and any Primary Domain Controllers. */
+#define CHECK_TIME_MST_ANNOUNCE 15
+
+/* Time between syncs from domain master browser to local master browsers. */
+#define CHECK_TIME_DMB_TO_LMB_SYNC 15
+
+/* Do all remote announcements this often. */
+#define REMOTE_ANNOUNCE_INTERVAL 180
+
+/* what is the maximum period between name refreshes. Note that this only
+ affects non-permanent self names (in seconds) */
+#define MAX_REFRESH_TIME (60*20)
+
+/* The Extinction interval: 4 days, time a node will stay in released state */
+#define EXTINCTION_INTERVAL (4*24*60*60)
+
+/* The Extinction time-out: 1 day, time a node will stay in deleted state */
+#define EXTINCTION_TIMEOUT (24*60*60)
+
+/* Macro's to enumerate subnets either with or without
+ the UNICAST subnet. */
+
+extern struct subnet_record *subnetlist;
+extern struct subnet_record *unicast_subnet;
+extern struct subnet_record *wins_server_subnet;
+extern struct subnet_record *remote_broadcast_subnet;
+
+#define FIRST_SUBNET subnetlist
+#define NEXT_SUBNET_EXCLUDING_UNICAST(x) ((x)->next)
+#define NEXT_SUBNET_INCLUDING_UNICAST(x) (get_next_subnet_maybe_unicast((x)))
+
+/* wins replication record used between nmbd and wrepld */
+typedef struct _WINS_RECORD {
+ char name[17];
+ char type;
+ int nb_flags;
+ int wins_flags;
+ uint64_t id;
+ int num_ips;
+ struct in_addr ip[25];
+ struct in_addr wins_ip;
+} WINS_RECORD;
+
#include "nmbd/nmbd_proto.h"
#define NMBD_WAIT_INTERFACES_TIME_USEC (250 * 1000)
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index a1d8dee..1da3657 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -43,6 +43,7 @@ bool nmbd_init_packet_server(void)
status = nb_packet_server_create(
NULL, nmbd_event_context(),
+ global_nmbd_socket_dir(),
lp_parm_int(-1, "nmbd", "unexpected_clients", 200),
&packet_server);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/rpc_server/wkssvc/srv_wkssvc_nt.c b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
index 0724dd0..ed16278 100644
--- a/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
+++ b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
@@ -50,7 +50,7 @@ static int dom_user_cmp(const struct dom_usr *usr1, const struct dom_usr *usr2)
/* Called from qsort to compare two domain users in a dom_usr_t array
* for sorting by login time. Return >0 if usr1 login time was later
* than usr2 login time, <0 if it was earlier */
- return (usr1->login_time - usr2->login_time);
+ return NUMERIC_CMP(usr1->login_time, usr2->login_time);
}
/*******************************************************************
diff --git a/source3/script/tests/test_recycle.sh b/source3/script/tests/test_recycle.sh
index 8c9291f..ba1d0a5 100755
--- a/source3/script/tests/test_recycle.sh
+++ b/source3/script/tests/test_recycle.sh
@@ -90,11 +90,16 @@ quit
return 0
}
+panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
testit "recycle" \
test_recycle ||
failed=$((failed + 1))
+panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
+
+testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $failed + 1)
+
#
# Cleanup.
do_cleanup
diff --git a/source3/script/tests/test_widelink_dfs_ci.sh b/source3/script/tests/test_widelink_dfs_ci.sh
new file mode 100755
index 0000000..6ae5cf5
--- /dev/null
+++ b/source3/script/tests/test_widelink_dfs_ci.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# regression test for dfs access with wide links enabled on dfs share
+# Ensure we still maintain case insensitivity.
+
+if [ $# -lt 7 ]; then
+ cat <<EOF
+Usage: test_widelink_dfs_ci.sh SERVER SERVER_IP SHARE USERNAME PASSWORD PREFIX SMBCLIENT <smbclient arguments>
+EOF
+ exit 1
+fi
+
+SERVER="$1"
+SERVER_IP="$2"
+SHARE="$3"
+USERNAME="$4"
+PASSWORD="$5"
+PREFIX="$6"
+SMBCLIENT="$7"
+shift 7
+ADDARGS="$@"
+
+incdir=$(dirname "$0")"/../../../testprogs/blackbox"
+. "$incdir/subunit.sh"
+. "$incdir/common_test_fns.inc"
+
+failed=0
+
+# Do not let deprecated option warnings muck this up
+SAMBA_DEPRECATED_SUPPRESS=1
+export SAMBA_DEPRECATED_SUPPRESS
+
+# Test chdir'ing into a lowercase directory with upper case.
+test_ci()
+{
+ tmpfile="$PREFIX/smbclient_ci_commands"
+
+ cat >"$tmpfile" <<EOF
+mkdir x
+cd X
+cd ..
+rmdir x
+quit
+EOF
+
+ cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT "$@" -U$USERNAME%$PASSWORD //$SERVER/msdfs-share-wl -I $SERVER_IP $ADDARGS < $tmpfile 2>&1'
+ eval echo "$cmd"
+ out=$(eval "$cmd")
+ ret=$?
+ rm -f "$tmpfile"
+
+ if [ $ret != 0 ]; then
+ echo "$out"
+ echo "failed create x then chdir into X with error $ret"
+ return 1
+ fi
+
+ echo "$out" | grep 'NT_STATUS_'
+ ret="$?"
+ if [ "$ret" -eq 0 ]; then
+ echo "$out"
+ echo "Error create x then chdir into X"
+ return 1
+ fi
+ return 0
+}
+
+testit "creating a directory x and chdir into it" \
+ test_ci ||
+ failed=$((failed + 1))
+
+testok "$0" "$failed"
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 0901c24..0648797 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -1808,6 +1808,17 @@ plantestsuite("samba3.blackbox.smbclient-bug15435",
smbclient3,
configuration])
+plantestsuite("samba3.blackbox.widelink_dfs_ci",
+ "fileserver",
+ [os.path.join(samba3srcdir, "script/tests/test_widelink_dfs_ci.sh"),
+ "$SERVER",
+ "$SERVER_IP",
+ "msdfs-share-wl",
+ "$USERNAME",
+ "$PASSWORD",
+ "$PREFIX",
+ smbclient3])
+
if have_cluster_support:
t = "readdir-timestamp"
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index 6aad76a..42bb323 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -1312,6 +1312,24 @@ next:
}
if (fd == -1) {
+ /*
+ * vfs_widelink widelink_openat will update stat for fsp
+ * and return ELOOP for non-existing link, we can report
+ * the link here and let calling code decide what to do.
+ */
+ if ((errno == ELOOP) && S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+ status = create_open_symlink_err(mem_ctx,
+ dirfsp,
+ &rel_fname,
+ &symlink_err);
+ if (NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_STOPPED_ON_SYMLINK;
+ } else {
+ DBG_ERR("read_symlink_reparse failed: %s\n",
+ nt_errstr(status));
+ }
+ goto fail;
+ }
status = map_nt_error_from_unix(errno);
DBG_DEBUG("SMB_VFS_OPENAT() failed: %s\n",
strerror(errno));
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 4928d1f..a954499 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -522,6 +522,11 @@ struct smbXsrv_connection {
} smbtorture;
bool signing_mandatory;
+ /*
+ * This is ConstrainedConnection in MS-SMB2,
+ * but with reversed value...
+ */
+ bool got_authenticated_session;
} smb2;
};
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index afb86ab..5b83d4d 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -494,6 +494,17 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *xconn,
goto inval;
}
+ if (!xconn->smb2.got_authenticated_session) {
+ D_INFO("Got SMB2_TRANSFORM header, "
+ "but not no authenticated session yet "
+ "client[%s] server[%s]\n",
+ tsocket_address_string(
+ xconn->remote_address, talloc_tos()),
+ tsocket_address_string(
+ xconn->local_address, talloc_tos()));
+ goto inval;
+ }
+
if (len < SMB2_TF_HDR_SIZE) {
DEBUG(1, ("%d bytes left, expected at least %d\n",
(int)len, SMB2_TF_HDR_SIZE));
diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c
index ac71e55..d3b21ea 100644
--- a/source3/smbd/smb2_sesssetup.c
+++ b/source3/smbd/smb2_sesssetup.c
@@ -271,6 +271,13 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
x->global->signing_flags &= ~SMBXSRV_SIGNING_REQUIRED;
/* we map anonymous to guest internally */
guest = true;
+ } else {
+ /*
+ * Remember we got one authenticated session on the connection
+ * in order to allow SMB3 decryption to happen
+ * (sadly even for future anonymous connections).
+ */
+ xconn->smb2.got_authenticated_session = true;
}
if (guest && (x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED)) {
@@ -288,7 +295,10 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
}
x->global->signing_algo = xconn->smb2.server.sign_algo;
x->global->encryption_cipher = xconn->smb2.server.cipher;
- if (guest) {
+ if (*out_session_flags & SMB2_SESSION_FLAG_IS_GUEST) {
+ /*
+ * A fallback to guest can't do any encryption
+ */
x->global->encryption_cipher = SMB2_ENCRYPTION_NONE;
}
@@ -642,6 +652,12 @@ static NTSTATUS smbd_smb2_bind_auth_return(struct smbXsrv_session *session,
return NT_STATUS_LOGON_FAILURE;
}
+ /*
+ * Remember we got one authenticated session on the connection
+ * in order to allow SMB3 decryption to happen
+ */
+ xconn->smb2.got_authenticated_session = true;
+
*out_session_id = session->global->session_wire_id;
return NT_STATUS_OK;
diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c
index b228036..20d8967 100644
--- a/source3/smbd/smb2_tcon.c
+++ b/source3/smbd/smb2_tcon.c
@@ -331,6 +331,10 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
}
}
+ if (guest_session) {
+ /* make sure we don't ask for optional encryption */
+ encryption_desired = false;
+ }
if (encryption_desired) {
encryption_flags |= SMBXSRV_ENCRYPTION_DESIRED;
}
diff --git a/source3/utils/conn_tdb.c b/source3/utils/conn_tdb.c
index 3724bd4..3f4ef00 100644
--- a/source3/utils/conn_tdb.c
+++ b/source3/utils/conn_tdb.c
@@ -27,6 +27,7 @@
#include "conn_tdb.h"
#include "util_tdb.h"
#include "lib/util/string_wrappers.h"
+#include "../libcli/security/session.h"
struct connections_forall_state {
struct db_context *session_by_pid;
@@ -44,7 +45,7 @@ struct connections_forall_session {
uint16_t cipher;
uint16_t dialect;
uint16_t signing;
- uint8_t signing_flags;
+ bool authenticated;
};
static int collect_sessions_fn(struct smbXsrv_session_global0 *global,
@@ -56,6 +57,7 @@ static int collect_sessions_fn(struct smbXsrv_session_global0 *global,
uint32_t id = global->session_global_id;
struct connections_forall_session sess;
+ enum security_user_level ul;
if (global->auth_session_info == NULL) {
sess.uid = -1;
@@ -69,7 +71,12 @@ static int collect_sessions_fn(struct smbXsrv_session_global0 *global,
sess.cipher = global->channels[0].encryption_cipher;
sess.signing = global->channels[0].signing_algo;
sess.dialect = global->connection_dialect;
- sess.signing_flags = global->signing_flags;
+ ul = security_session_user_level(global->auth_session_info, NULL);
+ if (ul >= SECURITY_USER) {
+ sess.authenticated = true;
+ } else {
+ sess.authenticated = false;
+ }
status = dbwrap_store(state->session_by_pid,
make_tdb_data((void*)&id, sizeof(id)),
@@ -134,6 +141,7 @@ static int traverse_tcon_fn(struct smbXsrv_tcon_global0 *global,
data.dialect = sess.dialect;
data.signing = sess.signing;
data.signing_flags = global->signing_flags;
+ data.authenticated = sess.authenticated;
state->count++;
diff --git a/source3/utils/conn_tdb.h b/source3/utils/conn_tdb.h
index 2a6e04e..23a5e21 100644
--- a/source3/utils/conn_tdb.h
+++ b/source3/utils/conn_tdb.h
@@ -36,6 +36,7 @@ struct connections_data {
uint16_t dialect;
uint8_t signing_flags;
uint16_t signing;
+ bool authenticated;
};
/* The following definitions come from lib/conn_tdb.c */
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index d95a209..43fa026 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -521,6 +521,11 @@ static int net_ads_info_json(ADS_STRUCT *ads)
goto failure;
}
+ ret = json_add_string (&jsobj, "Workgroup", ads->config.workgroup);
+ if (ret != 0) {
+ goto failure;
+ }
+
ret = json_add_string (&jsobj, "Realm", ads->config.realm);
if (ret != 0) {
goto failure;
@@ -627,6 +632,7 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
d_printf(_("LDAP server: %s\n"), addr);
d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
+ d_printf(_("Workgroup: %s\n"), ads->config.workgroup);
d_printf(_("Realm: %s\n"), ads->config.realm);
d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
d_printf(_("LDAP port: %d\n"), ads->ldap.port);
diff --git a/source3/utils/net_registry.c b/source3/utils/net_registry.c
index 5d1314e..b47a8ff 100644
--- a/source3/utils/net_registry.c
+++ b/source3/utils/net_registry.c
@@ -1146,7 +1146,7 @@ static int registry_value_cmp(
if (v1->type == v2->type) {
return data_blob_cmp(&v1->data, &v2->data);
}
- return v1->type - v2->type;
+ return NUMERIC_CMP(v1->type, v2->type);
}
static WERROR precheck_create_val(struct precheck_ctx *ctx,
diff --git a/source3/utils/sharesec.c b/source3/utils/sharesec.c
index a6481e2..4175729 100644
--- a/source3/utils/sharesec.c
+++ b/source3/utils/sharesec.c
@@ -120,19 +120,19 @@ static int ace_compare(struct security_ace *ace1, struct security_ace *ace2)
return 0;
if (ace1->type != ace2->type)
- return ace2->type - ace1->type;
+ return NUMERIC_CMP(ace2->type, ace1->type);
if (dom_sid_compare(&ace1->trustee, &ace2->trustee))
return dom_sid_compare(&ace1->trustee, &ace2->trustee);
if (ace1->flags != ace2->flags)
- return ace1->flags - ace2->flags;
+ return NUMERIC_CMP(ace1->flags, ace2->flags);
if (ace1->access_mask != ace2->access_mask)
- return ace1->access_mask - ace2->access_mask;
+ return NUMERIC_CMP(ace1->access_mask, ace2->access_mask);
if (ace1->size != ace2->size)
- return ace1->size - ace2->size;
+ return NUMERIC_CMP(ace1->size, ace2->size);
return memcmp(ace1, ace2, sizeof(struct security_ace));
}
diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c
index e0591ac..5df7158 100644
--- a/source3/utils/smbcacls.c
+++ b/source3/utils/smbcacls.c
@@ -510,22 +510,23 @@ static int ace_compare(struct security_ace *ace1, struct security_ace *ace2)
return -1;
if ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) &&
(ace2->flags & SEC_ACE_FLAG_INHERITED_ACE))
- return ace1 - ace2;
-
- if (ace1->type != ace2->type)
- return ace2->type - ace1->type;
+ return NUMERIC_CMP(ace2->type, ace1->type);
+ if (ace1->type != ace2->type) {
+ /* note the reverse order */
+ return NUMERIC_CMP(ace2->type, ace1->type);
+ }
if (dom_sid_compare(&ace1->trustee, &ace2->trustee))
return dom_sid_compare(&ace1->trustee, &ace2->trustee);
if (ace1->flags != ace2->flags)
- return ace1->flags - ace2->flags;
+ return NUMERIC_CMP(ace1->flags, ace2->flags);
if (ace1->access_mask != ace2->access_mask)
- return ace1->access_mask - ace2->access_mask;
+ return NUMERIC_CMP(ace1->access_mask, ace2->access_mask);
if (ace1->size != ace2->size)
- return ace1->size - ace2->size;
+ return NUMERIC_CMP(ace1->size, ace2->size);
return memcmp(ace1, ace2, sizeof(struct security_ace));
}
diff --git a/source3/utils/status.c b/source3/utils/status.c
index 4102b41..02a5f6d 100644
--- a/source3/utils/status.c
+++ b/source3/utils/status.c
@@ -483,9 +483,33 @@ static int traverse_connections_stdout(struct traverse_state *state,
char *server_id,
const char *machine,
const char *timestr,
- const char *encryption,
- const char *signing)
+ const char *encryption_cipher,
+ enum crypto_degree encryption_degree,
+ const char *signing_cipher,
+ enum crypto_degree signing_degree)
{
+ fstring encryption;
+ fstring signing;
+
+ if (encryption_degree == CRYPTO_DEGREE_FULL) {
+ fstr_sprintf(encryption, "%s", encryption_cipher);
+ } else if (encryption_degree == CRYPTO_DEGREE_ANONYMOUS) {
+ fstr_sprintf(encryption, "anonymous(%s)", encryption_cipher);
+ } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
+ fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
+ } else {
+ fstr_sprintf(encryption, "-");
+ }
+ if (signing_degree == CRYPTO_DEGREE_FULL) {
+ fstr_sprintf(signing, "%s", signing_cipher);
+ } else if (signing_degree == CRYPTO_DEGREE_ANONYMOUS) {
+ fstr_sprintf(signing, "anonymous(%s)", signing_cipher);
+ } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
+ fstr_sprintf(signing, "partial(%s)", signing_cipher);
+ } else {
+ fstr_sprintf(signing, "-");
+ }
+
d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
servicename, server_id, machine, timestr, encryption, signing);
@@ -538,7 +562,9 @@ static int traverse_connections(const struct connections_data *crec,
return -1;
}
- if (smbXsrv_is_encrypted(crec->encryption_flags)) {
+ if (smbXsrv_is_encrypted(crec->encryption_flags) ||
+ smbXsrv_is_partially_encrypted(crec->encryption_flags))
+ {
switch (crec->cipher) {
case SMB_ENCRYPTION_GSSAPI:
encryption = "GSSAPI";
@@ -549,14 +575,31 @@ static int traverse_connections(const struct connections_data *crec,
case SMB2_ENCRYPTION_AES128_GCM:
encryption = "AES-128-GCM";
break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ encryption = "AES-256-CCM";
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ encryption = "AES-256-GCM";
+ break;
default:
encryption = "???";
break;
}
- encryption_degree = CRYPTO_DEGREE_FULL;
+ if (smbXsrv_is_encrypted(crec->encryption_flags)) {
+ encryption_degree = CRYPTO_DEGREE_FULL;
+ } else if (smbXsrv_is_partially_encrypted(crec->encryption_flags)) {
+ encryption_degree = CRYPTO_DEGREE_PARTIAL;
+ }
+ if (encryption_degree != CRYPTO_DEGREE_NONE &&
+ !crec->authenticated)
+ {
+ encryption_degree = CRYPTO_DEGREE_ANONYMOUS;
+ }
}
- if (smbXsrv_is_signed(crec->signing_flags)) {
+ if (smbXsrv_is_signed(crec->signing_flags) ||
+ smbXsrv_is_partially_signed(crec->signing_flags))
+ {
switch (crec->signing) {
case SMB2_SIGNING_MD5_SMB1:
signing = "HMAC-MD5";
@@ -574,7 +617,16 @@ static int traverse_connections(const struct connections_data *crec,
signing = "???";
break;
}
- signing_degree = CRYPTO_DEGREE_FULL;
+ if (smbXsrv_is_signed(crec->signing_flags)) {
+ signing_degree = CRYPTO_DEGREE_FULL;
+ } else if (smbXsrv_is_partially_signed(crec->signing_flags)) {
+ signing_degree = CRYPTO_DEGREE_PARTIAL;
+ }
+ if (signing_degree != CRYPTO_DEGREE_NONE &&
+ !crec->authenticated)
+ {
+ signing_degree = CRYPTO_DEGREE_ANONYMOUS;
+ }
}
if (!state->json_output) {
@@ -584,7 +636,9 @@ static int traverse_connections(const struct connections_data *crec,
crec->machine,
timestr,
encryption,
- signing);
+ encryption_degree,
+ signing,
+ signing_degree);
} else {
result = traverse_connections_json(state,
crec,
@@ -615,6 +669,8 @@ static int traverse_sessionid_stdout(struct traverse_state *state,
if (encryption_degree == CRYPTO_DEGREE_FULL) {
fstr_sprintf(encryption, "%s", encryption_cipher);
+ } else if (encryption_degree == CRYPTO_DEGREE_ANONYMOUS) {
+ fstr_sprintf(encryption, "anonymous(%s)", encryption_cipher);
} else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
} else {
@@ -622,6 +678,8 @@ static int traverse_sessionid_stdout(struct traverse_state *state,
}
if (signing_degree == CRYPTO_DEGREE_FULL) {
fstr_sprintf(signing, "%s", signing_cipher);
+ } else if (signing_degree == CRYPTO_DEGREE_ANONYMOUS) {
+ fstr_sprintf(signing, "anonymous(%s)", signing_cipher);
} else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
fstr_sprintf(signing, "partial(%s)", signing_cipher);
} else {
@@ -756,6 +814,11 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
} else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
encryption_degree = CRYPTO_DEGREE_PARTIAL;
}
+ if (encryption_degree != CRYPTO_DEGREE_NONE &&
+ !session->authenticated)
+ {
+ encryption_degree = CRYPTO_DEGREE_ANONYMOUS;
+ }
}
if (smbXsrv_is_signed(session->signing_flags) ||
@@ -783,6 +846,11 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
} else if (smbXsrv_is_partially_signed(session->signing_flags)) {
signing_degree = CRYPTO_DEGREE_PARTIAL;
}
+ if (signing_degree != CRYPTO_DEGREE_NONE &&
+ !session->authenticated)
+ {
+ signing_degree = CRYPTO_DEGREE_ANONYMOUS;
+ }
}
diff --git a/source3/utils/status.h b/source3/utils/status.h
index c08aba4..6674f0d 100644
--- a/source3/utils/status.h
+++ b/source3/utils/status.h
@@ -38,6 +38,7 @@ struct traverse_state {
enum crypto_degree {
CRYPTO_DEGREE_NONE,
CRYPTO_DEGREE_PARTIAL,
+ CRYPTO_DEGREE_ANONYMOUS,
CRYPTO_DEGREE_FULL
};
diff --git a/source3/utils/status_json.c b/source3/utils/status_json.c
index ee24a3b..f558c91 100644
--- a/source3/utils/status_json.c
+++ b/source3/utils/status_json.c
@@ -258,6 +258,8 @@ static int add_crypto_to_json(struct json_object *parent_json,
if (degree == CRYPTO_DEGREE_NONE) {
degree_str = "none";
+ } else if (degree == CRYPTO_DEGREE_ANONYMOUS) {
+ degree_str = "anonymous";
} else if (degree == CRYPTO_DEGREE_PARTIAL) {
degree_str = "partial";
} else {
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index 5c9fe07..b800282 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -320,7 +320,10 @@ static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
struct tldap_context **pld)
{
struct netr_DsRGetDCNameInfo *dcinfo;
- struct sockaddr_storage dcaddr;
+ struct sockaddr_storage dcaddr = {
+ .ss_family = AF_UNSPEC,
+ };
+ struct sockaddr_storage *pdcaddr = NULL;
struct cli_credentials *creds;
struct loadparm_context *lp_ctx;
struct tldap_context *ld;
@@ -362,9 +365,13 @@ static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
* create_local_private_krb5_conf_for_domain() can deal with
* sitename==NULL
*/
+ if (strequal(domname, lp_realm()) || strequal(domname, lp_workgroup()))
+ {
+ pdcaddr = &dcaddr;
+ }
ok = create_local_private_krb5_conf_for_domain(
- lp_realm(), lp_workgroup(), sitename, &dcaddr);
+ lp_realm(), lp_workgroup(), sitename, pdcaddr);
TALLOC_FREE(sitename);
if (!ok) {
DBG_DEBUG("Could not create private krb5.conf\n");
diff --git a/source3/wscript_build b/source3/wscript_build
index ff8de1e..3fcdb55 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -901,6 +901,7 @@ bld.SAMBA3_SUBSYSTEM('LIBNMB',
LIBTSOCKET
LIBCLI_NETLOGON
samba3util
+ smbconf
addns
lmhosts
resolv
diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c
index be79a4e..d30e971 100644
--- a/source4/dns_server/dns_crypto.c
+++ b/source4/dns_server/dns_crypto.c
@@ -27,6 +27,7 @@
#include "libcli/util/ntstatus.h"
#include "auth/auth.h"
#include "auth/gensec/gensec.h"
+#include "lib/util/bytearray.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_DNS
@@ -106,7 +107,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
struct dns_server_tkey *tkey = NULL;
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
-
+ const char *algorithm = NULL;
/* Find the first TSIG record in the additional records */
for (i=0; i < packet->arcount; i++) {
@@ -145,7 +146,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
tkey = dns_find_tkey(dns->tkeys, state->tsig->name);
if (tkey == NULL) {
- DBG_DEBUG("dns_find_tkey() => NOTAUTH / DNS_RCODE_BADKEY\n");
+ DBG_DEBUG("dns_find_tkey() => REFUSED / DNS_RCODE_BADKEY\n");
/*
* We must save the name for use in the TSIG error
* response and have no choice here but to save the
@@ -157,10 +158,20 @@ WERROR dns_verify_tsig(struct dns_server *dns,
return WERR_NOT_ENOUGH_MEMORY;
}
state->tsig_error = DNS_RCODE_BADKEY;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
DBG_DEBUG("dns_find_tkey() => found\n");
+ algorithm = state->tsig->rdata.tsig_record.algorithm_name;
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ state->tsig_error = DNS_RCODE_BADKEY;
+ return DNS_ERR(REFUSED);
+ }
+
/*
* Remember the keyname that found an existing tkey, used
* later to fetch the key with dns_find_tkey() when signing
@@ -183,7 +194,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
}
check_rec->rr_class = DNS_QCLASS_ANY;
check_rec->ttl = 0;
- check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm);
+ check_rec->algorithm_name = talloc_strdup(check_rec, algorithm);
if (check_rec->algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
@@ -239,7 +250,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
dump_data_dbgc(DBGC_DNS, 8, buffer, buffer_len);
DBG_NOTICE("Verifying tsig failed: %s\n", nt_errstr(status));
state->tsig_error = DNS_RCODE_BADSIG;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
if (!NT_STATUS_IS_OK(status)) {
@@ -271,11 +282,19 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
size_t mac_size = 0;
+ bool gss_tsig;
if (check_rec == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
+ if (strcmp(tkey->algorithm, "gss-tsig") == 0) {
+ gss_tsig = true;
+ } else {
+ /* gss.microsoft.com */
+ gss_tsig = false;
+ }
+
/* first build and verify check packet */
check_rec->name = talloc_strdup(check_rec, tkey->name);
if (check_rec->name == NULL) {
@@ -315,6 +334,9 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
}
buffer_len = mac_size;
+ if (gss_tsig && mac_size > 0) {
+ buffer_len += 2;
+ }
buffer_len += packet_blob.length;
if (buffer_len < packet_blob.length) {
@@ -335,11 +357,21 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
/*
* RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer
* that we're going to sign:
- * 1. MAC of request (if present)
+ * 1. if MAC of request is present
+ * - 16bit big endian length of MAC of request
+ * - MAC of request
* 2. Outgoing packet
* 3. TSIG record
*/
if (mac_size > 0) {
+ if (gss_tsig) {
+ /*
+ * only gss-tsig not with
+ * gss.microsoft.com
+ */
+ PUSH_BE_U16(p, 0, mac_size);
+ p += 2;
+ }
memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size);
p += mac_size;
}
@@ -372,6 +404,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
.data = NULL,
.length = 0
};
+ const char *algorithm = "gss-tsig";
tsig = talloc_zero(mem_ctx, struct dns_res_rec);
if (tsig == NULL) {
@@ -392,6 +425,8 @@ WERROR dns_sign_tsig(struct dns_server *dns,
if (!W_ERROR_IS_OK(werror)) {
return werror;
}
+
+ algorithm = tkey->algorithm;
}
tsig->name = talloc_strdup(tsig, state->key_name);
@@ -402,7 +437,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
tsig->rr_type = DNS_QTYPE_TSIG;
tsig->ttl = 0;
tsig->length = UINT16_MAX;
- tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig");
+ tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, algorithm);
if (tsig->rdata.tsig_record.algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 181beda..1f46ee0 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -663,8 +663,17 @@ static NTSTATUS create_tkey(struct dns_server *dns,
{
NTSTATUS status;
struct dns_server_tkey_store *store = dns->tkeys;
- struct dns_server_tkey *k = talloc_zero(store, struct dns_server_tkey);
+ struct dns_server_tkey *k = NULL;
+
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ k = talloc_zero(store, struct dns_server_tkey);
if (k == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -790,12 +799,22 @@ static WERROR handle_tkey(struct dns_server *dns,
{
struct dns_res_rec *in_tkey = NULL;
struct dns_res_rec *ret_tkey;
- uint16_t i;
- for (i = 0; i < in->arcount; i++) {
+ /*
+ * TKEY needs to we the last one in
+ * additional or answers
+ */
+ if (in->arcount >= 1) {
+ uint16_t i = in->arcount - 1;
if (in->additional[i].rr_type == DNS_QTYPE_TKEY) {
in_tkey = &in->additional[i];
- break;
+ }
+ } else if (in->nscount >= 1) {
+ /* no lookup */
+ } else if (in->ancount >= 1) {
+ uint16_t i = in->ancount - 1;
+ if (in->answers[i].rr_type == DNS_QTYPE_TKEY) {
+ in_tkey = &in->answers[i];
}
}
diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c
index 4d2ee0b..1285111 100644
--- a/source4/dns_server/dns_update.c
+++ b/source4/dns_server/dns_update.c
@@ -570,6 +570,8 @@ static WERROR handle_one_update(struct dns_server *dns,
W_ERROR_NOT_OK_RETURN(werror);
for (i = first; i < rcount; i++) {
+ struct dnsp_DnssrvRpcRecord orig_rec = recs[i];
+
if (!dns_record_match(&recs[i], &recs[rcount])) {
continue;
}
@@ -583,6 +585,15 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_replace_records(dns, mem_ctx, dn,
needs_add, recs, rcount);
DBG_DEBUG("dns_replace_records(REPLACE): %s\n", win_errstr(werror));
+ if (W_ERROR_EQUAL(werror, WERR_ACCESS_DENIED) &&
+ !needs_add &&
+ orig_rec.dwTtlSeconds == recs[i].dwTtlSeconds)
+ {
+ DBG_NOTICE("dns_replace_records(REPLACE): %s "
+ "=> skip no-op\n",
+ win_errstr(werror));
+ werror = WERR_OK;
+ }
W_ERROR_NOT_OK_RETURN(werror);
return WERR_OK;
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index aba7f41..88aed2e 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -68,6 +68,8 @@ uint8_t werr_to_dns_err(WERROR werr)
return DNS_RCODE_NOTZONE;
} else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
return DNS_RCODE_BADKEY;
+ } else if (W_ERROR_EQUAL(WERR_ACCESS_DENIED, werr)) {
+ return DNS_RCODE_REFUSED;
}
DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
return DNS_RCODE_SERVFAIL;
@@ -642,7 +644,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* The records are sorted with higher types first,
* which puts tombstones (type 0) last.
*/
- return r2->wType - r1->wType;
+ return NUMERIC_CMP(r2->wType, r1->wType);
}
/*
* Then we need to sort from the oldest to newest timestamp.
@@ -650,7 +652,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* Note that dwTimeStamp == 0 (never expiring) records come first,
* then the ones whose expiry is soonest.
*/
- return r1->dwTimeStamp - r2->dwTimeStamp;
+ return NUMERIC_CMP(r1->dwTimeStamp, r2->dwTimeStamp);
}
/*
@@ -1408,7 +1410,7 @@ static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m
/* If the string lengths are not equal just sort by length */
if (l1 != l2) {
/* If m1 is the larger zone name, return it first */
- return l2 - l1;
+ return NUMERIC_CMP(l2, l1);
}
/*TODO: We need to compare DNs here, we want the DomainDNSZones first */
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index d46b19e..7ba5c79 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -1043,7 +1043,7 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
if (W_ERROR_EQUAL(status, WERR_DS_DRA_SCHEMA_MISMATCH)) {
struct dreplsrv_partition *p;
- bool ok;
+ struct tevent_req *subreq = NULL;
if (was_schema) {
nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
@@ -1141,12 +1141,15 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
state->retry_started = true;
- ok = dreplsrv_op_pull_source_detect_schema_cycle(req);
- if (!ok) {
+ subreq = dreplsrv_out_drsuapi_send(state,
+ state->ev,
+ state->op->source_dsa->conn);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
-
- dreplsrv_op_pull_source_get_changes_trigger(req);
+ tevent_req_set_callback(subreq,
+ dreplsrv_op_pull_source_connect_done,
+ req);
return;
} else if (!W_ERROR_IS_OK(status)) {
@@ -1205,10 +1208,21 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
* operation once we are done.
*/
if (state->source_dsa_retry != NULL) {
+ struct tevent_req *subreq = NULL;
+
state->op->source_dsa = state->source_dsa_retry;
state->op->extended_op = state->extended_op_retry;
state->source_dsa_retry = NULL;
- dreplsrv_op_pull_source_get_changes_trigger(req);
+
+ subreq = dreplsrv_out_drsuapi_send(state,
+ state->ev,
+ state->op->source_dsa->conn);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ dreplsrv_op_pull_source_connect_done,
+ req);
return;
}
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 1317b58..20613a7 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -1070,7 +1070,7 @@ static int pso_compare(struct ldb_message **m1, struct ldb_message **m2)
return ndr_guid_compare(&guid1, &guid2);
} else {
- return prec1 - prec2;
+ return NUMERIC_CMP(prec1, prec2);
}
}
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 7aec006..2790679 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1063,16 +1063,21 @@ static int replmd_ldb_message_element_attid_sort(const struct ldb_message_elemen
a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
/*
- * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
- * in the schema
+ * If the elements do not have valid attribute names in the schema
+ * (which we would prefer to think can't happen), we need to sort them
+ * somehow. The current strategy is to put them at the end, sorted by
+ * attribute name.
*/
- if (!a1 || !a2) {
+ if (a1 == NULL && a2 == NULL) {
return strcasecmp(e1->name, e2->name);
}
- if (a1->attributeID_id == a2->attributeID_id) {
- return 0;
+ if (a1 == NULL) {
+ return 1;
+ }
+ if (a2 == NULL) {
+ return -1;
}
- return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
+ return NUMERIC_CMP(a1->attributeID_id, a2->attributeID_id);
}
static void replmd_ldb_message_sort(struct ldb_message *msg,
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
index 398091c..8b90e7f 100644
--- a/source4/dsdb/schema/schema_set.c
+++ b/source4/dsdb/schema/schema_set.c
@@ -478,19 +478,13 @@ static void dsdb_setup_attribute_shortcuts(struct ldb_context *ldb, struct dsdb_
TALLOC_FREE(frame);
}
-static int uint32_cmp(uint32_t c1, uint32_t c2)
-{
- if (c1 == c2) return 0;
- return c1 > c2 ? 1 : -1;
-}
-
static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
{
return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
}
static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
{
- return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
+ return NUMERIC_CMP((*c1)->governsID_id, (*c2)->governsID_id);
}
static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
{
@@ -507,11 +501,11 @@ static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
+ return NUMERIC_CMP((*a1)->attributeID_id, (*a2)->attributeID_id);
}
static int dsdb_compare_attribute_by_msDS_IntId(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->msDS_IntId, (*a2)->msDS_IntId);
+ return NUMERIC_CMP((*a1)->msDS_IntId, (*a2)->msDS_IntId);
}
static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
@@ -519,7 +513,7 @@ static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->linkID, (*a2)->linkID);
+ return NUMERIC_CMP((*a1)->linkID, (*a2)->linkID);
}
static int dsdb_compare_attribute_by_cn(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
diff --git a/source4/libcli/dgram/dgramsocket.c b/source4/libcli/dgram/dgramsocket.c
index 154a667..2a98792 100644
--- a/source4/libcli/dgram/dgramsocket.c
+++ b/source4/libcli/dgram/dgramsocket.c
@@ -90,6 +90,10 @@ static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
dgmslot->handler(dgmslot, packet, src);
} else {
DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
+ /* dispatch if there is a general handler */
+ if (dgmsock->incoming.handler) {
+ dgmsock->incoming.handler(dgmsock, packet, src);
+ }
}
} else {
/* dispatch if there is a general handler */
@@ -205,6 +209,38 @@ NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
return NT_STATUS_OK;
}
+NTSTATUS nbt_dgram_send_raw(struct nbt_dgram_socket *dgmsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob)
+{
+ struct nbt_dgram_request *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ req = talloc(dgmsock, struct nbt_dgram_request);
+ if (req == NULL) {
+ goto failed;
+ }
+
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) {
+ goto failed;
+ }
+
+ req->encoded = data_blob_dup_talloc(req, pkt_blob);
+ if (req->encoded.length != pkt_blob.length) {
+ goto failed;
+ }
+
+ DLIST_ADD_END(dgmsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(dgmsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return status;
+}
/*
queue a datagram for send
@@ -220,8 +256,8 @@ NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
req = talloc(dgmsock, struct nbt_dgram_request);
if (req == NULL) goto failed;
- req->dest = dest;
- if (talloc_reference(req, dest) == NULL) goto failed;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
ndr_err = ndr_push_struct_blob(&req->encoded, req, packet,
(ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h
index 0f313a6..7e57a94 100644
--- a/source4/libcli/dgram/libdgram.h
+++ b/source4/libcli/dgram/libdgram.h
@@ -83,6 +83,9 @@ struct dgram_mailslot_handler {
/* prototypes */
+NTSTATUS nbt_dgram_send_raw(struct nbt_dgram_socket *dgmsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob);
NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
struct nbt_dgram_packet *packet,
struct socket_address *dest);
diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index e94512d..322a7bd 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -385,7 +385,9 @@ static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
return;
}
- if (cli_credentials_is_anonymous(state->credentials)) {
+ if (cli_credentials_is_anonymous(state->credentials) &&
+ !state->session->anonymous_session_key)
+ {
/*
* Windows server does not set the
* SMB2_SESSION_FLAG_IS_GUEST nor
@@ -399,10 +401,14 @@ static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
return;
}
- status = gensec_session_key(session->gensec, state,
- &session_key);
- if (tevent_req_nterror(req, status)) {
- return;
+ if (state->session->forced_session_key.length != 0) {
+ session_key = state->session->forced_session_key;
+ } else {
+ status = gensec_session_key(session->gensec, state,
+ &session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
}
if (state->session_bind) {
diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h
index 88e651a..1e2f185 100644
--- a/source4/libcli/smb2/smb2.h
+++ b/source4/libcli/smb2/smb2.h
@@ -128,6 +128,8 @@ struct smb2_session {
struct gensec_security *gensec;
struct smbXcli_session *smbXcli;
bool needs_bind;
+ bool anonymous_session_key;
+ DATA_BLOB forced_session_key;
};
diff --git a/source4/nbt_server/dgram/request.c b/source4/nbt_server/dgram/request.c
index ea2b6e8..7614514 100644
--- a/source4/nbt_server/dgram/request.c
+++ b/source4/nbt_server/dgram/request.c
@@ -27,6 +27,11 @@
#include "nbt_server/dgram/proto.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "param/param.h"
+#include "lib/util/util_str_escape.h"
+#include "lib/util/util_net.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
/*
a list of mailslots that we have static handlers for
@@ -51,8 +56,55 @@ void dgram_request_handler(struct nbt_dgram_socket *dgmsock,
struct nbt_dgram_packet *packet,
struct socket_address *src)
{
- DEBUG(0,("General datagram request from %s:%d\n", src->addr, src->port));
- NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+ struct nbtd_interface *iface =
+ talloc_get_type_abort(dgmsock->incoming.private_data,
+ struct nbtd_interface);
+ struct nbtd_server *nbtsrv = iface->nbtsrv;
+ const char *mailslot_name = NULL;
+ struct packet_struct *pstruct = NULL;
+ DATA_BLOB blob = { .length = 0, };
+ enum ndr_err_code ndr_err;
+
+ mailslot_name = dgram_mailslot_name(packet);
+ if (mailslot_name != NULL) {
+ DBG_DEBUG("Unexpected mailslot[%s] datagram request from %s:%d\n",
+ log_escape(packet, mailslot_name),
+ src->addr, src->port);
+ } else {
+ DBG_DEBUG("Unexpected general datagram request from %s:%d\n",
+ src->addr, src->port);
+ }
+
+ if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+ NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+ }
+
+ /*
+ * For now we only pass DGRAM_DIRECT_UNIQUE
+ * messages via nb_packet_dispatch() to
+ * nbtsrv->unexpected_server
+ */
+ if (packet->msg_type != DGRAM_DIRECT_UNIQUE) {
+ return;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, packet, packet,
+ (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_push_nbt_dgram_packet - %s\n",
+ ndr_errstr(ndr_err));
+ return;
+ }
+
+ pstruct = parse_packet((char *)blob.data,
+ blob.length,
+ DGRAM_PACKET,
+ interpret_addr2(src->addr),
+ src->port);
+ if (pstruct != NULL) {
+ nb_packet_dispatch(nbtsrv->unexpected_server, pstruct);
+ free_packet(pstruct);
+ }
}
diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c
index b946a1d..0888c1b 100644
--- a/source4/nbt_server/interfaces.c
+++ b/source4/nbt_server/interfaces.c
@@ -31,6 +31,9 @@
#include "param/param.h"
#include "lib/util/util_net.h"
#include "lib/util/idtree.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
/*
receive an incoming request and dispatch it to the right place
@@ -115,7 +118,33 @@ static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
}
if (!req) {
+ struct packet_struct *pstruct = NULL;
+ DATA_BLOB blob = { .length = 0, };
+ enum ndr_err_code ndr_err;
+
+ /*
+ * Here we have NBT_FLAG_REPLY
+ */
DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
+
+ ndr_err = ndr_push_struct_blob(&blob, packet, packet,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_push_nbt_name_packet - %s\n",
+ ndr_errstr(ndr_err));
+ return;
+ }
+
+ pstruct = parse_packet((char *)blob.data,
+ blob.length,
+ NMB_PACKET,
+ interpret_addr2(src->addr),
+ src->port);
+ if (pstruct != NULL) {
+ nb_packet_dispatch(nbtsrv->unexpected_server, pstruct);
+ free_packet(pstruct);
+ }
+
return;
}
diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c
index 6d28bbd..c3f9fac 100644
--- a/source4/nbt_server/nbt_server.c
+++ b/source4/nbt_server/nbt_server.c
@@ -29,9 +29,113 @@
#include "auth/auth.h"
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
+#include "dynconfig/dynconfig.h"
+#include "lib/util/pidfile.h"
+#include "lib/util/util_net.h"
+#include "lib/socket/socket.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
+#include "../source3/lib/util_procid.h"
NTSTATUS server_service_nbtd_init(TALLOC_CTX *);
+static void nbtd_server_msg_send_packet(struct imessaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ size_t num_fds,
+ int *fds,
+ DATA_BLOB *data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct nbtd_server *nbtsrv =
+ talloc_get_type_abort(private_data,
+ struct nbtd_server);
+ struct packet_struct *p = (struct packet_struct *)data->data;
+ struct sockaddr_storage ss;
+ struct socket_address *dst = NULL;
+ struct nbtd_interface *iface = NULL;
+ char buf[1024] = { 0, };
+ DATA_BLOB blob = { .length = 0, };
+
+ DBG_DEBUG("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src));
+
+ if (data->length != sizeof(struct packet_struct)) {
+ DBG_WARNING("Discarding invalid packet length from %u\n",
+ (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ if ((p->packet_type != NMB_PACKET) &&
+ (p->packet_type != DGRAM_PACKET)) {
+ DBG_WARNING("Discarding invalid packet type from %u: %d\n",
+ (unsigned int)procid_to_pid(&src), p->packet_type);
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->port = 138;
+ }
+
+ in_addr_to_sockaddr_storage(&ss, p->ip);
+ dst = socket_address_from_sockaddr_storage(frame, &ss, p->port);
+ if (dst == NULL) {
+ TALLOC_FREE(frame);
+ return;
+ }
+ if (p->port == 0) {
+ DBG_WARNING("Discarding packet with missing port for addr[%s] "
+ "from %u\n",
+ dst->addr, (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ iface = nbtd_find_request_iface(nbtsrv, dst->addr, true);
+ if (iface == NULL) {
+ DBG_WARNING("Could not find iface for packet to addr[%s] "
+ "from %u\n",
+ dst->addr, (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ p->recv_fd = -1;
+ p->send_fd = -1;
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->packet.dgram.header.source_ip.s_addr = interpret_addr(iface->ip_address);
+ p->packet.dgram.header.source_port = 138;
+ }
+
+ blob.length = build_packet(buf, sizeof(buf), p);
+ if (blob.length == 0) {
+ TALLOC_FREE(frame);
+ return;
+ }
+ blob.data = (uint8_t *)buf;
+
+ if (p->packet_type == DGRAM_PACKET) {
+ nbt_dgram_send_raw(iface->dgmsock, dst, blob);
+ } else {
+ nbt_name_send_raw(iface->nbtsock, dst, blob);
+ }
+
+ TALLOC_FREE(frame);
+}
+
+static int nbtd_server_destructor(struct nbtd_server *nbtsrv)
+{
+ struct task_server *task = nbtsrv->task;
+
+ pidfile_unlink(lpcfg_pid_directory(task->lp_ctx), "nmbd");
+
+ return 0;
+}
+
/*
startup the nbtd task
*/
@@ -40,6 +144,8 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
struct nbtd_server *nbtsrv;
NTSTATUS status;
struct interface *ifaces;
+ const char *nmbd_socket_dir = NULL;
+ int unexpected_clients;
load_interface_list(task, task->lp_ctx, &ifaces);
@@ -66,6 +172,8 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
nbtsrv->bcast_interface = NULL;
nbtsrv->wins_interface = NULL;
+ talloc_set_destructor(nbtsrv, nbtd_server_destructor);
+
/* start listening on the configured network interfaces */
status = nbtd_startup_interfaces(nbtsrv, task->lp_ctx, ifaces);
if (!NT_STATUS_IS_OK(status)) {
@@ -73,6 +181,30 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
return status;
}
+ nmbd_socket_dir = lpcfg_parm_string(task->lp_ctx,
+ NULL,
+ "nmbd",
+ "socket dir");
+ if (nmbd_socket_dir == NULL) {
+ nmbd_socket_dir = get_dyn_NMBDSOCKETDIR();
+ }
+
+ unexpected_clients = lpcfg_parm_int(task->lp_ctx,
+ NULL,
+ "nmbd",
+ "unexpected_clients",
+ 200);
+
+ status = nb_packet_server_create(nbtsrv,
+ nbtsrv->task->event_ctx,
+ nmbd_socket_dir,
+ unexpected_clients,
+ &nbtsrv->unexpected_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ task_server_terminate(task, "nbtd failed to start unexpected_server", true);
+ return status;
+ }
+
nbtsrv->sam_ctx = samdb_connect(nbtsrv,
task->event_ctx,
task->lp_ctx,
@@ -93,11 +225,22 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
nbtd_register_irpc(nbtsrv);
+ status = imessaging_register(task->msg_ctx,
+ nbtsrv,
+ MSG_SEND_PACKET,
+ nbtd_server_msg_send_packet);
+ if (!NT_STATUS_IS_OK(status)) {
+ task_server_terminate(task, "nbtd failed imessaging_register(MSG_SEND_PACKET)", true);
+ return status;
+ }
+
/* start the process of registering our names on all interfaces */
nbtd_register_names(nbtsrv);
irpc_add_name(task->msg_ctx, "nbt_server");
+ pidfile_create(lpcfg_pid_directory(task->lp_ctx), "nmbd");
+
return NT_STATUS_OK;
}
diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h
index c80e5bf..cbad3e9 100644
--- a/source4/nbt_server/nbt_server.h
+++ b/source4/nbt_server/nbt_server.h
@@ -78,6 +78,8 @@ struct nbtd_server {
struct nbtd_statistics stats;
struct ldb_context *sam_ctx;
+
+ struct nb_packet_server *unexpected_server;
};
diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c
index 2a05e96..7df40c3 100644
--- a/source4/nbt_server/wins/winsdb.c
+++ b/source4/nbt_server/wins/winsdb.c
@@ -32,6 +32,7 @@
#include "lib/socket/netif.h"
#include "param/param.h"
#include "lib/util/smb_strtox.h"
+#include "lib/util/tsort.h"
#undef strcasecmp
@@ -349,7 +350,7 @@ static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **
* then the replica addresses with the newest to the oldest address
*/
if (a2->expire_time != a1->expire_time) {
- return a2->expire_time - a1->expire_time;
+ return NUMERIC_CMP(a2->expire_time, a1->expire_time);
}
if (strcmp(a2->wins_owner, h->local_owner) == 0) {
@@ -360,7 +361,7 @@ static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **
a1_owned = true;
}
- return a2_owned - a1_owned;
+ return NUMERIC_CMP(a2_owned, a1_owned);
}
struct winsdb_addr **winsdb_addr_list_add(struct winsdb_handle *h, const struct winsdb_record *rec,
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index a9f3ecd..6679961 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -36,6 +36,7 @@
#include "param/param.h"
#include "libcli/resolve/resolve.h"
#include "lib/util/util_net.h"
+#include "lib/util/tsort.h"
/*
work out the ttl we will use given a client requested ttl
@@ -653,7 +654,7 @@ static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
- return match_bits2 - match_bits1;
+ return NUMERIC_CMP(match_bits2, match_bits1);
}
static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
diff --git a/source4/nbt_server/wscript_build b/source4/nbt_server/wscript_build
index 9d0c24a..ce436e8 100644
--- a/source4/nbt_server/wscript_build
+++ b/source4/nbt_server/wscript_build
@@ -38,7 +38,7 @@ bld.SAMBA_SUBSYSTEM('NBTD_DGRAM',
bld.SAMBA_SUBSYSTEM('NBT_SERVER',
source='interfaces.c register.c query.c nodestatus.c defense.c packet.c irpc.c',
autoproto='nbt_server_proto.h',
- deps='cli-nbt NBTD_WINS NBTD_DGRAM service',
+ deps='cli-nbt NBTD_WINS NBTD_DGRAM service LIBNMB',
enabled=bld.AD_DC_BUILD_IS_ENABLED()
)
diff --git a/source4/ntvfs/posix/pvfs_streams.c b/source4/ntvfs/posix/pvfs_streams.c
index 9210237..d2d5eed 100644
--- a/source4/ntvfs/posix/pvfs_streams.c
+++ b/source4/ntvfs/posix/pvfs_streams.c
@@ -22,6 +22,7 @@
#include "includes.h"
#include "vfs_posix.h"
#include "librpc/gen_ndr/xattr.h"
+#include "lib/util/tsort.h"
/*
normalise a stream name, removing a :$DATA suffix if there is one
@@ -51,7 +52,7 @@ static int stream_name_cmp(const char *name1, const char *name2)
l1 = c1?(c1 - name1):strlen(name1);
l2 = c2?(c2 - name2):strlen(name2);
if (l1 != l2) {
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
ret = strncasecmp_m(name1, name2, l1);
if (ret != 0) {
diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c
index e6d35fc..6ffca19 100644
--- a/source4/rpc_server/dnsserver/dnsdata.c
+++ b/source4/rpc_server/dnsserver/dnsdata.c
@@ -1075,9 +1075,23 @@ int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const
name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
- if (name1 == NULL || name2 == NULL) {
+ /*
+ * We sort NULL names to the start of the list, because the only
+ * caller of this function, dnsserver_enumerate_records() will call
+ * dns_build_tree() with the sorted list, which will always return an
+ * error when it hits a NULL, so we might as well make that happen
+ * quickly.
+ */
+ if (name1 == name2) {
+ /* this includes the both NULL case */
return 0;
}
+ if (name1 == NULL) {
+ return -1;
+ }
+ if (name2 == NULL) {
+ return 1;
+ }
/* Compare the last components of names.
* If search_name is not NULL, compare the second last components of names */
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index 841c764..66a7785 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -1166,7 +1166,7 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call
*/
static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
{
- return e1->idx - e2->idx;
+ return NUMERIC_CMP(e1->idx, e2->idx);
}
static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
@@ -1197,8 +1197,9 @@ static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
}
/*
- * Get and compare the rids, if we fail to extract a rid treat it as a
- * missing SID and sort to the end of the list
+ * Get and compare the rids. If we fail to extract a rid (because
+ * there are no subauths) the msg goes to the end of the list, but
+ * before the NULL SIDs.
*/
status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index d70d7d5..e47eb57 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -531,7 +531,11 @@ plantestsuite_loadlist("samba.tests.dns_aging", "fl2003dc:local",
plantestsuite_loadlist("samba.tests.dns_forwarder", "fl2003dc:local", [python, os.path.join(srcdir(), "python/samba/tests/dns_forwarder.py"), '$SERVER', '$SERVER_IP', '$DNS_FORWARDER1', '$DNS_FORWARDER2', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
-plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
+plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc",
+ ['USERNAME_UNPRIV=$DOMAIN_USER','PASSWORD_UNPRIV=$DOMAIN_USER_PASSWORD',
+ python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"),
+ '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"',
+ '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba.tests.dns_wildcard", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_wildcard.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba.tests.dns_invalid", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_invalid.py"), '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
@@ -817,6 +821,11 @@ plantestsuite("samba4.blackbox.trust_ntlm", "fl2000dc:local", [os.path.join(bbdi
plantestsuite("samba4.blackbox.trust_ntlm", "ad_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
plantestsuite("samba4.blackbox.trust_ntlm", "nt4_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$DOMAIN', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2008r2dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2003dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2000dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "ad_member:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+
plantestsuite("samba4.blackbox.trust_utils(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
plantestsuite("samba4.blackbox.trust_utils(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
plantestsuite("samba4.blackbox.trust_utils(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
@@ -1477,6 +1486,9 @@ planoldpythontestsuite("fileserver",
"samba.tests.blackbox.smbcacls_dfs_propagate_inherit",
"samba.tests.blackbox.smbcacls_dfs_propagate_inherit(DFS-msdfs-root)",
environ={'SHARE': 'smbcacls_share'})
+
+planoldpythontestsuite("fileserver",
+ "samba.tests.blackbox.misc_dfs_widelink")
#
# Want a selection of environments across the process models
#
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
index 3765dc0..beceaa5 100644
--- a/source4/torture/smb2/ioctl.c
+++ b/source4/torture/smb2/ioctl.c
@@ -7389,6 +7389,68 @@ static bool test_ioctl_bug14788_NETWORK_INTERFACE(struct torture_context *tortur
}
/*
+ * basic regression test for BUG 15664
+ * https://bugzilla.samba.org/show_bug.cgi?id=15664
+ */
+static bool test_ioctl_copy_chunk_bug15644(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk chunk;
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_create_fill(torture,
+ tree,
+ tmp_ctx,
+ FNAME2,
+ &dest_h,
+ 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "dest file create fill");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = dest_h;
+ ioctl.smb2.in.function = FSCTL_SRV_COPYCHUNK;
+ ioctl.smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp);
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCT(chunk);
+ ZERO_STRUCT(cc_copy);
+ /* overwrite the resume key with a bogus value */
+ memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
+ cc_copy.chunk_count = 1;
+ cc_copy.chunks = &chunk;
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "FSCTL_SRV_COPYCHUNK");
+
+ status = smb2_util_close(tree, dest_h);
+ torture_assert_ntstatus_ok(torture, status, "close");
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
* testing of SMB2 ioctls
*/
struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
@@ -7420,6 +7482,8 @@ struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
test_ioctl_copy_chunk_dest_lck);
torture_suite_add_1smb2_test(suite, "copy_chunk_bad_key",
test_ioctl_copy_chunk_bad_key);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_bug15644",
+ test_ioctl_copy_chunk_bug15644);
torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest",
test_ioctl_copy_chunk_src_is_dest);
torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest_overlap",
diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c
index 823304f..2a3d0e6 100644
--- a/source4/torture/smb2/session.c
+++ b/source4/torture/smb2/session.c
@@ -5527,6 +5527,630 @@ static bool test_session_ntlmssp_bug14932(struct torture_context *tctx, struct s
return ret;
}
+static bool test_session_anon_encryption1(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ /*
+ * The connection is still in ConstrainedConnection state...
+ *
+ * This will use encryption and causes a connection reset
+ */
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ status = NT_STATUS_CONNECTION_RESET;
+ }
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_CONNECTION_RESET,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected");
+
+ return true;
+}
+
+static bool test_session_anon_encryption2(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *_creds = samba_cmdline_get_creds();
+ struct cli_credentials *user_creds = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *user_session = NULL;
+ struct smb2_tree *user_tree = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ struct smb2_ioctl ioctl = {
+ .level = RAW_IOCTL_SMB2,
+ .in = {
+ .file = {
+ .handle = {
+ .data = {
+ [0] = UINT64_MAX,
+ [1] = UINT64_MAX,
+ },
+ },
+ },
+ .function = FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ /* Windows client sets this to 64KiB */
+ .max_output_response = 0x10000,
+ .flags = SMB2_IOCTL_FLAG_IS_FSCTL,
+ },
+ };
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint32_t caps = smb2cli_conn_server_capabilities(transport0->conn);
+ NTSTATUS expected_mc_status;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ if (caps & SMB2_CAP_MULTI_CHANNEL) {
+ expected_mc_status = NT_STATUS_OK;
+ } else {
+ expected_mc_status = NT_STATUS_FS_DRIVER_REQUIRED;
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ user_creds = cli_credentials_shallow_copy(tctx, _creds);
+ torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(user_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ user_creds,
+ &user_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ user_session = user_tree->session;
+ transport = user_session->transport;
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)");
+ ok = smbXcli_session_is_authenticated(user_session->smbXcli);
+ torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)");
+
+ anon_session = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)");
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ anon_tree = smb2_tree_init(anon_session, tctx, false);
+ torture_assert(tctx, anon_tree != NULL, "smb2_tree_init");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2cli_tcon_recv(anon)");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ ok = smb2cli_tcon_is_encryption_on(anon_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ status = smb2_ioctl(user_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO user");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(anon_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(user_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO user");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(anon_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
+static bool test_session_anon_encryption3(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *_creds = samba_cmdline_get_creds();
+ struct cli_credentials *user_creds = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *user_session = NULL;
+ struct smb2_tree *user_tree = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, };
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ user_creds = cli_credentials_shallow_copy(tctx, _creds);
+ torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(user_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ user_creds,
+ &user_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ user_session = user_tree->session;
+ transport = user_session->transport;
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)");
+ ok = smbXcli_session_is_authenticated(user_session->smbXcli);
+ torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)");
+
+ anon_session = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)");
+
+ anon_session->anonymous_session_key = true;
+ anon_session->forced_session_key = data_blob_const(wrong_session_key,
+ ARRAY_SIZE(wrong_session_key));
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ anon_tree = smb2_tree_init(anon_session, tctx, false);
+ torture_assert(tctx, anon_tree != NULL, "smb2_tree_init");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ status = NT_STATUS_CONNECTION_RESET;
+ }
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_CONNECTION_RESET,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected");
+
+ return true;
+}
+
+static bool test_session_anon_signing1(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_signing");
+ ok = cli_credentials_set_smb_ipc_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
+static bool test_session_anon_signing2(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_session *anon_session_nosign = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, };
+ uint64_t session_id;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_signing");
+ ok = cli_credentials_set_smb_ipc_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ anon_session->forced_session_key = data_blob_const(wrong_session_key,
+ ARRAY_SIZE(wrong_session_key));
+ smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true);
+ smb2cli_session_torture_no_signing_disconnect(anon_session->smbXcli);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ /*
+ * create a new structure for the same session id,
+ * but without smb2.should_sign set.
+ */
+ session_id = smb2cli_session_current_id(anon_session->smbXcli);
+ anon_session_nosign = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session_nosign != NULL, "smb2_session_init(anon_nosign)");
+ smb2cli_session_set_id_and_flags(anon_session_nosign->smbXcli, session_id, 0);
+ smb2cli_session_torture_no_signing_disconnect(anon_session_nosign->smbXcli);
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session_nosign->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite =
@@ -5599,6 +6223,11 @@ struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
torture_suite_add_1smb2_test(suite, "encryption-aes-256-ccm", test_session_encryption_aes_256_ccm);
torture_suite_add_1smb2_test(suite, "encryption-aes-256-gcm", test_session_encryption_aes_256_gcm);
torture_suite_add_1smb2_test(suite, "ntlmssp_bug14932", test_session_ntlmssp_bug14932);
+ torture_suite_add_1smb2_test(suite, "anon-encryption1", test_session_anon_encryption1);
+ torture_suite_add_1smb2_test(suite, "anon-encryption2", test_session_anon_encryption2);
+ torture_suite_add_1smb2_test(suite, "anon-encryption3", test_session_anon_encryption3);
+ torture_suite_add_1smb2_test(suite, "anon-signing1", test_session_anon_signing1);
+ torture_suite_add_1smb2_test(suite, "anon-signing2", test_session_anon_signing2);
suite->description = talloc_strdup(suite, "SMB2-SESSION tests");
diff --git a/testprogs/blackbox/test_ldap_token.sh b/testprogs/blackbox/test_ldap_token.sh
new file mode 100755
index 0000000..5965590
--- /dev/null
+++ b/testprogs/blackbox/test_ldap_token.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+# Copyright (C) 2017 Stefan Metzmacher <metze@samba.org>
+
+if [ $# -lt 6 ]; then
+ cat <<EOF
+Usage: $# test_ldap_token.sh SERVER USERNAME PASSWORD REALM DOMAIN DOMSID
+EOF
+ exit 1
+fi
+
+SERVER=$1
+shift 1
+USERNAME=$1
+PASSWORD=$2
+REALM=$3
+DOMAIN=$4
+DOMSID=$5
+shift 5
+failed=0
+
+. $(dirname $0)/subunit.sh
+. $(dirname $0)/common_test_fns.inc
+
+ldbsearch=$(system_or_builddir_binary ldbsearch "${BINDIR}")
+
+test_token()
+{
+ auth_user="${1}"
+ shift 1
+ auth_sid="${1}"
+ shift 1
+ auth_args="$@"
+
+ out=$($VALGRIND $ldbsearch -H ldap://$SERVER.$REALM ${auth_user} -b '' --scope=base ${auth_args} tokenGroups 2>&1)
+ ret=$?
+ test x"$ret" = x"0" || {
+ echo "$out"
+ return 1
+ }
+
+ domain_sids=$(echo "$out" | grep '^tokenGroups' | grep "${DOMSID}-" | wc -l)
+ test "$domain_sids" -ge "1" || {
+ echo "$out"
+ echo "Less than 1 sid from $DOMAIN $DOMSID"
+ return 1
+ }
+
+ builtin_sids=$(echo "$out" | grep '^tokenGroups' | grep "S-1-5-32-" | wc -l)
+ test "$builtin_sids" -ge "1" || {
+ echo "$out"
+ echo "Less than 1 sid from BUILTIN S-1-5-32"
+ return 1
+ }
+
+ #
+ # The following should always be present
+ #
+ # SID_WORLD(S-1-1-0)
+ # SID_NT_NETWORK(S-1-5-2)
+ # SID_NT_AUTHENTICATED_USERS(S-1-5-11)
+ #
+ required_sids="S-1-1-0 S-1-5-2 S-1-5-11 ${auth_sid}"
+ for sid in $required_sids; do
+ found=$(echo "$out" | grep "^tokenGroups: ${sid}$" | wc -l)
+ test x"$found" = x"1" || {
+ echo "$out"
+ echo "SID: ${sid} not found"
+ return 1
+ }
+ done
+
+ return 0
+}
+
+UARGS="-U$REALM\\$USERNAME%$PASSWORD"
+# Check that SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY(S-1-18-1) is added for krb5
+AARGS="-k yes"
+testit "Test token with kerberos USER (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=required"
+testit "Test token with kerberos USER (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--option=clientusekerberos=required"
+testit "Test token with kerberos USER (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=required --option=clientusekerberos=off"
+testit "Test token with kerberos USER (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+# Check that SID_NT_NTLM_AUTHENTICATION(S-1-5-64-10) is added for NTLMSSP
+AARGS="-k no"
+testit "Test token with NTLMSSP USER (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=off"
+testit "Test token with NTLMSSP USER (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--option=clientusekerberos=off"
+testit "Test token with NTLMSSP USER (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=off --option=clientusekerberos=required"
+testit "Test token with NTLMSSP USER (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+
+UARGS="-P"
+# Check that SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY(S-1-18-1) is added for krb5
+AARGS="-k yes"
+testit "Test token with kerberos MACHINE (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=required"
+testit "Test token with kerberos MACHINE (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--option=clientusekerberos=required"
+testit "Test token with kerberos MACHINE (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=required --option=clientusekerberos=off"
+testit "Test token with kerberos MACHINE (${AARGS})" test_token "${UARGS}" "S-1-18-1" "${AARGS}" || failed=$(expr $failed + 1)
+# Check that SID_NT_NTLM_AUTHENTICATION(S-1-5-64-10) is added for NTLMSSP
+AARGS="-k no"
+testit "Test token with NTLMSSP MACHINE (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=off"
+testit "Test token with NTLMSSP MACHINE (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--option=clientusekerberos=off"
+testit "Test token with NTLMSSP MACHINE (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+AARGS="--use-kerberos=off --option=clientusekerberos=required"
+testit "Test token with NTLMSSP MACHINE (${AARGS})" test_token "${UARGS}" "S-1-5-64-10" "${AARGS}" || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/testprogs/blackbox/test_trust_token.sh b/testprogs/blackbox/test_trust_token.sh
index 075c032..92d4ad5 100755
--- a/testprogs/blackbox/test_trust_token.sh
+++ b/testprogs/blackbox/test_trust_token.sh
@@ -34,7 +34,7 @@ ldbsearch=$(system_or_builddir_binary ldbsearch "${BINDIR}")
test_token()
{
auth_args="${1}"
- auth_sid="${2-}"
+ auth_sid="${2}"
out=$($VALGRIND $ldbsearch -H ldap://$SERVER.$REALM -U$TRUST_REALM\\$TRUST_USERNAME%$TRUST_PASSWORD -b '' --scope=base -k ${auth_args} tokenGroups 2>&1)
ret=$?
@@ -84,7 +84,8 @@ test_token()
return 0
}
-testit "Test token with kerberos" test_token "yes" "" || failed=$(expr $failed + 1)
+# Check that SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY(S-1-18-1) is added for krb5
+testit "Test token with kerberos" test_token "yes" "S-1-18-1" || failed=$(expr $failed + 1)
# Check that SID_NT_NTLM_AUTHENTICATION(S-1-5-64-10) is added for NTLMSSP
testit "Test token with NTLMSSP" test_token "no" "S-1-5-64-10" || failed=$(expr $failed + 1)
diff --git a/third_party/socket_wrapper/socket_wrapper.c b/third_party/socket_wrapper/socket_wrapper.c
index c759d35..37799c8 100644
--- a/third_party/socket_wrapper/socket_wrapper.c
+++ b/third_party/socket_wrapper/socket_wrapper.c
@@ -1388,6 +1388,9 @@ static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt);
}
+/* JEMALLOC: This tells socket_wrapper if it should handle syscall() */
+static bool swrap_handle_syscall;
+
#ifdef HAVE_SYSCALL
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
static long int libc_vsyscall(long int sysno, va_list va)
@@ -1396,7 +1399,27 @@ static long int libc_vsyscall(long int sysno, va_list va)
long int rc;
int i;
- swrap_bind_symbol_all();
+ /*
+ * JEMALLOC:
+ *
+ * This is a workaround to prevent a deadlock in jemalloc calling
+ * malloc_init() twice. The first allocation call will trigger a
+ * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
+ * so it goes to socket or uid wrapper. In this code path we need to
+ * avoid any allocation calls. This will prevent the deadlock.
+ *
+ * We also need to avoid dlopen() as that would trigger the recursion
+ * into malloc_init(), so we use dlsym(RTLD_NEXT), until we reached
+ * swrap_constructor() or any real socket call at that time
+ * swrap_bind_symbol_all() will replace the function pointer again after
+ * dlopen of libc.
+ */
+ if (swrap_handle_syscall) {
+ swrap_bind_symbol_all();
+ } else if (swrap.libc.symbols._libc_syscall.obj == NULL) {
+ swrap.libc.symbols._libc_syscall.obj = dlsym(RTLD_NEXT,
+ "syscall");
+ }
for (i = 0; i < 8; i++) {
args[i] = va_arg(va, long int);
@@ -1517,6 +1540,8 @@ static void __swrap_bind_symbol_all_once(void)
swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_valid);
swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_va);
#endif
+
+ swrap_handle_syscall = true;
}
static void swrap_bind_symbol_all(void)
@@ -8745,6 +8770,21 @@ long int syscall(long int sysno, ...)
va_start(va, sysno);
/*
+ * JEMALLOC:
+ *
+ * This is a workaround to prevent a deadlock in jemalloc calling
+ * malloc_init() twice. The first allocation call will trigger a
+ * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
+ * so it goes to socket or uid wrapper. In this code path we need to
+ * avoid any allocation calls. This will prevent the deadlock.
+ */
+ if (!swrap_handle_syscall) {
+ rc = libc_vsyscall(sysno, va);
+ va_end(va);
+ return rc;
+ }
+
+ /*
* We should only handle the syscall numbers
* we care about...
*/
@@ -8860,6 +8900,9 @@ void swrap_constructor(void)
pthread_atfork(&swrap_thread_prepare,
&swrap_thread_parent,
&swrap_thread_child);
+
+ /* Let socket_wrapper handle syscall() */
+ swrap_handle_syscall = true;
}
/****************************
diff --git a/third_party/socket_wrapper/wscript b/third_party/socket_wrapper/wscript
index 9d2210d..cdd3493 100644
--- a/third_party/socket_wrapper/wscript
+++ b/third_party/socket_wrapper/wscript
@@ -2,7 +2,7 @@
import os
-VERSION = "1.4.2"
+VERSION = "1.4.3"
def configure(conf):
@@ -10,6 +10,7 @@ def configure(conf):
conf.DEFINE('USING_SYSTEM_SOCKET_WRAPPER', 1)
libsocket_wrapper_so_path = 'libsocket_wrapper.so'
else:
+ conf.CHECK_HEADERS('gnu/lib-names.h')
if conf.CONFIG_SET("HAVE___THREAD"):
conf.DEFINE("HAVE_GCC_THREAD_LOCAL_STORAGE", 1)
diff --git a/third_party/uid_wrapper/uid_wrapper.c b/third_party/uid_wrapper/uid_wrapper.c
index 5b6a82b..ca578e6 100644
--- a/third_party/uid_wrapper/uid_wrapper.c
+++ b/third_party/uid_wrapper/uid_wrapper.c
@@ -38,6 +38,10 @@
#include <pthread.h>
+#ifdef HAVE_GNU_LIB_NAMES_H
+#include <gnu/lib-names.h>
+#endif
+
#ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
# define UWRAP_THREAD __thread
#else
@@ -558,6 +562,13 @@ static void *uwrap_load_lib_handle(enum uwrap_lib lib)
switch (lib) {
case UWRAP_LIBC:
handle = uwrap.libc.handle;
+#ifdef LIBC_SO
+ if (handle == NULL) {
+ handle = dlopen(LIBC_SO, flags);
+
+ uwrap.libc.handle = handle;
+ }
+#endif
if (handle == NULL) {
for (i = 10; i >= 0; i--) {
char soname[256] = {0};
@@ -656,6 +667,9 @@ static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
dlsym(RTLD_DEFAULT, #sym_name); \
}
+/* JEMALLOC: This tells uid_wrapper if it should handle syscall() */
+static bool uwrap_handle_syscall;
+
/* DO NOT call this function during library initialization! */
static void __uwrap_bind_symbol_all_once(void)
{
@@ -699,6 +713,8 @@ static void __uwrap_bind_symbol_all_once(void)
#endif
uwrap_bind_symbol_libpthread(pthread_create);
uwrap_bind_symbol_libpthread(pthread_exit);
+
+ uwrap_handle_syscall = true;
}
static void uwrap_bind_symbol_all(void)
@@ -863,7 +879,27 @@ static long int libc_vsyscall(long int sysno, va_list va)
long int rc;
int i;
- uwrap_bind_symbol_all();
+ /*
+ * JEMALLOC:
+ *
+ * This is a workaround to prevent a deadlock in jemalloc calling
+ * malloc_init() twice. The first allocation call will trigger a
+ * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
+ * so it goes to socket or uid wrapper. In this code path we need to
+ * avoid any allocation calls. This will prevent the deadlock.
+ *
+ * We also need to avoid dlopen() as that would trigger the recursion
+ * into malloc_init(), so we use dlsym(RTLD_NEXT), until we reached
+ * swrap_constructor() or any real socket call at that time
+ * swrap_bind_symbol_all() will replace the function pointer again after
+ * dlopen of libc.
+ */
+ if (uwrap_handle_syscall) {
+ uwrap_bind_symbol_all();
+ } else if (uwrap.libc.symbols._libc_syscall.obj == NULL) {
+ uwrap.libc.symbols._libc_syscall.obj = dlsym(RTLD_NEXT,
+ "syscall");
+ }
for (i = 0; i < 8; i++) {
args[i] = va_arg(va, long int);
@@ -1375,7 +1411,7 @@ static void uwrap_init_env(struct uwrap_thread *id)
exit(-1);
}
- UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
+ UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize groups with %s", env);
id->ngroups = ngroups;
}
}
@@ -2709,6 +2745,21 @@ long int syscall (long int sysno, ...)
va_start(va, sysno);
/*
+ * JEMALLOC:
+ *
+ * This is a workaround to prevent a deadlock in jemalloc calling
+ * malloc_init() twice. The first allocation call will trigger a
+ * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
+ * so it goes to socket or uid wrapper. In this code path we need to
+ * avoid any allocation calls. This will prevent the deadlock.
+ */
+ if (!uwrap_handle_syscall) {
+ rc = libc_vsyscall(sysno, va);
+ va_end(va);
+ return rc;
+ }
+
+ /*
* We need to check for uwrap related syscall numbers before calling
* uid_wrapper_enabled() otherwise we'd deadlock during the freebsd libc
* fork() which calls syscall() after invoking uwrap_thread_prepare().
@@ -2821,6 +2872,9 @@ void uwrap_constructor(void)
* for main process.
*/
uwrap_init();
+
+ /* Let socket_wrapper handle syscall() */
+ uwrap_handle_syscall = true;
}
/****************************
diff --git a/third_party/uid_wrapper/wscript b/third_party/uid_wrapper/wscript
index 7b65d93..5af7690 100644
--- a/third_party/uid_wrapper/wscript
+++ b/third_party/uid_wrapper/wscript
@@ -3,13 +3,15 @@
from waflib import Options
import os, sys
-VERSION="1.3.0"
+VERSION="1.3.1"
def configure(conf):
if conf.CHECK_UID_WRAPPER():
conf.DEFINE('USING_SYSTEM_UID_WRAPPER', 1)
libuid_wrapper_so_path = 'libuid_wrapper.so'
else:
+ conf.CHECK_HEADERS('gnu/lib-names.h')
+
# check HAVE_GCC_ATOMIC_BUILTINS
conf.CHECK_CODE('''
#include <stdbool.h>
diff --git a/wscript b/wscript
index 770b9bc..167a3a7 100644
--- a/wscript
+++ b/wscript
@@ -140,7 +140,27 @@ def options(opt):
dest='with_smb1server',
help=("Build smbd with SMB1 support (default=yes)."))
+ opt.add_option('--vendor-name',
+ help=('Specify a vendor (or packager) name to include in the version string'),
+ type="string",
+ dest='SAMBA_VERSION_VENDOR_SUFFIX',
+ default=None)
+
+ opt.add_option('--vendor-patch-revision',
+ help=('Specify a vendor (or packager) patch revision number include in the version string (requires --vendor-name)'),
+ type="int",
+ dest='SAMBA_VERSION_VENDOR_PATCH',
+ default=None)
+
def configure(conf):
+ if Options.options.SAMBA_VERSION_VENDOR_SUFFIX:
+ conf.env.SAMBA_VERSION_VENDOR_SUFFIX = Options.options.SAMBA_VERSION_VENDOR_SUFFIX
+
+ if Options.options.SAMBA_VERSION_VENDOR_PATCH:
+ if not Options.options.SAMBA_VERSION_VENDOR_SUFFIX:
+ raise conf.fatal('--vendor-patch-revision requires --vendor-version')
+ conf.env.SAMBA_VERSION_VENDOR_PATCH = Options.options.SAMBA_VERSION_VENDOR_PATCH
+
version = samba_version.load_version(env=conf.env)
conf.DEFINE('CONFIG_H_IS_FROM_SAMBA', 1)