diff --git a/SOURCES/CVE-2016-2124.patch b/SOURCES/CVE-2016-2124.patch new file mode 100644 index 0000000..a4e015d --- /dev/null +++ b/SOURCES/CVE-2016-2124.patch @@ -0,0 +1,108 @@ +From 2a961e883b624219a72f212c554d34a18f22d4d1 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 24 Nov 2016 09:12:59 +0100 +Subject: [PATCH 1/2] CVE-2016-2124: s4:libcli/sesssetup: don't fallback to non + spnego authentication if we require kerberos + +We should not send NTLM[v2] data on the wire if the user asked for kerberos +only. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12444 + +Signed-off-by: Stefan Metzmacher +--- + source4/libcli/smb_composite/sesssetup.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c +index 51e121bdce6b..391ee081fe62 100644 +--- a/source4/libcli/smb_composite/sesssetup.c ++++ b/source4/libcli/smb_composite/sesssetup.c +@@ -622,6 +622,8 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + NTSTATUS status; + enum smb_encryption_setting encryption_state = + cli_credentials_get_smb_encryption(io->in.credentials); ++ enum credentials_use_kerberos krb5_state = ++ cli_credentials_get_kerberos_state(io->in.credentials); + + c = composite_create(session, session->transport->ev); + if (c == NULL) return NULL; +@@ -642,6 +644,10 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + + /* no session setup at all in earliest protocol varients */ + if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) { ++ if (krb5_state == CRED_USE_KERBEROS_REQUIRED) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + ZERO_STRUCT(io->out); + composite_done(c); + return c; +@@ -649,9 +655,17 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + + /* see what session setup interface we will use */ + if (session->transport->negotiate.protocol < PROTOCOL_NT1) { ++ if (krb5_state == CRED_USE_KERBEROS_REQUIRED) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + status = session_setup_old(c, session, io, &state->req); + } else if (!session->transport->options.use_spnego || + !(io->in.capabilities & CAP_EXTENDED_SECURITY)) { ++ if (krb5_state == CRED_USE_KERBEROS_REQUIRED) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + status = session_setup_nt1(c, session, io, &state->req); + } else { + struct tevent_req *subreq = NULL; +-- +2.25.1 + + +From 31a67554cf6c3d9368bef58d1249844f8eeb0059 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 27 Oct 2016 10:40:28 +0200 +Subject: [PATCH 2/2] CVE-2016-2124: s3:libsmb: don't fallback to non spnego + authentication if we require kerberos + +We should not send NTLM[v2] nor plaintext data on the wire if the user +asked for kerberos only. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12444 + +Signed-off-by: Stefan Metzmacher +--- + source3/libsmb/cliconnect.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c +index 853fb344bcd6..c01846ac8119 100644 +--- a/source3/libsmb/cliconnect.c ++++ b/source3/libsmb/cliconnect.c +@@ -1442,6 +1442,8 @@ struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx, + uint32_t in_sess_key = 0; + const char *in_native_os = NULL; + const char *in_native_lm = NULL; ++ enum credentials_use_kerberos krb5_state = ++ cli_credentials_get_kerberos_state(creds); + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, +@@ -1483,6 +1485,13 @@ struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx, + return req; + } + ++ if (krb5_state == CRED_USE_KERBEROS_REQUIRED) { ++ DBG_WARNING("Kerberos authentication requested, but " ++ "the server does not support SPNEGO authentication\n"); ++ tevent_req_nterror(req, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return tevent_req_post(req, ev); ++ } ++ + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) { + /* + * SessionSetupAndX was introduced by LANMAN 1.0. So we skip +-- +2.25.1 + diff --git a/SOURCES/CVE-2020-25717.patch b/SOURCES/CVE-2020-25717.patch new file mode 100644 index 0000000..7ffaa23 --- /dev/null +++ b/SOURCES/CVE-2020-25717.patch @@ -0,0 +1,3771 @@ +From 5ec536b3549edf118d2f88ca8a9265878a7c9fc5 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 18:04:55 +0200 +Subject: [PATCH 01/39] selftest/Samba3: remove unused close(USERMAP); calls + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14869 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org backported from commit d998f7f8df215866ab32e05be772e24fc0b2131c + as offline login tests are not in Samba 4.14] +--- + selftest/target/Samba3.pm | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index b0910433940..914b8d40c89 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -771,7 +771,6 @@ sub provision_ad_member + + mkdir($_, 0777) foreach(@dirs); + +- close(USERMAP); + $ret->{DOMAIN} = $dcvars->{DOMAIN}; + $ret->{REALM} = $dcvars->{REALM}; + $ret->{DOMSID} = $dcvars->{DOMSID}; +@@ -920,7 +919,6 @@ sub setup_ad_member_rfc2307 + + $ret or return undef; + +- close(USERMAP); + $ret->{DOMAIN} = $dcvars->{DOMAIN}; + $ret->{REALM} = $dcvars->{REALM}; + $ret->{DOMSID} = $dcvars->{DOMSID}; +@@ -1018,7 +1016,6 @@ sub setup_ad_member_idmap_rid + + $ret or return undef; + +- close(USERMAP); + $ret->{DOMAIN} = $dcvars->{DOMAIN}; + $ret->{REALM} = $dcvars->{REALM}; + $ret->{DOMSID} = $dcvars->{DOMSID}; +@@ -1118,7 +1115,6 @@ sub setup_ad_member_idmap_ad + + $ret or return undef; + +- close(USERMAP); + $ret->{DOMAIN} = $dcvars->{DOMAIN}; + $ret->{REALM} = $dcvars->{REALM}; + $ret->{DOMSID} = $dcvars->{DOMSID}; +-- +2.33.1 + + +From 6ad8a242a682abd7baa1e4d3672bb24c9e65ab0b Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 16:42:00 +0200 +Subject: [PATCH 02/39] selftest/Samba3: replace (winbindd => "yes", skip_wait + => 1) with (winbindd => "offline") + +This is much more flexible and concentrates the logic in a single place. + +We'll use winbindd => "offline" in other places soon. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14870 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 4dc3c68c9a28f71888e3d6dd3b1f0bcdb8fa45de) +--- + selftest/target/Samba3.pm | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 914b8d40c89..9534d06b597 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -827,7 +827,7 @@ sub provision_ad_member + nmbd => "yes", + winbindd => "yes", + smbd => "yes")) { +- return undef; ++ return undef; + } + + $ret->{DC_SERVER} = $dcvars->{SERVER}; +@@ -1909,7 +1909,7 @@ sub check_or_start($$) { + LOG_FILE => $env_vars->{WINBINDD_TEST_LOG}, + PCAP_FILE => "env-$ENV{ENVNAME}-winbindd", + }; +- if ($winbindd ne "yes") { ++ if ($winbindd ne "yes" and $winbindd ne "offline") { + $daemon_ctx->{SKIP_DAEMON} = 1; + } + +@@ -3130,13 +3130,17 @@ sub wait_for_start($$$$$) + } + } + +- if ($winbindd eq "yes") { ++ if ($winbindd eq "yes" or $winbindd eq "offline") { + print "checking for winbindd\n"; + my $count = 0; + $cmd = "SELFTEST_WINBINDD_SOCKET_DIR='$envvars->{SELFTEST_WINBINDD_SOCKET_DIR}' "; + $cmd .= "NSS_WRAPPER_PASSWD='$envvars->{NSS_WRAPPER_PASSWD}' "; + $cmd .= "NSS_WRAPPER_GROUP='$envvars->{NSS_WRAPPER_GROUP}' "; +- $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc"; ++ if ($winbindd eq "yes") { ++ $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc"; ++ } elsif ($winbindd eq "offline") { ++ $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping"; ++ } + + do { + $ret = system($cmd); +-- +2.33.1 + + +From c25f4625813b0f7f3baf33ce17c3d6691c9fd602 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Tue, 11 May 2021 17:59:51 +0200 +Subject: [PATCH 03/39] CVE-2020-25717 selftest: Pass down the machine account + name to provision_ad_member + +Signed-off-by: Andreas Schneider +Reviewed-by: Jeremy Allison + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit fbe68dcbb783409589cdefd8ee551c9971c51f08) + +Needed as preparation for CVE-2020-25717 +--- + selftest/target/Samba.pm | 1 + + selftest/target/Samba3.pm | 10 ++++++++-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm +index 5a7efa9c280..d48ac2c64a1 100644 +--- a/selftest/target/Samba.pm ++++ b/selftest/target/Samba.pm +@@ -588,6 +588,7 @@ sub get_interface($) + addcsmb1 => 54, + lclnt4dc2smb1 => 55, + fipsdc => 56, ++ fipsadmember => 57, + + rootdnsforwarder => 64, + +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 9534d06b597..4686f5d36aa 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -646,6 +646,7 @@ sub provision_ad_member + { + my ($self, + $prefix, ++ $machine_account, + $dcvars, + $trustvars_f, + $trustvars_e, +@@ -762,7 +763,7 @@ sub provision_ad_member + prefix => $prefix, + domain => $dcvars->{DOMAIN}, + realm => $dcvars->{REALM}, +- server => "LOCALADMEMBER", ++ server => $machine_account, + password => "loCalMemberPass", + extra_options => $member_options, + resolv_conf => $dcvars->{RESOLV_CONF}); +@@ -876,7 +877,11 @@ sub setup_ad_member + + print "PROVISIONING AD MEMBER..."; + +- return $self->provision_ad_member($prefix, $dcvars, $trustvars_f, $trustvars_e); ++ return $self->provision_ad_member($prefix, ++ "LOCALADMEMBER", ++ $dcvars, ++ $trustvars_f, ++ $trustvars_e); + } + + sub setup_ad_member_rfc2307 +@@ -1199,6 +1204,7 @@ sub setup_ad_member_fips + print "PROVISIONING AD FIPS MEMBER..."; + + return $self->provision_ad_member($prefix, ++ "FIPSADMEMBER", + $dcvars, + $trustvars_f, + $trustvars_e, +-- +2.33.1 + + +From 449503537d409f5774433ea19f520f560bfff981 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Thu, 10 Jun 2021 16:20:28 +0200 +Subject: [PATCH 04/39] CVE-2020-25717 selftest: Only set netbios aliases for + the ad_member env + +The provision_ad_member() function is reused by different +setup_ad_member*() functions. Each environment needs to have unique +netbios aliases as they are all in the same network. +The aliases should only be set for the 'ad_member' environment. + +Signed-Off-By: Andreas Schneider +Reviewed-by: Jeremy Allison + +Autobuild-User(master): Jeremy Allison +Autobuild-Date(master): Fri Jun 11 01:26:36 UTC 2021 on sn-devel-184 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit e165dcc770ec58c3749d653d6cb85f6ecf9479d6) +--- + selftest/target/Samba3.pm | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 4686f5d36aa..5c0f71757ef 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -682,11 +682,17 @@ sub provision_ad_member + $substitution_path = "$share_dir/D_$dcvars->{DOMAIN}/u_$dcvars->{DOMAIN}/alice/g_$dcvars->{DOMAIN}/domain users"; + push(@dirs, $substitution_path); + ++ ++ my $netbios_aliases = ""; ++ if ($machine_account eq "LOCALADMEMBER") { ++ $netbios_aliases = "netbios aliases = foo bar"; ++ } ++ + my $member_options = " + security = ads + workgroup = $dcvars->{DOMAIN} + realm = $dcvars->{REALM} +- netbios aliases = foo bar ++ $netbios_aliases + template homedir = /home/%D/%G/%U + auth event notification = true + password server = $dcvars->{SERVER} +-- +2.33.1 + + +From 930722757311af95dbd516222e21a4a107f11ce4 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Wed, 14 Apr 2021 10:05:59 +0200 +Subject: [PATCH 05/39] CVE-2020-25717 auth3: Simplify check_samba4_security() + +First set up "server_info" in a local variable and once it's fully set +up, assign it to the out parameter "pserver_info". + +Pointer dereferencing obfuscates the code for me. + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 062a0c14c6ee0b74e7619af73747df59c5e67672) +--- + source3/auth/auth_samba4.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c +index 0a7c67be232..ac141354747 100644 +--- a/source3/auth/auth_samba4.c ++++ b/source3/auth/auth_samba4.c +@@ -108,11 +108,12 @@ static struct server_id *new_server_id_task(TALLOC_CTX *mem_ctx) + * services the AD DC. It is tested via pdbtest. + */ + +-static NTSTATUS check_samba4_security(const struct auth_context *auth_context, +- void *my_private_data, +- TALLOC_CTX *mem_ctx, +- const struct auth_usersupplied_info *user_info, +- struct auth_serversupplied_info **server_info) ++static NTSTATUS check_samba4_security( ++ const struct auth_context *auth_context, ++ void *my_private_data, ++ TALLOC_CTX *mem_ctx, ++ const struct auth_usersupplied_info *user_info, ++ struct auth_serversupplied_info **pserver_info) + { + TALLOC_CTX *frame = talloc_stackframe(); + struct netr_SamInfo3 *info3 = NULL; +@@ -120,6 +121,7 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, + struct auth_user_info_dc *user_info_dc; + struct auth4_context *auth4_context; + uint8_t authoritative = 0; ++ struct auth_serversupplied_info *server_info = NULL; + + nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context); + if (!NT_STATUS_IS_OK(nt_status)) { +@@ -161,17 +163,19 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, + } + + if (user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) { +- *server_info = make_server_info(mem_ctx); +- if (*server_info == NULL) { ++ server_info = make_server_info(mem_ctx); ++ if (server_info == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } +- (*server_info)->info3 = talloc_steal(*server_info, info3); +- ++ server_info->info3 = talloc_move(server_info, &info3); + } else { +- nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, +- user_info->mapped.domain_name, server_info, +- info3); ++ nt_status = make_server_info_info3( ++ mem_ctx, ++ user_info->client.account_name, ++ user_info->mapped.domain_name, ++ &server_info, ++ info3); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("make_server_info_info3 failed: %s\n", + nt_errstr(nt_status))); +@@ -179,6 +183,7 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, + } + } + ++ *pserver_info = server_info; + nt_status = NT_STATUS_OK; + + done: +-- +2.33.1 + + +From bf52e64053a0f4369d005782d2f9a75d03328ddb Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Tue, 13 Apr 2021 15:14:01 +0000 +Subject: [PATCH 06/39] CVE-2020-25717 auth: Simplify DEBUG statements in + make_auth3_context_for_ntlm() + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 8536bf7fce41c43bbed25f7ed4ce5775a1b9c0d5) +--- + source3/auth/auth.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/source3/auth/auth.c b/source3/auth/auth.c +index fa73c4e4db2..6d2a40f0f29 100644 +--- a/source3/auth/auth.c ++++ b/source3/auth/auth.c +@@ -530,28 +530,28 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, + struct auth_context **auth_context) + { + const char *methods = NULL; ++ const char *role = NULL; + + switch (lp_server_role()) { + case ROLE_ACTIVE_DIRECTORY_DC: +- DEBUG(5,("Making default auth method list for server role = " +- "'active directory domain controller'\n")); ++ role = "'active directory domain controller'"; + methods = "samba4"; + break; + case ROLE_DOMAIN_MEMBER: +- DEBUG(5,("Making default auth method list for server role = 'domain member'\n")); ++ role = "'domain member'"; + methods = "anonymous sam winbind sam_ignoredomain"; + break; + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: +- DEBUG(5,("Making default auth method list for DC\n")); ++ role = "'DC'"; + methods = "anonymous sam winbind sam_ignoredomain"; + break; + case ROLE_STANDALONE: +- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = yes\n")); + if (lp_encrypt_passwords()) { ++ role = "'standalone server', encrypt passwords = yes"; + methods = "anonymous sam_ignoredomain"; + } else { +- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = no\n")); ++ role = "'standalone server', encrypt passwords = no"; + methods = "anonymous unix"; + } + break; +@@ -560,6 +560,9 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, + return NT_STATUS_UNSUCCESSFUL; + } + ++ DBG_INFO("Making default auth method list for server role = %s\n", ++ role); ++ + return make_auth_context_specific(mem_ctx, auth_context, methods); + } + +-- +2.33.1 + + +From fe1188475e15269321a62b4d11cc520e5b7d0c6e Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Wed, 14 Apr 2021 21:48:32 +0200 +Subject: [PATCH 07/39] CVE-2020-25717 auth4: Make auth_anonymous pseudo-async + +Signed-off-by: Volker Lendecke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 759573136876ef2b1b1c7484f99570d7de957e0d) +--- + source4/auth/ntlm/auth_anonymous.c | 66 ++++++++++++++++++++++++++---- + source4/auth/ntlm/wscript_build | 2 +- + 2 files changed, 58 insertions(+), 10 deletions(-) + +diff --git a/source4/auth/ntlm/auth_anonymous.c b/source4/auth/ntlm/auth_anonymous.c +index 83aeb431f5f..a25aacaa137 100644 +--- a/source4/auth/ntlm/auth_anonymous.c ++++ b/source4/auth/ntlm/auth_anonymous.c +@@ -20,9 +20,11 @@ + */ + + #include "includes.h" ++#include + #include "auth/auth.h" + #include "auth/ntlm/auth_proto.h" + #include "param/param.h" ++#include "lib/util/tevent_ntstatus.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -84,19 +86,65 @@ static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, + * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' + * and pass onto the next module. + **/ +-static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, +- TALLOC_CTX *mem_ctx, +- const struct auth_usersupplied_info *user_info, +- struct auth_user_info_dc **_user_info_dc, +- bool *authoritative) ++ ++struct anonymous_check_password_state { ++ struct auth_user_info_dc *user_info_dc; ++}; ++ ++static struct tevent_req *anonymous_check_password_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct auth_method_context *ctx, ++ const struct auth_usersupplied_info *user_info) ++{ ++ struct tevent_req *req = NULL; ++ struct anonymous_check_password_state *state = NULL; ++ NTSTATUS status; ++ ++ req = tevent_req_create( ++ mem_ctx, ++ &state, ++ struct anonymous_check_password_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ status = auth_anonymous_user_info_dc( ++ state, ++ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), ++ &state->user_info_dc); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); ++ } ++ tevent_req_done(req); ++ return tevent_req_post(req, ev); ++} ++ ++static NTSTATUS anonymous_check_password_recv( ++ struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct auth_user_info_dc **interim_info, ++ bool *authoritative) + { +- return auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), _user_info_dc); ++ struct anonymous_check_password_state *state = tevent_req_data( ++ req, struct anonymous_check_password_state); ++ NTSTATUS status; ++ ++ if (tevent_req_is_nterror(req, &status)) { ++ tevent_req_received(req); ++ return status; ++ } ++ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); ++ tevent_req_received(req); ++ return NT_STATUS_OK; + } + ++ + static const struct auth_operations anonymous_auth_ops = { +- .name = "anonymous", +- .want_check = anonymous_want_check, +- .check_password = anonymous_check_password ++ .name = "anonymous", ++ .want_check = anonymous_want_check, ++ .check_password_send = anonymous_check_password_send, ++ .check_password_recv = anonymous_check_password_recv, + }; + + _PUBLIC_ NTSTATUS auth4_anonymous_init(TALLOC_CTX *ctx) +diff --git a/source4/auth/ntlm/wscript_build b/source4/auth/ntlm/wscript_build +index 04a760c3e49..6ea0c4d7e3a 100644 +--- a/source4/auth/ntlm/wscript_build ++++ b/source4/auth/ntlm/wscript_build +@@ -12,7 +12,7 @@ bld.SAMBA_MODULE('auth4_anonymous', + source='auth_anonymous.c', + subsystem='auth4', + init_function='auth4_anonymous_init', +- deps='talloc' ++ deps='tevent' + ) + + +-- +2.33.1 + + +From c72dd26cd46ca9dc7e68649f444accf0da9b7d51 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Wed, 14 Apr 2021 22:22:18 +0200 +Subject: [PATCH 08/39] CVE-2020-25717 auth4: Make auth_developer pseudo-async + +This is a simpler approach to really just wrap the code. + +Signed-off-by: Volker Lendecke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 43a1e42815718591faa8d526319b96d089a758fa) +--- + source4/auth/ntlm/auth_developer.c | 61 +++++++++++++++++++++++++++++- + source4/auth/ntlm/wscript_build | 2 +- + 2 files changed, 61 insertions(+), 2 deletions(-) + +diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c +index 209786b63b2..1823989c68d 100644 +--- a/source4/auth/ntlm/auth_developer.c ++++ b/source4/auth/ntlm/auth_developer.c +@@ -20,9 +20,11 @@ + */ + + #include "includes.h" ++#include + #include "auth/auth.h" + #include "auth/ntlm/auth_proto.h" + #include "libcli/security/security.h" ++#include "lib/util/tevent_ntstatus.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -137,10 +139,67 @@ static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, + return nt_status; + } + ++struct name_to_ntstatus_check_password_state { ++ struct auth_user_info_dc *user_info_dc; ++ bool authoritative; ++}; ++ ++static struct tevent_req *name_to_ntstatus_check_password_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct auth_method_context *ctx, ++ const struct auth_usersupplied_info *user_info) ++{ ++ struct tevent_req *req = NULL; ++ struct name_to_ntstatus_check_password_state *state = NULL; ++ NTSTATUS status; ++ ++ req = tevent_req_create( ++ mem_ctx, ++ &state, ++ struct name_to_ntstatus_check_password_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ status = name_to_ntstatus_check_password( ++ ctx, ++ state, ++ user_info, ++ &state->user_info_dc, ++ &state->authoritative); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); ++ } ++ tevent_req_done(req); ++ return tevent_req_post(req, ev); ++} ++ ++static NTSTATUS name_to_ntstatus_check_password_recv( ++ struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct auth_user_info_dc **interim_info, ++ bool *authoritative) ++{ ++ struct name_to_ntstatus_check_password_state *state = tevent_req_data( ++ req, struct name_to_ntstatus_check_password_state); ++ NTSTATUS status; ++ ++ if (tevent_req_is_nterror(req, &status)) { ++ tevent_req_received(req); ++ return status; ++ } ++ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); ++ *authoritative = state->authoritative; ++ tevent_req_received(req); ++ return NT_STATUS_OK; ++} ++ + static const struct auth_operations name_to_ntstatus_auth_ops = { + .name = "name_to_ntstatus", + .want_check = name_to_ntstatus_want_check, +- .check_password = name_to_ntstatus_check_password ++ .check_password_send = name_to_ntstatus_check_password_send, ++ .check_password_recv = name_to_ntstatus_check_password_recv, + }; + + _PUBLIC_ NTSTATUS auth4_developer_init(TALLOC_CTX *ctx) +diff --git a/source4/auth/ntlm/wscript_build b/source4/auth/ntlm/wscript_build +index 6ea0c4d7e3a..1ee8d79563a 100644 +--- a/source4/auth/ntlm/wscript_build ++++ b/source4/auth/ntlm/wscript_build +@@ -28,7 +28,7 @@ bld.SAMBA_MODULE('auth4_developer', + source='auth_developer.c', + subsystem='auth4', + init_function='auth4_developer_init', +- deps='talloc' ++ deps='tevent' + ) + + +-- +2.33.1 + + +From a5f3c5d48c490c637cf4e5854dbd01a585c9c0eb Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Wed, 14 Apr 2021 21:59:55 +0200 +Subject: [PATCH 09/39] CVE-2020-25717 auth4: Make auth_unix pseudo-async + +Signed-off-by: Volker Lendecke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit a6f42ab8a778b9863990da3112c2e868cd006303) +--- + source4/auth/ntlm/auth_unix.c | 85 ++++++++++++++++++++++++----------- + 1 file changed, 59 insertions(+), 26 deletions(-) + +diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c +index 67cd5f3dc44..cfe4f1a073f 100644 +--- a/source4/auth/ntlm/auth_unix.c ++++ b/source4/auth/ntlm/auth_unix.c +@@ -27,6 +27,7 @@ + #include "lib/tsocket/tsocket.h" + #include "../libcli/auth/pam_errors.h" + #include "param/param.h" ++#include "lib/util/tevent_ntstatus.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -713,46 +714,78 @@ static NTSTATUS authunix_want_check(struct auth_method_context *ctx, + return NT_STATUS_OK; + } + +-static NTSTATUS authunix_check_password(struct auth_method_context *ctx, +- TALLOC_CTX *mem_ctx, +- const struct auth_usersupplied_info *user_info, +- struct auth_user_info_dc **user_info_dc, +- bool *authoritative) ++struct authunix_check_password_state { ++ struct auth_user_info_dc *user_info_dc; ++}; ++ ++static struct tevent_req *authunix_check_password_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct auth_method_context *ctx, ++ const struct auth_usersupplied_info *user_info) + { +- TALLOC_CTX *check_ctx; +- NTSTATUS nt_status; +- struct passwd *pwd; ++ struct tevent_req *req = NULL; ++ struct authunix_check_password_state *state = NULL; ++ struct passwd *pwd = NULL; ++ NTSTATUS status; + +- if (user_info->password_state != AUTH_PASSWORD_PLAIN) { +- return NT_STATUS_INVALID_PARAMETER; ++ req = tevent_req_create( ++ mem_ctx, ++ &state, ++ struct authunix_check_password_state); ++ if (req == NULL) { ++ return NULL; + } + +- check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); +- if (check_ctx == NULL) { +- return NT_STATUS_NO_MEMORY; ++ if (user_info->password_state != AUTH_PASSWORD_PLAIN) { ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return tevent_req_post(req, ev); + } + +- nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); +- if (!NT_STATUS_IS_OK(nt_status)) { +- talloc_free(check_ctx); +- return nt_status; ++ status = check_unix_password( ++ state, ctx->auth_ctx->lp_ctx, user_info, &pwd); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); + } + +- nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), +- user_info, pwd, user_info_dc); +- if (!NT_STATUS_IS_OK(nt_status)) { +- talloc_free(check_ctx); +- return nt_status; ++ status = authunix_make_user_info_dc( ++ state, ++ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), ++ user_info, ++ pwd, ++ &state->user_info_dc); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); + } + +- talloc_free(check_ctx); ++ tevent_req_done(req); ++ return tevent_req_post(req, ev); ++} ++ ++static NTSTATUS authunix_check_password_recv( ++ struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct auth_user_info_dc **interim_info, ++ bool *authoritative) ++{ ++ struct authunix_check_password_state *state = tevent_req_data( ++ req, struct authunix_check_password_state); ++ NTSTATUS status; ++ ++ if (tevent_req_is_nterror(req, &status)) { ++ tevent_req_received(req); ++ return status; ++ } ++ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); ++ tevent_req_received(req); + return NT_STATUS_OK; + } + + static const struct auth_operations unix_ops = { +- .name = "unix", +- .want_check = authunix_want_check, +- .check_password = authunix_check_password ++ .name = "unix", ++ .want_check = authunix_want_check, ++ .check_password_send = authunix_check_password_send, ++ .check_password_recv = authunix_check_password_recv, + }; + + _PUBLIC_ NTSTATUS auth4_unix_init(TALLOC_CTX *ctx) +-- +2.33.1 + + +From e655b408ee2bf4fb4535140c03dd1d795be861dd Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Thu, 15 Apr 2021 10:04:21 +0200 +Subject: [PATCH 10/39] CVE-2020-25717 auth4: Make auth_sam pseudo-async + +Signed-off-by: Volker Lendecke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit f852fb4cd4e2bcd676a9ea104c5bf00979771eed) +--- + source4/auth/ntlm/auth_sam.c | 69 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 67 insertions(+), 2 deletions(-) + +diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c +index c5b27171937..a521bc94bc4 100644 +--- a/source4/auth/ntlm/auth_sam.c ++++ b/source4/auth/ntlm/auth_sam.c +@@ -36,6 +36,7 @@ + #include "lib/messaging/irpc.h" + #include "libcli/auth/libcli_auth.h" + #include "libds/common/roles.h" ++#include "lib/util/tevent_ntstatus.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -733,6 +734,68 @@ static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx + return NT_STATUS_OK; + } + ++struct authsam_check_password_state { ++ struct auth_user_info_dc *user_info_dc; ++ bool authoritative; ++}; ++ ++static struct tevent_req *authsam_check_password_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct auth_method_context *ctx, ++ const struct auth_usersupplied_info *user_info) ++{ ++ struct tevent_req *req = NULL; ++ struct authsam_check_password_state *state = NULL; ++ NTSTATUS status; ++ ++ req = tevent_req_create( ++ mem_ctx, &state, struct authsam_check_password_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ /* ++ * authsam_check_password_internals() sets this to false in ++ * the rodc case, otherwise it leaves it untouched. Default to ++ * "we're authoritative". ++ */ ++ state->authoritative = true; ++ ++ status = authsam_check_password_internals( ++ ctx, ++ state, ++ user_info, ++ &state->user_info_dc, ++ &state->authoritative); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); ++ } ++ ++ tevent_req_done(req); ++ return tevent_req_post(req, ev); ++} ++ ++static NTSTATUS authsam_check_password_recv( ++ struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct auth_user_info_dc **interim_info, ++ bool *authoritative) ++{ ++ struct authsam_check_password_state *state = tevent_req_data( ++ req, struct authsam_check_password_state); ++ NTSTATUS status; ++ ++ *authoritative = state->authoritative; ++ ++ if (tevent_req_is_nterror(req, &status)) { ++ tevent_req_received(req); ++ return status; ++ } ++ *interim_info = talloc_move(mem_ctx, &state->user_info_dc); ++ tevent_req_received(req); ++ return NT_STATUS_OK; ++} ++ + static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +@@ -888,14 +951,16 @@ static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx, + static const struct auth_operations sam_ignoredomain_ops = { + .name = "sam_ignoredomain", + .want_check = authsam_ignoredomain_want_check, +- .check_password = authsam_check_password_internals, ++ .check_password_send = authsam_check_password_send, ++ .check_password_recv = authsam_check_password_recv, + .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + }; + + static const struct auth_operations sam_ops = { + .name = "sam", + .want_check = authsam_want_check, +- .check_password = authsam_check_password_internals, ++ .check_password_send = authsam_check_password_send, ++ .check_password_recv = authsam_check_password_recv, + .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + }; + +-- +2.33.1 + + +From 61e6c5f7c5d1df83350ae4969a1f365b4302a240 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Wed, 14 Apr 2021 22:24:44 +0200 +Subject: [PATCH 11/39] CVE-2020-25717 auth4: Remove sync check_password from + auth_operations + +Remove complexity in the data structures, and pushes the async-ness +one level down. + +Signed-off-by: Volker Lendecke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 254af19ba89b4c42e5f45ec731e6577d2fcc6736) +--- + source4/auth/auth.h | 4 ---- + source4/auth/ntlm/auth.c | 44 ++++------------------------------------ + 2 files changed, 4 insertions(+), 44 deletions(-) + +diff --git a/source4/auth/auth.h b/source4/auth/auth.h +index 51895c9259f..3f9fb1ae3cb 100644 +--- a/source4/auth/auth.h ++++ b/source4/auth/auth.h +@@ -61,10 +61,6 @@ struct auth_operations { + + /* Given the user supplied info, check a password */ + +- NTSTATUS (*check_password)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, +- const struct auth_usersupplied_info *user_info, +- struct auth_user_info_dc **interim_info, +- bool *authoritative); + struct tevent_req *(*check_password_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct auth_method_context *ctx, +diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c +index 75cf12c5742..e54eb7719f5 100644 +--- a/source4/auth/ntlm/auth.c ++++ b/source4/auth/ntlm/auth.c +@@ -332,7 +332,6 @@ static void auth_check_password_next(struct tevent_req *req) + struct auth_check_password_state *state = + tevent_req_data(req, struct auth_check_password_state); + struct tevent_req *subreq = NULL; +- bool authoritative = true; + NTSTATUS status; + + if (state->method == NULL) { +@@ -357,47 +356,12 @@ static void auth_check_password_next(struct tevent_req *req) + return; + } + +- if (state->method->ops->check_password_send != NULL) { +- subreq = state->method->ops->check_password_send(state, +- state->ev, +- state->method, +- state->user_info); +- if (tevent_req_nomem(subreq, req)) { +- return; +- } +- tevent_req_set_callback(subreq, +- auth_check_password_done, +- req); +- return; +- } +- +- if (state->method->ops->check_password == NULL) { +- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); +- return; +- } +- +- status = state->method->ops->check_password(state->method, +- state, +- state->user_info, +- &state->user_info_dc, +- &authoritative); +- if (!authoritative || +- NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) { +- DEBUG(11,("auth_check_password_send: " +- "%s passes to the next method\n", +- state->method->ops->name)); +- state->method = state->method->next; +- auth_check_password_next(req); +- return; +- } +- +- /* the backend has handled the request */ +- +- if (tevent_req_nterror(req, status)) { ++ subreq = state->method->ops->check_password_send( ++ state, state->ev, state->method, state->user_info); ++ if (tevent_req_nomem(subreq, req)) { + return; + } +- +- tevent_req_done(req); ++ tevent_req_set_callback(subreq, auth_check_password_done, req); + } + + static void auth_check_password_done(struct tevent_req *subreq) +-- +2.33.1 + + +From 557c44fe666b758eebb8ffab2b540722d995f3cd Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 17:29:34 +0200 +Subject: [PATCH 12/39] CVE-2020-25717: s3:winbindd: make sure we default to + r->out.authoritative = true + +We need to make sure that temporary failures don't trigger a fallback +to the local SAM that silently ignores the domain name part for users. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/winbindd/winbindd_dual_srv.c | 7 +++++++ + source3/winbindd/winbindd_irpc.c | 7 +++++++ + source3/winbindd/winbindd_pam.c | 15 +++++++++++---- + source3/winbindd/winbindd_pam_auth_crap.c | 9 ++++++++- + source3/winbindd/winbindd_util.c | 7 +++++++ + 5 files changed, 40 insertions(+), 5 deletions(-) + +diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c +index 32d11e1fa57..0be5ae5554b 100644 +--- a/source3/winbindd/winbindd_dual_srv.c ++++ b/source3/winbindd/winbindd_dual_srv.c +@@ -941,6 +941,13 @@ NTSTATUS _winbind_SamLogon(struct pipes_struct *p, + union netr_Validation *validation = NULL; + bool interactive = false; + ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ r->out.authoritative = true; ++ + domain = wb_child_domain(); + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; +diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c +index e419736010b..918393c0827 100644 +--- a/source3/winbindd/winbindd_irpc.c ++++ b/source3/winbindd/winbindd_irpc.c +@@ -142,6 +142,13 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg, + const char *target_domain_name = NULL; + const char *account_name = NULL; + ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ req->out.authoritative = true; ++ + switch (req->in.logon_level) { + case NetlogonInteractiveInformation: + case NetlogonServiceInformation: +diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c +index f27802ee065..f71eb8197a4 100644 +--- a/source3/winbindd/winbindd_pam.c ++++ b/source3/winbindd/winbindd_pam.c +@@ -1799,7 +1799,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( + { + fstring name_namespace, name_domain, name_user; + NTSTATUS result; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level = 0; + union netr_Validation *validation = NULL; +@@ -2453,6 +2453,13 @@ done: + result = NT_STATUS_NO_LOGON_SERVERS; + } + ++ /* ++ * Here we don't alter ++ * state->response->data.auth.authoritative based ++ * on the servers response ++ * as we don't want a fallback to the local sam ++ * for interactive PAM logons ++ */ + set_auth_errors(state->response, result); + + DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n", +@@ -2667,7 +2674,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, + const char *name_domain = NULL; + const char *workstation; + uint64_t logon_id = 0; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level; + union netr_Validation *validation = NULL; +@@ -2740,7 +2747,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, + &validation_level, + &validation); + if (!NT_STATUS_IS_OK(result)) { +- state->response->data.auth.authoritative = authoritative; + goto done; + } + +@@ -2772,7 +2778,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, + "from firewalled domain [%s]\n", + info3->base.account_name.string, + info3->base.logon_domain.string); +- state->response->data.auth.authoritative = true; + result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED; + goto done; + } +@@ -2794,6 +2799,8 @@ done: + } + + set_auth_errors(state->response, result); ++ state->response->data.auth.authoritative = authoritative; ++ + /* + * Log the winbind pam authentication, the logon_id will tie this to + * any of the logons invoked from this request. +diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c +index dacb6566be6..a6f13806df9 100644 +--- a/source3/winbindd/winbindd_pam_auth_crap.c ++++ b/source3/winbindd/winbindd_pam_auth_crap.c +@@ -26,6 +26,7 @@ + + struct winbindd_pam_auth_crap_state { + struct winbindd_response *response; ++ bool authoritative; + uint32_t flags; + }; + +@@ -47,7 +48,7 @@ struct tevent_req *winbindd_pam_auth_crap_send( + if (req == NULL) { + return NULL; + } +- ++ state->authoritative = true; + state->flags = request->flags; + + if (state->flags & WBFLAG_PAM_AUTH_PAC) { +@@ -126,6 +127,11 @@ struct tevent_req *winbindd_pam_auth_crap_send( + + domain = find_auth_domain(request->flags, auth_domain); + if (domain == NULL) { ++ /* ++ * We don't know the domain so ++ * we're not authoritative ++ */ ++ state->authoritative = false; + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } +@@ -186,6 +192,7 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req, + + if (tevent_req_is_nterror(req, &status)) { + set_auth_errors(response, status); ++ response->data.auth.authoritative = state->authoritative; + return status; + } + +diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c +index 414b770a271..ac4cd731c09 100644 +--- a/source3/winbindd/winbindd_util.c ++++ b/source3/winbindd/winbindd_util.c +@@ -2095,6 +2095,13 @@ void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain) + + void set_auth_errors(struct winbindd_response *resp, NTSTATUS result) + { ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ resp->data.auth.authoritative = true; ++ + resp->data.auth.nt_status = NT_STATUS_V(result); + fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result)); + +-- +2.33.1 + + +From 3733dfeb24e5b58f9d92940573afbcd4a4d418fa Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 17:29:34 +0200 +Subject: [PATCH 13/39] CVE-2020-25717: s4:auth/ntlm: make sure + auth_check_password() defaults to r->out.authoritative = true + +We need to make sure that temporary failures don't trigger a fallback +to the local SAM that silently ignores the domain name part for users. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/auth/ntlm/auth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c +index e54eb7719f5..4c66f2c23cb 100644 +--- a/source4/auth/ntlm/auth.c ++++ b/source4/auth/ntlm/auth.c +@@ -169,6 +169,11 @@ _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx, + /*TODO: create a new event context here! */ + ev = auth_ctx->event_ctx; + ++ /* ++ * We are authoritative by default ++ */ ++ *pauthoritative = 1; ++ + subreq = auth_check_password_send(mem_ctx, + ev, + auth_ctx, +-- +2.33.1 + + +From fb466bcff4f42287e2895cf3b1b0dc20776ec607 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 14/39] CVE-2020-25717: s4:torture: start with authoritative = + 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/torture/rpc/samlogon.c | 4 ++-- + source4/torture/rpc/schannel.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c +index 76933b8869e..703e25fe3c5 100644 +--- a/source4/torture/rpc/samlogon.c ++++ b/source4/torture/rpc/samlogon.c +@@ -1407,7 +1407,7 @@ static bool test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + + union netr_LogonLevel logon; + union netr_Validation validation; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + + ZERO_STRUCT(logon); +@@ -1520,7 +1520,7 @@ bool test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + + union netr_LogonLevel logon; + union netr_Validation validation; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + struct dcerpc_binding_handle *b = p->binding_handle; + + ZERO_STRUCT(a); +diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c +index a5755041040..08a5120b66d 100644 +--- a/source4/torture/rpc/schannel.c ++++ b/source4/torture/rpc/schannel.c +@@ -50,7 +50,7 @@ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, + struct netr_NetworkInfo ninfo; + union netr_LogonLevel logon; + union netr_Validation validation; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t _flags = 0; + DATA_BLOB names_blob, chal, lm_resp, nt_resp; + int i; +-- +2.33.1 + + +From 7e3934334f6d532a087db43a308c404d34b81458 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 15/39] CVE-2020-25717: s4:smb_server: start with authoritative + = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/smb_server/smb/sesssetup.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/source4/smb_server/smb/sesssetup.c b/source4/smb_server/smb/sesssetup.c +index 68cdd70feff..8428ca3fabb 100644 +--- a/source4/smb_server/smb/sesssetup.c ++++ b/source4/smb_server/smb/sesssetup.c +@@ -102,7 +102,7 @@ static void sesssetup_old_send(struct tevent_req *subreq) + struct auth_session_info *session_info; + struct smbsrv_session *smb_sess; + NTSTATUS status; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags; + + status = auth_check_password_recv(subreq, req, &user_info_dc, +@@ -243,7 +243,7 @@ static void sesssetup_nt1_send(struct tevent_req *subreq) + struct auth_user_info_dc *user_info_dc = NULL; + struct auth_session_info *session_info; + struct smbsrv_session *smb_sess; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags; + NTSTATUS status; + +-- +2.33.1 + + +From c4a595518b453ecc5c0e2bfe7ba2cf531ea37e13 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 16/39] CVE-2020-25717: s4:auth_simple: start with + authoritative = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/auth/ntlm/auth_simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c +index 8df160cefc3..8301aec519c 100644 +--- a/source4/auth/ntlm/auth_simple.c ++++ b/source4/auth/ntlm/auth_simple.c +@@ -150,7 +150,7 @@ static void authenticate_ldap_simple_bind_done(struct tevent_req *subreq) + const struct tsocket_address *local_address = user_info->local_host; + const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE; + struct auth_user_info_dc *user_info_dc = NULL; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + NTSTATUS nt_status; + +-- +2.33.1 + + +From 0e32b75b21d5daf08fffbe25b6c40197ed04cbf8 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 17/39] CVE-2020-25717: s3:ntlm_auth: start with authoritative + = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/utils/ntlm_auth.c | 4 ++-- + source3/utils/ntlm_auth_diagnostics.c | 10 +++++----- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index 0370803167f..b3ab3a473bf 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -1927,7 +1927,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod + TALLOC_FREE(mem_ctx); + + } else { +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + + if (!domain) { + domain = smb_xstrdup(get_winbind_domain()); +@@ -2443,7 +2443,7 @@ static bool check_auth_crap(void) + char *hex_lm_key; + char *hex_user_session_key; + char *error_string; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + + setbuf(stdout, NULL); + +diff --git a/source3/utils/ntlm_auth_diagnostics.c b/source3/utils/ntlm_auth_diagnostics.c +index 41591a8de33..fc0fc19bacb 100644 +--- a/source3/utils/ntlm_auth_diagnostics.c ++++ b/source3/utils/ntlm_auth_diagnostics.c +@@ -54,7 +54,7 @@ static bool test_lm_ntlm_broken(enum ntlm_break break_which) + DATA_BLOB lm_response = data_blob(NULL, 24); + DATA_BLOB nt_response = data_blob(NULL, 24); + DATA_BLOB session_key = data_blob(NULL, 16); +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uchar lm_key[8]; + uchar user_session_key[16]; + uchar lm_hash[16]; +@@ -177,7 +177,7 @@ static bool test_ntlm_in_lm(void) + NTSTATUS nt_status; + uint32_t flags = 0; + DATA_BLOB nt_response = data_blob(NULL, 24); +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uchar lm_key[8]; + uchar lm_hash[16]; + uchar user_session_key[16]; +@@ -245,7 +245,7 @@ static bool test_ntlm_in_both(void) + uint32_t flags = 0; + DATA_BLOB nt_response = data_blob(NULL, 24); + DATA_BLOB session_key = data_blob(NULL, 16); +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint8_t lm_key[8]; + uint8_t lm_hash[16]; + uint8_t user_session_key[16]; +@@ -322,7 +322,7 @@ static bool test_lmv2_ntlmv2_broken(enum ntlm_break break_which) + DATA_BLOB lmv2_response = data_blob_null; + DATA_BLOB ntlmv2_session_key = data_blob_null; + DATA_BLOB names_blob = NTLMv2_generate_names_blob(NULL, get_winbind_netbios_name(), get_winbind_domain()); +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uchar user_session_key[16]; + DATA_BLOB chall = get_challenge(); + char *error_string; +@@ -452,7 +452,7 @@ static bool test_plaintext(enum ntlm_break break_which) + char *password; + smb_ucs2_t *nt_response_ucs2; + size_t converted_size; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uchar user_session_key[16]; + uchar lm_key[16]; + static const uchar zeros[8] = { 0, }; +-- +2.33.1 + + +From aa52008a73b9960acbb6b39684c5c460480e365b Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 18/39] CVE-2020-25717: s3:torture: start with authoritative = + 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/torture/pdbtest.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c +index 5d74aa9ab78..b300504c4cb 100644 +--- a/source3/torture/pdbtest.c ++++ b/source3/torture/pdbtest.c +@@ -277,7 +277,7 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry) + struct netr_SamInfo6 *info6_wbc = NULL; + NTSTATUS status; + bool ok; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + int rc; + + rc = SMBOWFencrypt(pdb_get_nt_passwd(pdb_entry), challenge_8, +-- +2.33.1 + + +From 9c133372ac3687e9316f1b76fdbcc9d95d54db42 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 19/39] CVE-2020-25717: s3:rpcclient: start with authoritative + = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/rpcclient/cmd_netlogon.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c +index d5c1b91f2be..4ea63e40b8d 100644 +--- a/source3/rpcclient/cmd_netlogon.c ++++ b/source3/rpcclient/cmd_netlogon.c +@@ -496,7 +496,7 @@ static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli, + uint32_t logon_param = 0; + const char *workstation = NULL; + struct netr_SamInfo3 *info3 = NULL; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level; + union netr_Validation *validation = NULL; +-- +2.33.1 + + +From 7a2bf7eb4be1c7988bfe14dbbf297f79a05220ad Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 20/39] CVE-2020-25717: s3:auth: start with authoritative = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 2 +- + source3/auth/auth_samba4.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index e62585e919c..57281874b35 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -416,7 +416,7 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context, + { + NTSTATUS nt_status; + void *server_info; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + struct tevent_context *ev = NULL; + struct tevent_req *subreq = NULL; + bool ok; +diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c +index ac141354747..fde78d5e74e 100644 +--- a/source3/auth/auth_samba4.c ++++ b/source3/auth/auth_samba4.c +@@ -120,7 +120,7 @@ static NTSTATUS check_samba4_security( + NTSTATUS nt_status; + struct auth_user_info_dc *user_info_dc; + struct auth4_context *auth4_context; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + struct auth_serversupplied_info *server_info = NULL; + + nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context); +-- +2.33.1 + + +From 97f2108d84017998d2612139b787fdb674c235e2 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 26 Oct 2021 17:42:41 +0200 +Subject: [PATCH 21/39] CVE-2020-25717: auth/ntlmssp: start with authoritative + = 1 + +This is not strictly needed, but makes it easier to audit +that we don't miss important places. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + auth/ntlmssp/ntlmssp_server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c +index 001238278d7..939aa0ef4aa 100644 +--- a/auth/ntlmssp/ntlmssp_server.c ++++ b/auth/ntlmssp/ntlmssp_server.c +@@ -799,7 +799,7 @@ static void ntlmssp_server_auth_done(struct tevent_req *subreq) + struct gensec_security *gensec_security = state->gensec_security; + struct gensec_ntlmssp_context *gensec_ntlmssp = state->gensec_ntlmssp; + struct auth4_context *auth_context = gensec_security->auth_context; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + NTSTATUS status; + + status = auth_context->check_ntlm_password_recv(subreq, +-- +2.33.1 + + +From 59e3ccaaced1fa3f7db250d44c7e9a94070d583b Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Tue, 28 Sep 2021 10:43:40 +0200 +Subject: [PATCH 22/39] CVE-2020-25717: loadparm: Add new parameter "min domain + uid" + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Samuel Cabrero +Signed-off-by: Stefan Metzmacher + +[abartlet@samba.org Backported from master/4.15 due to + conflicts with other new parameters] +--- + docs-xml/smbdotconf/security/mindomainuid.xml | 17 +++++++++++++++++ + docs-xml/smbdotconf/winbind/idmapconfig.xml | 4 ++++ + lib/param/loadparm.c | 4 ++++ + source3/param/loadparm.c | 2 ++ + 4 files changed, 27 insertions(+) + create mode 100644 docs-xml/smbdotconf/security/mindomainuid.xml + +diff --git a/docs-xml/smbdotconf/security/mindomainuid.xml b/docs-xml/smbdotconf/security/mindomainuid.xml +new file mode 100644 +index 00000000000..46ae795d730 +--- /dev/null ++++ b/docs-xml/smbdotconf/security/mindomainuid.xml +@@ -0,0 +1,17 @@ ++ ++ ++ ++ The integer parameter specifies the minimum uid allowed when mapping a ++ local account to a domain account. ++ ++ ++ ++ Note that this option interacts with the configured idmap ranges! ++ ++ ++ ++1000 ++ +diff --git a/docs-xml/smbdotconf/winbind/idmapconfig.xml b/docs-xml/smbdotconf/winbind/idmapconfig.xml +index 1374040fb29..f70f11df757 100644 +--- a/docs-xml/smbdotconf/winbind/idmapconfig.xml ++++ b/docs-xml/smbdotconf/winbind/idmapconfig.xml +@@ -80,6 +80,9 @@ + authoritative for a unix ID to SID mapping, so it must be set + for each individually configured domain and for the default + configuration. The configured ranges must be mutually disjoint. ++ ++ ++ Note that the low value interacts with the option! + + + +@@ -115,4 +118,5 @@ + + + ++min domain uid + +diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c +index 3548c47d857..eedfa00bcb0 100644 +--- a/lib/param/loadparm.c ++++ b/lib/param/loadparm.c +@@ -3090,6 +3090,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) + "client smb encrypt", + "default"); + ++ lpcfg_do_global_parameter(lp_ctx, ++ "min domain uid", ++ "1000"); ++ + for (i = 0; parm_table[i].label; i++) { + if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { + lp_ctx->flags[i] |= FLAG_DEFAULT; +diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c +index acb4d149f0b..300b539748b 100644 +--- a/source3/param/loadparm.c ++++ b/source3/param/loadparm.c +@@ -967,6 +967,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) + + Globals.client_smb_encrypt = SMB_ENCRYPTION_DEFAULT; + ++ Globals.min_domain_uid = 1000; ++ + /* Now put back the settings that were set with lp_set_cmdline() */ + apply_lp_set_cmdline(); + } +-- +2.33.1 + + +From 977bbda9fed9362bfa46e541c8cdb9666d43b57a Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 19:57:18 +0200 +Subject: [PATCH 23/39] CVE-2020-25717: s3:auth: let + auth3_generate_session_info_pac() forward the low level errors + +Mapping everything to ACCESS_DENIED makes it hard to debug problems, +which may happen because of our more restrictive behaviour in future. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index 57281874b35..f6a501f1df7 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -166,7 +166,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", + nt_errstr(status))); +- status = NT_STATUS_ACCESS_DENIED; ++ status = nt_status_squash(status); + goto done; + } + +-- +2.33.1 + + +From ed88e24afbf85cc6a61c236604f3fc43a10f0d97 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Tue, 28 Sep 2021 10:45:11 +0200 +Subject: [PATCH 24/39] CVE-2020-25717: s3:auth: Check minimum domain uid + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Samuel Cabrero +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Removed knownfail on advice from metze] +--- + source3/auth/auth_util.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 4686b29111e..4de4bc74374 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -2103,6 +2103,22 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, + } + } + goto out; ++ } else if ((lp_security() == SEC_ADS || lp_security() == SEC_DOMAIN) && ++ !is_myname(domain) && pwd->pw_uid < lp_min_domain_uid()) { ++ /* ++ * !is_myname(domain) because when smbd starts tries to setup ++ * the guest user info, calling this function with nobody ++ * username. Nobody is usually uid 65535 but it can be changed ++ * to a regular user with 'guest account' parameter ++ */ ++ nt_status = NT_STATUS_INVALID_TOKEN; ++ DBG_NOTICE("Username '%s%s%s' is invalid on this system, " ++ "it does not meet 'min domain uid' " ++ "restriction (%u < %u): %s\n", ++ nt_domain, lp_winbind_separator(), nt_username, ++ pwd->pw_uid, lp_min_domain_uid(), ++ nt_errstr(nt_status)); ++ goto out; + } + + result = make_server_info(tmp_ctx); +-- +2.33.1 + + +From 51a78934575b47e6add3110904c5de6c97566fd7 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 17:40:30 +0200 +Subject: [PATCH 25/39] CVE-2020-25717: s3:auth: we should not try to + autocreate the guest account + +We should avoid autocreation of users as much as possible. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/user_krb5.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c +index 8998f9c8f8a..074e8c7eb71 100644 +--- a/source3/auth/user_krb5.c ++++ b/source3/auth/user_krb5.c +@@ -155,7 +155,7 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + if (!fuser) { + return NT_STATUS_NO_MEMORY; + } +- pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); ++ pw = smb_getpwnam(mem_ctx, fuser, &unixuser, false); + } + + /* extra sanity check that the guest account is valid */ +-- +2.33.1 + + +From 0ef009b205acf1b14f8763cf2e6ce13ec8bea151 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 18:08:20 +0200 +Subject: [PATCH 26/39] CVE-2020-25717: s3:auth: no longer let check_account() + autocreate local users + +So far we autocreated local user accounts based on just the +account_name (just ignoring any domain part). + +This only happens via a possible 'add user script', +which is not typically defined on domain members +and on NT4 DCs local users already exist in the +local passdb anyway. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 4de4bc74374..99b85d47a5f 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -1898,7 +1898,7 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, + return NT_STATUS_NO_MEMORY; + } + +- passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, true ); ++ passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false); + if (!passwd) { + DEBUG(3, ("Failed to find authenticated user %s via " + "getpwnam(), denying access.\n", dom_user)); +-- +2.33.1 + + +From de475a3eba52cb4599330f6932e98f97c3749ec7 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 8 Oct 2021 12:33:16 +0200 +Subject: [PATCH 27/39] CVE-2020-25717: s3:auth: remove fallbacks in + smb_getpwnam() + +So far we tried getpwnam("DOMAIN\account") first and +always did a fallback to getpwnam("account") completely +ignoring the domain part, this just causes problems +as we mix "DOMAIN1\account", "DOMAIN2\account", +and "account"! + +As we require a running winbindd for domain member setups +we should no longer do a fallback to just "account" for +users served by winbindd! + +For users of the local SAM don't use this code path, +as check_sam_security() doesn't call check_account(). + +The only case where smb_getpwnam("account") happens is +when map_username() via ("username map [script]") mapped +"DOMAIN\account" to something without '\', but that is +explicitly desired by the admin. + +Note: use 'git show -w' + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Ralph Boehme +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/ktest | 26 +++++++++++++ + source3/auth/auth_util.c | 77 +++++++++++++++++++++----------------- + 2 files changed, 68 insertions(+), 35 deletions(-) + create mode 100644 selftest/knownfail.d/ktest + +diff --git a/selftest/knownfail.d/ktest b/selftest/knownfail.d/ktest +new file mode 100644 +index 00000000000..809612ba0b9 +--- /dev/null ++++ b/selftest/knownfail.d/ktest +@@ -0,0 +1,26 @@ ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,packet...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,packet...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,sign...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,sign...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,seal...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,seal...rpcclient.ktest:local ++^samba3.blackbox.smbclient_krb5.old.ccache..smbclient.ktest:local ++^samba3.blackbox.smbclient_krb5.new.ccache..smbclient.ktest:local ++^samba3.blackbox.smbclient_large_file..krb5.smbclient.large.posix.write.read.ktest:local ++^samba3.blackbox.smbclient_large_file..krb5.cmp.of.read.and.written.files.ktest:local ++^samba3.blackbox.smbclient_krb5.old.ccache.--client-protection=encrypt.smbclient.ktest:local ++^samba3.blackbox.smbclient_krb5.new.ccache.--client-protection=encrypt.smbclient.ktest:local ++^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.smbclient.large.posix.write.read.ktest:local ++^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.cmp.of.read.and.written.files.ktest:local +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 99b85d47a5f..d81313a0495 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -1933,7 +1933,7 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, + { + struct passwd *pw = NULL; + char *p = NULL; +- char *username = NULL; ++ const char *username = NULL; + + /* we only save a copy of the username it has been mangled + by winbindd use default domain */ +@@ -1952,48 +1952,55 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, + /* code for a DOMAIN\user string */ + + if ( p ) { +- pw = Get_Pwnam_alloc( mem_ctx, domuser ); +- if ( pw ) { +- /* make sure we get the case of the username correct */ +- /* work around 'winbind use default domain = yes' */ +- +- if ( lp_winbind_use_default_domain() && +- !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { +- char *domain; +- +- /* split the domain and username into 2 strings */ +- *p = '\0'; +- domain = username; +- +- *p_save_username = talloc_asprintf(mem_ctx, +- "%s%c%s", +- domain, +- *lp_winbind_separator(), +- pw->pw_name); +- if (!*p_save_username) { +- TALLOC_FREE(pw); +- return NULL; +- } +- } else { +- *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); +- } ++ const char *domain = NULL; + +- /* whew -- done! */ +- return pw; ++ /* split the domain and username into 2 strings */ ++ *p = '\0'; ++ domain = username; ++ p++; ++ username = p; ++ ++ if (strequal(domain, get_global_sam_name())) { ++ /* ++ * This typically don't happen ++ * as check_sam_Security() ++ * don't call make_server_info_info3() ++ * and thus check_account(). ++ * ++ * But we better keep this. ++ */ ++ goto username_only; + } + +- /* setup for lookup of just the username */ +- /* remember that p and username are overlapping memory */ +- +- p++; +- username = talloc_strdup(mem_ctx, p); +- if (!username) { ++ pw = Get_Pwnam_alloc( mem_ctx, domuser ); ++ if (pw == NULL) { + return NULL; + } ++ /* make sure we get the case of the username correct */ ++ /* work around 'winbind use default domain = yes' */ ++ ++ if ( lp_winbind_use_default_domain() && ++ !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { ++ *p_save_username = talloc_asprintf(mem_ctx, ++ "%s%c%s", ++ domain, ++ *lp_winbind_separator(), ++ pw->pw_name); ++ if (!*p_save_username) { ++ TALLOC_FREE(pw); ++ return NULL; ++ } ++ } else { ++ *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); ++ } ++ ++ /* whew -- done! */ ++ return pw; ++ + } + + /* just lookup a plain username */ +- ++username_only: + pw = Get_Pwnam_alloc(mem_ctx, username); + + /* Create local user if requested but only if winbindd +-- +2.33.1 + + +From debd9501c568ebd536275a240cd796187d1ce39b Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 21 Sep 2021 13:13:52 +0200 +Subject: [PATCH 28/39] CVE-2020-25717: s3:lib: add lp_allow_trusted_domains() + logic to is_allowed_domain() + +is_allowed_domain() is a central place we already use to +trigger NT_STATUS_AUTHENTICATION_FIREWALL_FAILED, so +we can add additional logic there. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/lib/util_names.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/source3/lib/util_names.c b/source3/lib/util_names.c +index 630a25875c7..876035cbe29 100644 +--- a/source3/lib/util_names.c ++++ b/source3/lib/util_names.c +@@ -200,5 +200,18 @@ bool is_allowed_domain(const char *domain_name) + } + } + +- return true; ++ if (lp_allow_trusted_domains()) { ++ return true; ++ } ++ ++ if (strequal(lp_workgroup(), domain_name)) { ++ return true; ++ } ++ ++ if (is_myname(domain_name)) { ++ return true; ++ } ++ ++ DBG_NOTICE("Not trusted domain '%s'\n", domain_name); ++ return false; + } +-- +2.33.1 + + +From d2b7d75eccee7575c3dab25cc8c61e2cf00994d3 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 18:03:55 +0200 +Subject: [PATCH 29/39] CVE-2020-25717: s3:auth: don't let create_local_token + depend on !winbind_ping() + +We always require a running winbindd on a domain member, so +we should better fail a request instead of silently alter +the behaviour, which results in a different unix token, just +because winbindd might be restarted. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_util.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index d81313a0495..065b525500f 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -576,13 +576,11 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx, + } + + /* +- * If winbind is not around, we can not make much use of the SIDs the +- * domain controller provided us with. Likewise if the user name was +- * mapped to some local unix user. ++ * If the user name was mapped to some local unix user, ++ * we can not make much use of the SIDs the ++ * domain controller provided us with. + */ +- +- if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) || +- (server_info->nss_token)) { ++ if (server_info->nss_token) { + char *found_username = NULL; + status = create_token_from_username(session_info, + server_info->unix_name, +-- +2.33.1 + + +From 045a019e452c512224a13cfbd98c592cb7f2e912 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 11 Nov 2020 18:50:45 +0200 +Subject: [PATCH 30/39] CVE-2020-25717: Add FreeIPA domain controller role + +As we want to reduce use of 'classic domain controller' role but FreeIPA +relies on it internally, add a separate role to mark FreeIPA domain +controller role. + +It means that role won't result in ROLE_STANDALONE. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Alexander Bokovoy +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + docs-xml/smbdotconf/security/serverrole.xml | 7 ++++ + lib/param/loadparm_server_role.c | 2 ++ + lib/param/param_table.c | 1 + + lib/param/util.c | 1 + + libcli/netlogon/netlogon.c | 2 +- + libds/common/roles.h | 1 + + source3/auth/auth.c | 3 ++ + source3/auth/auth_sam.c | 14 ++++---- + source3/include/smb_macros.h | 2 +- + source3/lib/netapi/joindomain.c | 1 + + source3/param/loadparm.c | 4 ++- + source3/passdb/lookup_sid.c | 2 +- + source3/passdb/machine_account_secrets.c | 7 ++-- + source3/registry/reg_backend_prod_options.c | 1 + + source3/rpc_server/dssetup/srv_dssetup_nt.c | 1 + + source3/smbd/server.c | 2 +- + source3/winbindd/winbindd_misc.c | 2 +- + source3/winbindd/winbindd_util.c | 40 ++++++++++++++++----- + source4/auth/ntlm/auth.c | 1 + + source4/kdc/kdc-heimdal.c | 1 + + source4/rpc_server/samr/dcesrv_samr.c | 2 ++ + 21 files changed, 72 insertions(+), 25 deletions(-) + +diff --git a/docs-xml/smbdotconf/security/serverrole.xml b/docs-xml/smbdotconf/security/serverrole.xml +index 9511c61c96d..b8b83a127b5 100644 +--- a/docs-xml/smbdotconf/security/serverrole.xml ++++ b/docs-xml/smbdotconf/security/serverrole.xml +@@ -78,6 +78,13 @@ + url="http://wiki.samba.org/index.php/Samba4/HOWTO">Samba4 + HOWTO + ++ SERVER ROLE = IPA DOMAIN CONTROLLER ++ ++ This mode of operation runs Samba in a hybrid mode for IPA ++ domain controller, providing forest trust to Active Directory. ++ This role requires special configuration performed by IPA installers ++ and should not be used manually by any administrator. ++ + + + security +diff --git a/lib/param/loadparm_server_role.c b/lib/param/loadparm_server_role.c +index 7a6bc770723..a78d1ab9cf3 100644 +--- a/lib/param/loadparm_server_role.c ++++ b/lib/param/loadparm_server_role.c +@@ -42,6 +42,7 @@ static const struct srv_role_tab { + { ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" }, + { ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" }, + { ROLE_ACTIVE_DIRECTORY_DC, "ROLE_ACTIVE_DIRECTORY_DC" }, ++ { ROLE_IPA_DC, "ROLE_IPA_DC"}, + { 0, NULL } + }; + +@@ -140,6 +141,7 @@ bool lp_is_security_and_server_role_valid(int server_role, int security) + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: + case ROLE_ACTIVE_DIRECTORY_DC: ++ case ROLE_IPA_DC: + if (security == SEC_USER) { + valid = true; + } +diff --git a/lib/param/param_table.c b/lib/param/param_table.c +index e2f737279dc..3dc5fc59991 100644 +--- a/lib/param/param_table.c ++++ b/lib/param/param_table.c +@@ -111,6 +111,7 @@ static const struct enum_list enum_server_role[] = { + {ROLE_ACTIVE_DIRECTORY_DC, "active directory domain controller"}, + {ROLE_ACTIVE_DIRECTORY_DC, "domain controller"}, + {ROLE_ACTIVE_DIRECTORY_DC, "dc"}, ++ {ROLE_IPA_DC, "IPA primary domain controller"}, + {-1, NULL} + }; + +diff --git a/lib/param/util.c b/lib/param/util.c +index cd8e74b9d8f..9a0fc102de8 100644 +--- a/lib/param/util.c ++++ b/lib/param/util.c +@@ -255,6 +255,7 @@ const char *lpcfg_sam_name(struct loadparm_context *lp_ctx) + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: + case ROLE_ACTIVE_DIRECTORY_DC: ++ case ROLE_IPA_DC: + return lpcfg_workgroup(lp_ctx); + default: + return lpcfg_netbios_name(lp_ctx); +diff --git a/libcli/netlogon/netlogon.c b/libcli/netlogon/netlogon.c +index 239503e85b6..59af460dc4e 100644 +--- a/libcli/netlogon/netlogon.c ++++ b/libcli/netlogon/netlogon.c +@@ -93,7 +93,7 @@ NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx, + if (ndr->offset < ndr->data_size) { + TALLOC_FREE(ndr); + /* +- * We need to handle a bug in FreeIPA (at least <= 4.1.2). ++ * We need to handle a bug in IPA (at least <= 4.1.2). + * + * They include the ip address information without setting + * NETLOGON_NT_VERSION_5EX_WITH_IP, while using +diff --git a/libds/common/roles.h b/libds/common/roles.h +index 4772c8d7d3f..03ba1915b21 100644 +--- a/libds/common/roles.h ++++ b/libds/common/roles.h +@@ -33,6 +33,7 @@ enum server_role { + + /* not in samr.idl */ + ROLE_ACTIVE_DIRECTORY_DC = 4, ++ ROLE_IPA_DC = 5, + + /* To determine the role automatically, this is not a valid role */ + ROLE_AUTO = 100 +diff --git a/source3/auth/auth.c b/source3/auth/auth.c +index 6d2a40f0f29..d0036ea6b30 100644 +--- a/source3/auth/auth.c ++++ b/source3/auth/auth.c +@@ -543,6 +543,7 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, + break; + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: ++ case ROLE_IPA_DC: + role = "'DC'"; + methods = "anonymous sam winbind sam_ignoredomain"; + break; +@@ -574,6 +575,7 @@ NTSTATUS make_auth3_context_for_netlogon(TALLOC_CTX *mem_ctx, + switch (lp_server_role()) { + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: ++ case ROLE_IPA_DC: + methods = "sam_netlogon3 winbind"; + break; + +@@ -595,6 +597,7 @@ NTSTATUS make_auth3_context_for_winbind(TALLOC_CTX *mem_ctx, + case ROLE_DOMAIN_MEMBER: + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: ++ case ROLE_IPA_DC: + methods = "sam"; + break; + case ROLE_ACTIVE_DIRECTORY_DC: +diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c +index e8e0d543f8c..a2ce1013975 100644 +--- a/source3/auth/auth_sam.c ++++ b/source3/auth/auth_sam.c +@@ -143,12 +143,13 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, + break; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + if (!is_local_name && !is_my_domain) { + /* If we are running on a DC that has PASSDB module with domain + * information, check if DNS forest name is matching the domain +- * name. This is the case of FreeIPA domain controller when +- * trusted AD DCs attempt to authenticate FreeIPA users using +- * the forest root domain (which is the only domain in FreeIPA). ++ * name. This is the case of IPA domain controller when ++ * trusted AD DCs attempt to authenticate IPA users using ++ * the forest root domain (which is the only domain in IPA). + */ + struct pdb_domain_info *dom_info = NULL; + +@@ -234,6 +235,7 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, + switch (lp_server_role()) { + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + break; + default: + DBG_ERR("Invalid server role\n"); +@@ -252,9 +254,9 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, + if (!is_my_domain) { + /* If we are running on a DC that has PASSDB module with domain + * information, check if DNS forest name is matching the domain +- * name. This is the case of FreeIPA domain controller when +- * trusted AD DCs attempt to authenticate FreeIPA users using +- * the forest root domain (which is the only domain in FreeIPA). ++ * name. This is the case of IPA domain controller when ++ * trusted AD DCs attempt to authenticate IPA users using ++ * the forest root domain (which is the only domain in IPA). + */ + struct pdb_domain_info *dom_info = NULL; + dom_info = pdb_get_domain_info(mem_ctx); +diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h +index d9583945c55..def122727f0 100644 +--- a/source3/include/smb_macros.h ++++ b/source3/include/smb_macros.h +@@ -203,7 +203,7 @@ copy an IP address from one buffer to another + Check to see if we are a DC for this domain + *****************************************************************************/ + +-#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) ++#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_server_role() == ROLE_IPA_DC) + #define IS_AD_DC (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) + + /* +diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c +index f2d36fc00db..d1710c4b938 100644 +--- a/source3/lib/netapi/joindomain.c ++++ b/source3/lib/netapi/joindomain.c +@@ -375,6 +375,7 @@ WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx, + case ROLE_DOMAIN_MEMBER: + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + *r->out.name_type = NetSetupDomainName; + break; + case ROLE_STANDALONE: +diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c +index 300b539748b..8bcd35f3d88 100644 +--- a/source3/param/loadparm.c ++++ b/source3/param/loadparm.c +@@ -4412,6 +4412,7 @@ int lp_default_server_announce(void) + default_server_announce |= SV_TYPE_DOMAIN_MEMBER; + break; + case ROLE_DOMAIN_PDC: ++ case ROLE_IPA_DC: + default_server_announce |= SV_TYPE_DOMAIN_CTRL; + break; + case ROLE_DOMAIN_BDC: +@@ -4437,7 +4438,8 @@ int lp_default_server_announce(void) + bool lp_domain_master(void) + { + if (Globals._domain_master == Auto) +- return (lp_server_role() == ROLE_DOMAIN_PDC); ++ return (lp_server_role() == ROLE_DOMAIN_PDC || ++ lp_server_role() == ROLE_IPA_DC); + + return (bool)Globals._domain_master; + } +diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c +index 0e01467b3cb..a551bcfd24a 100644 +--- a/source3/passdb/lookup_sid.c ++++ b/source3/passdb/lookup_sid.c +@@ -121,7 +121,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, + + /* If we are running on a DC that has PASSDB module with domain + * information, check if DNS forest name is matching the domain +- * name. This is the case of FreeIPA domain controller when ++ * name. This is the case of IPA domain controller when + * trusted AD DC looks up users found in a Global Catalog of + * the forest root domain. */ + if (!check_global_sam && (IS_DC)) { +diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c +index d81f79c705b..618019b8322 100644 +--- a/source3/passdb/machine_account_secrets.c ++++ b/source3/passdb/machine_account_secrets.c +@@ -198,7 +198,8 @@ bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid) + dyn_guid = (struct GUID *)secrets_fetch(key, &size); + + if (!dyn_guid) { +- if (lp_server_role() == ROLE_DOMAIN_PDC) { ++ if (lp_server_role() == ROLE_DOMAIN_PDC || ++ lp_server_role() == ROLE_IPA_DC) { + new_guid = GUID_random(); + if (!secrets_store_domain_guid(domain, &new_guid)) + return False; +@@ -314,9 +315,7 @@ static const char *trust_keystr(const char *domain) + + enum netr_SchannelType get_default_sec_channel(void) + { +- if (lp_server_role() == ROLE_DOMAIN_BDC || +- lp_server_role() == ROLE_DOMAIN_PDC || +- lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) { ++ if (IS_DC) { + return SEC_CHAN_BDC; + } else { + return SEC_CHAN_WKSTA; +diff --git a/source3/registry/reg_backend_prod_options.c b/source3/registry/reg_backend_prod_options.c +index 655c587ac40..7bd3f324c37 100644 +--- a/source3/registry/reg_backend_prod_options.c ++++ b/source3/registry/reg_backend_prod_options.c +@@ -40,6 +40,7 @@ static int prod_options_fetch_values(const char *key, struct regval_ctr *regvals + switch (lp_server_role()) { + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + value_ascii = "LanmanNT"; + break; + case ROLE_STANDALONE: +diff --git a/source3/rpc_server/dssetup/srv_dssetup_nt.c b/source3/rpc_server/dssetup/srv_dssetup_nt.c +index 64569382695..932452bc13b 100644 +--- a/source3/rpc_server/dssetup/srv_dssetup_nt.c ++++ b/source3/rpc_server/dssetup/srv_dssetup_nt.c +@@ -63,6 +63,7 @@ static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, + basic->domain = get_global_sam_name(); + break; + case ROLE_DOMAIN_PDC: ++ case ROLE_IPA_DC: + basic->role = DS_ROLE_PRIMARY_DC; + basic->domain = get_global_sam_name(); + break; +diff --git a/source3/smbd/server.c b/source3/smbd/server.c +index a0456100afe..26961fa6cf4 100644 +--- a/source3/smbd/server.c ++++ b/source3/smbd/server.c +@@ -1979,7 +1979,7 @@ extern void build_options(bool screen); + exit_daemon("smbd can not open secrets.tdb", EACCES); + } + +- if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { ++ if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC || lp_server_role() == ROLE_IPA_DC) { + struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); + if (!open_schannel_session_store(NULL, lp_ctx)) { + exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES); +diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c +index 451ad6aee14..db7e1c87dee 100644 +--- a/source3/winbindd/winbindd_misc.c ++++ b/source3/winbindd/winbindd_misc.c +@@ -76,7 +76,7 @@ static char *get_trust_type_string(TALLOC_CTX *mem_ctx, + case SEC_CHAN_BDC: { + int role = lp_server_role(); + +- if (role == ROLE_DOMAIN_PDC) { ++ if (role == ROLE_DOMAIN_PDC || role == ROLE_IPA_DC) { + s = talloc_strdup(mem_ctx, "PDC"); + if (s == NULL) { + return NULL; +diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c +index ac4cd731c09..42ddbfd2f44 100644 +--- a/source3/winbindd/winbindd_util.c ++++ b/source3/winbindd/winbindd_util.c +@@ -1254,15 +1254,37 @@ bool init_domain_list(void) + secure_channel_type = SEC_CHAN_LOCAL; + } + +- status = add_trusted_domain(get_global_sam_name(), +- NULL, +- get_global_sam_sid(), +- LSA_TRUST_TYPE_DOWNLEVEL, +- trust_flags, +- 0, /* trust_attribs */ +- secure_channel_type, +- NULL, +- &domain); ++ if ((pdb_domain_info != NULL) && (role == ROLE_IPA_DC)) { ++ /* This is IPA DC that presents itself as ++ * an Active Directory domain controller to trusted AD ++ * forests but in fact is a classic domain controller. ++ */ ++ trust_flags = NETR_TRUST_FLAG_PRIMARY; ++ trust_flags |= NETR_TRUST_FLAG_IN_FOREST; ++ trust_flags |= NETR_TRUST_FLAG_NATIVE; ++ trust_flags |= NETR_TRUST_FLAG_OUTBOUND; ++ trust_flags |= NETR_TRUST_FLAG_TREEROOT; ++ status = add_trusted_domain(pdb_domain_info->name, ++ pdb_domain_info->dns_domain, ++ &pdb_domain_info->sid, ++ LSA_TRUST_TYPE_UPLEVEL, ++ trust_flags, ++ LSA_TRUST_ATTRIBUTE_WITHIN_FOREST, ++ secure_channel_type, ++ NULL, ++ &domain); ++ TALLOC_FREE(pdb_domain_info); ++ } else { ++ status = add_trusted_domain(get_global_sam_name(), ++ NULL, ++ get_global_sam_sid(), ++ LSA_TRUST_TYPE_DOWNLEVEL, ++ trust_flags, ++ 0, /* trust_attribs */ ++ secure_channel_type, ++ NULL, ++ &domain); ++ } + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("Failed to add local SAM to " + "domain to winbindd's internal list\n"); +diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c +index 4c66f2c23cb..ea9ff70ce80 100644 +--- a/source4/auth/ntlm/auth.c ++++ b/source4/auth/ntlm/auth.c +@@ -737,6 +737,7 @@ const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context * + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: + case ROLE_ACTIVE_DIRECTORY_DC: ++ case ROLE_IPA_DC: + auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL); + break; + } +diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c +index a3c357ca1a6..ba74df4f2ec 100644 +--- a/source4/kdc/kdc-heimdal.c ++++ b/source4/kdc/kdc-heimdal.c +@@ -276,6 +276,7 @@ static NTSTATUS kdc_task_init(struct task_server *task) + return NT_STATUS_INVALID_DOMAIN_ROLE; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + task_server_terminate( + task, "Cannot start KDC as a 'classic Samba' DC", false); + return NT_STATUS_INVALID_DOMAIN_ROLE; +diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c +index cda887d45ee..29c509522be 100644 +--- a/source4/rpc_server/samr/dcesrv_samr.c ++++ b/source4/rpc_server/samr/dcesrv_samr.c +@@ -575,6 +575,7 @@ static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state + break; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + case ROLE_AUTO: + return NT_STATUS_INTERNAL_ERROR; + case ROLE_DOMAIN_MEMBER: +@@ -723,6 +724,7 @@ static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state, + break; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + case ROLE_AUTO: + return NT_STATUS_INTERNAL_ERROR; + case ROLE_DOMAIN_MEMBER: +-- +2.33.1 + + +From 4b3a3fa914b79c548100eda1baa5c589fd8f04bf Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 18:11:57 +0200 +Subject: [PATCH 31/39] CVE-2020-25719 CVE-2020-25717: auth/gensec: always + require a PAC in domain mode (DC or member) + +AD domains always provide a PAC unless UF_NO_AUTH_DATA_REQUIRED is set +on the service account, which can only be explicitly configured, +but that's an invalid configuration! + +We still try to support standalone servers in an MIT realm, +as legacy setup. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[jsutton@samba.org Removed knownfail entries] +--- + auth/gensec/gensec_util.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c +index e185acc0c20..694661b53b5 100644 +--- a/auth/gensec/gensec_util.c ++++ b/auth/gensec/gensec_util.c +@@ -25,6 +25,8 @@ + #include "auth/gensec/gensec_internal.h" + #include "auth/common_auth.h" + #include "../lib/util/asn1.h" ++#include "param/param.h" ++#include "libds/common/roles.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -46,10 +48,27 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, + session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; + + if (!pac_blob) { +- if (gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { +- DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", +- principal_string)); +- return NT_STATUS_ACCESS_DENIED; ++ enum server_role server_role = ++ lpcfg_server_role(gensec_security->settings->lp_ctx); ++ ++ /* ++ * For any domain setup (DC or member) we require having ++ * a PAC, as the service ticket comes from an AD DC, ++ * which will always provide a PAC, unless ++ * UF_NO_AUTH_DATA_REQUIRED is configured for our ++ * account, but that's just an invalid configuration, ++ * the admin configured for us! ++ * ++ * As a legacy case, we still allow kerberos tickets from an MIT ++ * realm, but only in standalone mode. In that mode we'll only ++ * ever accept a kerberos authentication with a keytab file ++ * being explicitly configured via the 'keytab method' option. ++ */ ++ if (server_role != ROLE_STANDALONE) { ++ DBG_WARNING("Unable to find PAC in ticket from %s, " ++ "failing to allow access\n", ++ principal_string); ++ return NT_STATUS_NO_IMPERSONATION_TOKEN; + } + DBG_NOTICE("Unable to find PAC for %s, resorting to local " + "user lookup\n", principal_string); +-- +2.33.1 + + +From 5b7e9cc45370601553e464e539d0243eeec98659 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 11 Oct 2021 23:17:19 +0200 +Subject: [PATCH 32/39] CVE-2020-25719 CVE-2020-25717: s4:auth: remove unused + auth_generate_session_info_principal() + +We'll require a PAC at the main gensec layer already. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/auth/auth.h | 8 ------ + source4/auth/ntlm/auth.c | 49 ++++-------------------------------- + source4/auth/ntlm/auth_sam.c | 12 --------- + 3 files changed, 5 insertions(+), 64 deletions(-) + +diff --git a/source4/auth/auth.h b/source4/auth/auth.h +index 3f9fb1ae3cb..6b7db99cbe2 100644 +--- a/source4/auth/auth.h ++++ b/source4/auth/auth.h +@@ -69,14 +69,6 @@ struct auth_operations { + TALLOC_CTX *mem_ctx, + struct auth_user_info_dc **interim_info, + bool *authoritative); +- +- /* Lookup a 'session info interim' return based only on the principal or DN */ +- NTSTATUS (*get_user_info_dc_principal)(TALLOC_CTX *mem_ctx, +- struct auth4_context *auth_context, +- const char *principal, +- struct ldb_dn *user_dn, +- struct auth_user_info_dc **interim_info); +- uint32_t flags; + }; + + struct auth_method_context { +diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c +index ea9ff70ce80..3dd2ffc9276 100644 +--- a/source4/auth/ntlm/auth.c ++++ b/source4/auth/ntlm/auth.c +@@ -86,48 +86,6 @@ _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t cha + return NT_STATUS_OK; + } + +-/**************************************************************************** +-Used in the gensec_gssapi and gensec_krb5 server-side code, where the +-PAC isn't available, and for tokenGroups in the DSDB stack. +- +- Supply either a principal or a DN +-****************************************************************************/ +-static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx, +- TALLOC_CTX *mem_ctx, +- const char *principal, +- struct ldb_dn *user_dn, +- uint32_t session_info_flags, +- struct auth_session_info **session_info) +-{ +- NTSTATUS nt_status; +- struct auth_method_context *method; +- struct auth_user_info_dc *user_info_dc; +- +- for (method = auth_ctx->methods; method; method = method->next) { +- if (!method->ops->get_user_info_dc_principal) { +- continue; +- } +- +- nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc); +- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { +- continue; +- } +- if (!NT_STATUS_IS_OK(nt_status)) { +- return nt_status; +- } +- +- nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx, +- user_info_dc, +- user_info_dc->info->account_name, +- session_info_flags, session_info); +- talloc_free(user_info_dc); +- +- return nt_status; +- } +- +- return NT_STATUS_NOT_IMPLEMENTED; +-} +- + /** + * Check a user's Plaintext, LM or NTLM password. + * (sync version) +@@ -627,8 +585,11 @@ static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx, + TALLOC_CTX *tmp_ctx; + + if (!pac_blob) { +- return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name, +- NULL, session_info_flags, session_info); ++ /* ++ * This should already be catched at the main ++ * gensec layer, but better check twice ++ */ ++ return NT_STATUS_INTERNAL_ERROR; + } + + tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context"); +diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c +index a521bc94bc4..dbbf97665db 100644 +--- a/source4/auth/ntlm/auth_sam.c ++++ b/source4/auth/ntlm/auth_sam.c +@@ -938,22 +938,11 @@ static NTSTATUS authsam_want_check(struct auth_method_context *ctx, + return NT_STATUS_OK; + } + +-/* Wrapper for the auth subsystem pointer */ +-static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx, +- struct auth4_context *auth_context, +- const char *principal, +- struct ldb_dn *user_dn, +- struct auth_user_info_dc **user_info_dc) +-{ +- return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx, +- principal, user_dn, user_info_dc); +-} + static const struct auth_operations sam_ignoredomain_ops = { + .name = "sam_ignoredomain", + .want_check = authsam_ignoredomain_want_check, + .check_password_send = authsam_check_password_send, + .check_password_recv = authsam_check_password_recv, +- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + }; + + static const struct auth_operations sam_ops = { +@@ -961,7 +950,6 @@ static const struct auth_operations sam_ops = { + .want_check = authsam_want_check, + .check_password_send = authsam_check_password_send, + .check_password_recv = authsam_check_password_recv, +- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + }; + + _PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *); +-- +2.33.1 + + +From 85914f7dbe62cb0092f106ee89a4cff46b91fb3e Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 21 Sep 2021 12:27:28 +0200 +Subject: [PATCH 33/39] CVE-2020-25717: s3:ntlm_auth: fix memory leaks in + ntlm_auth_generate_session_info_pac() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/utils/ntlm_auth.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index b3ab3a473bf..16431771e74 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -818,23 +818,27 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + if (!p) { + DEBUG(3, ("[%s] Doesn't look like a valid principal\n", + princ_name)); +- return NT_STATUS_LOGON_FAILURE; ++ status = NT_STATUS_LOGON_FAILURE; ++ goto done; + } + + user = talloc_strndup(mem_ctx, princ_name, p - princ_name); + if (!user) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + + realm = talloc_strdup(talloc_tos(), p + 1); + if (!realm) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + + if (!strequal(realm, lp_realm())) { + DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); + if (!lp_allow_trusted_domains()) { +- return NT_STATUS_LOGON_FAILURE; ++ status = NT_STATUS_LOGON_FAILURE; ++ goto done; + } + } + +@@ -842,7 +846,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + domain = talloc_strdup(mem_ctx, + logon_info->info3.base.logon_domain.string); + if (!domain) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); + } else { +@@ -872,7 +877,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + domain = talloc_strdup(mem_ctx, realm); + } + if (!domain) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); + } +-- +2.33.1 + + +From 128802ff973fd3a3089e672f7d81c517a779c6be Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 21 Sep 2021 12:44:01 +0200 +Subject: [PATCH 34/39] CVE-2020-25717: s3:ntlm_auth: let + ntlm_auth_generate_session_info_pac() base the name on the PAC LOGON_INFO + only + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/utils/ntlm_auth.c | 91 ++++++++++++--------------------------- + 1 file changed, 28 insertions(+), 63 deletions(-) + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index 16431771e74..02a23792890 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -790,10 +790,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + struct PAC_LOGON_INFO *logon_info = NULL; + char *unixuser; + NTSTATUS status; +- char *domain = NULL; +- char *realm = NULL; +- char *user = NULL; +- char *p; ++ const char *domain = ""; ++ const char *user = ""; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { +@@ -810,79 +808,46 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- } +- +- DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); +- +- p = strchr_m(princ_name, '@'); +- if (!p) { +- DEBUG(3, ("[%s] Doesn't look like a valid principal\n", +- princ_name)); +- status = NT_STATUS_LOGON_FAILURE; ++ } else { ++ status = NT_STATUS_ACCESS_DENIED; ++ DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n", ++ princ_name, nt_errstr(status)); + goto done; + } + +- user = talloc_strndup(mem_ctx, princ_name, p - princ_name); +- if (!user) { +- status = NT_STATUS_NO_MEMORY; +- goto done; ++ if (logon_info->info3.base.account_name.string != NULL) { ++ user = logon_info->info3.base.account_name.string; ++ } else { ++ user = ""; ++ } ++ if (logon_info->info3.base.logon_domain.string != NULL) { ++ domain = logon_info->info3.base.logon_domain.string; ++ } else { ++ domain = ""; + } + +- realm = talloc_strdup(talloc_tos(), p + 1); +- if (!realm) { +- status = NT_STATUS_NO_MEMORY; ++ if (strlen(user) == 0 || strlen(domain) == 0) { ++ status = NT_STATUS_ACCESS_DENIED; ++ DBG_WARNING("Kerberos ticket for[%s] has invalid " ++ "account_name[%s]/logon_domain[%s]: %s\n", ++ princ_name, ++ logon_info->info3.base.account_name.string, ++ logon_info->info3.base.logon_domain.string, ++ nt_errstr(status)); + goto done; + } + +- if (!strequal(realm, lp_realm())) { +- DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); ++ DBG_NOTICE("Kerberos ticket principal name is [%s] " ++ "account_name[%s]/logon_domain[%s]\n", ++ princ_name, user, domain); ++ ++ if (!strequal(domain, lp_workgroup())) { + if (!lp_allow_trusted_domains()) { + status = NT_STATUS_LOGON_FAILURE; + goto done; + } + } + +- if (logon_info && logon_info->info3.base.logon_domain.string) { +- domain = talloc_strdup(mem_ctx, +- logon_info->info3.base.logon_domain.string); +- if (!domain) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); +- } else { +- +- /* If we have winbind running, we can (and must) shorten the +- username by using the short netbios name. Otherwise we will +- have inconsistent user names. With Kerberos, we get the +- fully qualified realm, with ntlmssp we get the short +- name. And even w2k3 does use ntlmssp if you for example +- connect to an ip address. */ +- +- wbcErr wbc_status; +- struct wbcDomainInfo *info = NULL; +- +- DEBUG(10, ("Mapping [%s] to short name using winbindd\n", +- realm)); +- +- wbc_status = wbcDomainInfo(realm, &info); +- +- if (WBC_ERROR_IS_OK(wbc_status)) { +- domain = talloc_strdup(mem_ctx, +- info->short_name); +- wbcFreeMemory(info); +- } else { +- DEBUG(3, ("Could not find short name: %s\n", +- wbcErrorString(wbc_status))); +- domain = talloc_strdup(mem_ctx, realm); +- } +- if (!domain) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); +- } +- + unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user); + if (!unixuser) { + status = NT_STATUS_NO_MEMORY; +-- +2.33.1 + + +From e9063c114461ac82c5db3fa32f59b57a87be65be Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 19:42:20 +0200 +Subject: [PATCH 35/39] CVE-2020-25717: s3:auth: let + auth3_generate_session_info_pac() delegate everything to + make_server_info_wbcAuthUserInfo() + +This consolidates the code paths used for NTLMSSP and Kerberos! + +I checked what we were already doing for NTLMSSP, which is this: + +a) source3/auth/auth_winbind.c calls wbcAuthenticateUserEx() +b) as a domain member we require a valid response from winbindd, + otherwise we'll return NT_STATUS_NO_LOGON_SERVERS +c) we call make_server_info_wbcAuthUserInfo(), which internally + calls make_server_info_info3() +d) auth_check_ntlm_password() calls + smb_pam_accountcheck(unix_username, rhost), where rhost + is only an ipv4 or ipv6 address (without reverse dns lookup) +e) from auth3_check_password_send/auth3_check_password_recv() + server_returned_info will be passed to auth3_generate_session_info(), + triggered by gensec_session_info(), which means we'll call into + create_local_token() in order to transform auth_serversupplied_info + into auth_session_info. + +For Kerberos gensec_session_info() will call +auth3_generate_session_info_pac() via the gensec_generate_session_info_pac() +helper function. The current logic is this: + +a) gensec_generate_session_info_pac() is the function that + evaluates the 'gensec:require_pac', which defaulted to 'no' + before. +b) auth3_generate_session_info_pac() called + wbcAuthenticateUserEx() in order to pass the PAC blob + to winbindd, but only to prime its cache, e.g. netsamlogon cache + and others. Most failures were just ignored. +c) If the PAC blob is available, it extracted the PAC_LOGON_INFO + from it. +d) Then we called the horrible get_user_from_kerberos_info() function: + - It uses a first part of the tickets principal name (before the @) + as username and combines that with the 'logon_info->base.logon_domain' + if the logon_info (PAC) is present. + - As a fallback without a PAC it's tries to ask winbindd for a mapping + from realm to netbios domain name. + - Finally is falls back to using the realm as netbios domain name + With this information is builds 'userdomain+winbind_separator+useraccount' + and calls map_username() followed by smb_getpwnam() with create=true, + Note this is similar to the make_server_info_info3() => check_account() + => smb_getpwnam() logic under 3. + - It also calls smb_pam_accountcheck(), but may pass the reverse DNS lookup name + instead of the ip address as rhost. + - It does some MAP_TO_GUEST_ON_BAD_UID logic and auto creates the + guest account. +e) We called create_info3_from_pac_logon_info() +f) make_session_info_krb5() calls gets called and triggers this: + - If get_user_from_kerberos_info() mapped to guest, it calls + make_server_info_guest() + - If create_info3_from_pac_logon_info() created a info3 from logon_info, + it calls make_server_info_info3() + - Without a PAC it tries pdb_getsampwnam()/make_server_info_sam() with + a fallback to make_server_info_pw() + From there it calls create_local_token() + +I tried to change auth3_generate_session_info_pac() to behave similar +to auth_winbind.c together with auth3_generate_session_info() as +a domain member, as we now rely on a PAC: + +a) As domain member we require a PAC and always call wbcAuthenticateUserEx() + and require a valid response! +b) we call make_server_info_wbcAuthUserInfo(), which internally + calls make_server_info_info3(). Note make_server_info_info3() + handles MAP_TO_GUEST_ON_BAD_UID and make_server_info_guest() + internally. +c) Similar to auth_check_ntlm_password() we now call + smb_pam_accountcheck(unix_username, rhost), where rhost + is only an ipv4 or ipv6 address (without reverse dns lookup) +d) From there it calls create_local_token() + +As standalone server (in an MIT realm) we continue +with the already existing code logic, which works without a PAC: +a) we keep smb_getpwnam() with create=true logic as it + also requires an explicit 'add user script' option. +b) In the following commits we assert that there's + actually no PAC in this mode, which means we can + remove unused and confusing code. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14646 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 137 ++++++++++++++++++++++++++++-------- + 1 file changed, 109 insertions(+), 28 deletions(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index f6a501f1df7..a8390b1b156 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -46,6 +46,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + uint32_t session_info_flags, + struct auth_session_info **session_info) + { ++ enum server_role server_role = lp_server_role(); + TALLOC_CTX *tmp_ctx; + struct PAC_LOGON_INFO *logon_info = NULL; + struct netr_SamInfo3 *info3_copy = NULL; +@@ -54,39 +55,59 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + char *ntuser; + char *ntdomain; + char *username; +- char *rhost; ++ const char *rhost; + struct passwd *pw; + NTSTATUS status; +- int rc; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + +- if (pac_blob) { +-#ifdef HAVE_KRB5 ++ if (tsocket_address_is_inet(remote_address, "ip")) { ++ rhost = tsocket_address_inet_addr_string( ++ remote_address, tmp_ctx); ++ if (rhost == NULL) { ++ status = NT_STATUS_NO_MEMORY; ++ goto done; ++ } ++ } else { ++ rhost = "127.0.0.1"; ++ } ++ ++ if (server_role != ROLE_STANDALONE) { + struct wbcAuthUserParams params = { 0 }; + struct wbcAuthUserInfo *info = NULL; + struct wbcAuthErrorInfo *err = NULL; ++ struct auth_serversupplied_info *server_info = NULL; ++ char *original_user_name = NULL; ++ char *p = NULL; + wbcErr wbc_err; + ++ if (pac_blob == NULL) { ++ /* ++ * This should already be catched at the main ++ * gensec layer, but better check twice ++ */ ++ status = NT_STATUS_INTERNAL_ERROR; ++ goto done; ++ } ++ + /* + * Let winbind decode the PAC. + * This will also store the user + * data in the netsamlogon cache. + * +- * We need to do this *before* we +- * call get_user_from_kerberos_info() +- * as that does a user lookup that +- * expects info in the netsamlogon cache. +- * +- * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=11259 ++ * This used to be a cache prime ++ * optimization, but now we delegate ++ * all logic to winbindd, as we require ++ * winbindd as domain member anyway. + */ + params.level = WBC_AUTH_USER_LEVEL_PAC; + params.password.pac.data = pac_blob->data; + params.password.pac.length = pac_blob->length; + ++ /* we are contacting the privileged pipe */ + become_root(); + wbc_err = wbcAuthenticateUserEx(¶ms, &info, &err); + unbecome_root(); +@@ -99,18 +120,90 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + */ + + switch (wbc_err) { +- case WBC_ERR_WINBIND_NOT_AVAILABLE: + case WBC_ERR_SUCCESS: + break; ++ case WBC_ERR_WINBIND_NOT_AVAILABLE: ++ status = NT_STATUS_NO_LOGON_SERVERS; ++ DBG_ERR("winbindd not running - " ++ "but required as domain member: %s\n", ++ nt_errstr(status)); ++ goto done; + case WBC_ERR_AUTH_ERROR: + status = NT_STATUS(err->nt_status); + wbcFreeMemory(err); + goto done; ++ case WBC_ERR_NO_MEMORY: ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + default: + status = NT_STATUS_LOGON_FAILURE; + goto done; + } + ++ status = make_server_info_wbcAuthUserInfo(tmp_ctx, ++ info->account_name, ++ info->domain_name, ++ info, &server_info); ++ if (!NT_STATUS_IS_OK(status)) { ++ DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n", ++ nt_errstr(status))); ++ goto done; ++ } ++ ++ /* We skip doing this step if the caller asked us not to */ ++ if (!(server_info->guest)) { ++ const char *unix_username = server_info->unix_name; ++ ++ /* We might not be root if we are an RPC call */ ++ become_root(); ++ status = smb_pam_accountcheck(unix_username, rhost); ++ unbecome_root(); ++ ++ if (!NT_STATUS_IS_OK(status)) { ++ DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] " ++ "FAILED with error %s\n", ++ unix_username, nt_errstr(status))); ++ goto done; ++ } ++ ++ DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] " ++ "succeeded\n", unix_username)); ++ } ++ ++ DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); ++ ++ p = strchr_m(princ_name, '@'); ++ if (!p) { ++ DEBUG(3, ("[%s] Doesn't look like a valid principal\n", ++ princ_name)); ++ status = NT_STATUS_LOGON_FAILURE; ++ goto done; ++ } ++ ++ original_user_name = talloc_strndup(tmp_ctx, princ_name, p - princ_name); ++ if (original_user_name == NULL) { ++ status = NT_STATUS_NO_MEMORY; ++ goto done; ++ } ++ ++ status = create_local_token(mem_ctx, ++ server_info, ++ NULL, ++ original_user_name, ++ session_info); ++ if (!NT_STATUS_IS_OK(status)) { ++ DEBUG(10, ("create_local_token failed: %s\n", ++ nt_errstr(status))); ++ goto done; ++ } ++ ++ goto session_info_ready; ++ } ++ ++ /* This is the standalone legacy code path */ ++ ++ if (pac_blob != NULL) { ++#ifdef HAVE_KRB5 + status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL, + NULL, NULL, 0, &logon_info); + #else +@@ -121,22 +214,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + } + } + +- rc = get_remote_hostname(remote_address, +- &rhost, +- tmp_ctx); +- if (rc < 0) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- if (strequal(rhost, "UNKNOWN")) { +- rhost = tsocket_address_inet_addr_string(remote_address, +- tmp_ctx); +- if (rhost == NULL) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- } +- + status = get_user_from_kerberos_info(tmp_ctx, rhost, + princ_name, logon_info, + &is_mapped, &is_guest, +@@ -170,6 +247,8 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + goto done; + } + ++session_info_ready: ++ + /* setup the string used by %U */ + set_current_user_info((*session_info)->unix_info->sanitized_username, + (*session_info)->unix_info->unix_name, +@@ -179,7 +258,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + lp_load_with_shares(get_dyn_CONFIGFILE()); + + DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n", +- ntuser, ntdomain, rhost)); ++ (*session_info)->info->account_name, ++ (*session_info)->info->domain_name, ++ rhost)); + + status = NT_STATUS_OK; + +-- +2.33.1 + + +From a05d4ea28d68fda457c12a66052cb3712939279a Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 17:14:01 +0200 +Subject: [PATCH 36/39] CVE-2020-25717: selftest: configure 'ktest' env with + winbindd and idmap_autorid + +The 'ktest' environment was/is designed to test kerberos in an active +directory member setup. It was created at a time we wanted to test +smbd/winbindd with kerberos without having the source4 ad dc available. + +This still applies to testing the build with system krb5 libraries +but without relying on a running ad dc. + +As a domain member setup requires a running winbindd, we should test it +that way, in order to reflect a valid setup. + +As a side effect it provides a way to demonstrate that we can accept +smb connections authenticated via kerberos, but no connection to +a domain controller! In order get this working offline, we need an +idmap backend with ID_TYPE_BOTH support, so we use 'autorid', which +should be the default choice. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14646 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/ktest | 26 -------------------------- + selftest/target/Samba3.pm | 12 +++++------- + 2 files changed, 5 insertions(+), 33 deletions(-) + delete mode 100644 selftest/knownfail.d/ktest + +diff --git a/selftest/knownfail.d/ktest b/selftest/knownfail.d/ktest +deleted file mode 100644 +index 809612ba0b9..00000000000 +--- a/selftest/knownfail.d/ktest ++++ /dev/null +@@ -1,26 +0,0 @@ +-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5...rpcclient.ktest:local +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5...rpcclient.ktest:local +-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,packet...rpcclient.ktest:local +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,packet...rpcclient.ktest:local +-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,sign...rpcclient.ktest:local +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,sign...rpcclient.ktest:local +-^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest +-^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,seal...rpcclient.ktest:local +-^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,seal...rpcclient.ktest:local +-^samba3.blackbox.smbclient_krb5.old.ccache..smbclient.ktest:local +-^samba3.blackbox.smbclient_krb5.new.ccache..smbclient.ktest:local +-^samba3.blackbox.smbclient_large_file..krb5.smbclient.large.posix.write.read.ktest:local +-^samba3.blackbox.smbclient_large_file..krb5.cmp.of.read.and.written.files.ktest:local +-^samba3.blackbox.smbclient_krb5.old.ccache.--client-protection=encrypt.smbclient.ktest:local +-^samba3.blackbox.smbclient_krb5.new.ccache.--client-protection=encrypt.smbclient.ktest:local +-^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.smbclient.large.posix.write.read.ktest:local +-^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.cmp.of.read.and.written.files.ktest:local +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 5c0f71757ef..577e3170daa 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -1675,7 +1675,6 @@ sub setup_ktest + workgroup = KTEST + realm = ktest.samba.example.com + security = ads +- username map = $prefix/lib/username.map + server signing = required + server min protocol = SMB3_00 + client max protocol = SMB3 +@@ -1683,6 +1682,10 @@ sub setup_ktest + # This disables NTLM auth against the local SAM, which + # we use can then test this setting by. + ntlm auth = disabled ++ ++ idmap config * : backend = autorid ++ idmap config * : range = 1000000-1999999 ++ idmap config * : rangesize = 100000 + "; + + my $ret = $self->provision( +@@ -1708,12 +1711,6 @@ sub setup_ktest + + $ret->{KRB5_CONFIG} = $ctx->{krb5_conf}; + +- open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map"); +- print USERMAP " +-$ret->{USERNAME} = KTEST\\Administrator +-"; +- close(USERMAP); +- + #This is the secrets.tdb created by 'net ads join' from Samba3 to a + #Samba4 DC with the same parameters as are being used here. The + #domain SID is S-1-5-21-1071277805-689288055-3486227160 +@@ -1765,6 +1762,7 @@ $ret->{USERNAME} = KTEST\\Administrator + if (not $self->check_or_start( + env_vars => $ret, + nmbd => "yes", ++ winbindd => "offline", + smbd => "yes")) { + return undef; + } +-- +2.33.1 + + +From 0d821434ccdccad38659d76b54159b6335e351c5 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 18:12:49 +0200 +Subject: [PATCH 37/39] CVE-2020-25717: s3:auth: let + auth3_generate_session_info_pac() reject a PAC in standalone mode + +We should be strict in standalone mode, that we only support MIT realms +without a PAC in order to keep the code sane. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 29 +++++++++-------------------- + 1 file changed, 9 insertions(+), 20 deletions(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index a8390b1b156..babda46fc92 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -48,8 +48,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + { + enum server_role server_role = lp_server_role(); + TALLOC_CTX *tmp_ctx; +- struct PAC_LOGON_INFO *logon_info = NULL; +- struct netr_SamInfo3 *info3_copy = NULL; + bool is_mapped; + bool is_guest; + char *ntuser; +@@ -203,19 +201,20 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + /* This is the standalone legacy code path */ + + if (pac_blob != NULL) { +-#ifdef HAVE_KRB5 +- status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL, +- NULL, NULL, 0, &logon_info); +-#else +- status = NT_STATUS_ACCESS_DENIED; +-#endif ++ /* ++ * In standalone mode we don't expect a PAC! ++ * we only support MIT realms ++ */ ++ status = NT_STATUS_BAD_TOKEN_TYPE; ++ DBG_WARNING("Unexpected PAC for [%s] in standalone mode - %s\n", ++ princ_name, nt_errstr(status)); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + + status = get_user_from_kerberos_info(tmp_ctx, rhost, +- princ_name, logon_info, ++ princ_name, NULL, + &is_mapped, &is_guest, + &ntuser, &ntdomain, + &username, &pw); +@@ -226,19 +225,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + goto done; + } + +- /* Get the info3 from the PAC data if we have it */ +- if (logon_info) { +- status = create_info3_from_pac_logon_info(tmp_ctx, +- logon_info, +- &info3_copy); +- if (!NT_STATUS_IS_OK(status)) { +- goto done; +- } +- } +- + status = make_session_info_krb5(mem_ctx, + ntuser, ntdomain, username, pw, +- info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, ++ NULL, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, + session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", +-- +2.33.1 + + +From 2292c83cc012473d6729e578ec5a84d6be415fab Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 17:59:59 +0200 +Subject: [PATCH 38/39] CVE-2020-25717: s3:auth: simplify + get_user_from_kerberos_info() by removing the unused logon_info argument + +This code is only every called in standalone mode on a MIT realm, +it means we never have a PAC and we also don't have winbindd arround. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 2 +- + source3/auth/proto.h | 1 - + source3/auth/user_krb5.c | 57 +++++++------------------------------ + 3 files changed, 11 insertions(+), 49 deletions(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index babda46fc92..8923aec0a4d 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -214,7 +214,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + } + + status = get_user_from_kerberos_info(tmp_ctx, rhost, +- princ_name, NULL, ++ princ_name, + &is_mapped, &is_guest, + &ntuser, &ntdomain, + &username, &pw); +diff --git a/source3/auth/proto.h b/source3/auth/proto.h +index 097b17fee44..46fae447347 100644 +--- a/source3/auth/proto.h ++++ b/source3/auth/proto.h +@@ -423,7 +423,6 @@ struct PAC_LOGON_INFO; + NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + const char *cli_name, + const char *princ_name, +- struct PAC_LOGON_INFO *logon_info, + bool *is_mapped, + bool *mapped_to_guest, + char **ntuser, +diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c +index 074e8c7eb71..7b69ca6c222 100644 +--- a/source3/auth/user_krb5.c ++++ b/source3/auth/user_krb5.c +@@ -31,7 +31,6 @@ + NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + const char *cli_name, + const char *princ_name, +- struct PAC_LOGON_INFO *logon_info, + bool *is_mapped, + bool *mapped_to_guest, + char **ntuser, +@@ -40,8 +39,8 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + struct passwd **_pw) + { + NTSTATUS status; +- char *domain = NULL; +- char *realm = NULL; ++ const char *domain = NULL; ++ const char *realm = NULL; + char *user = NULL; + char *p; + char *fuser = NULL; +@@ -62,55 +61,16 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- realm = talloc_strdup(talloc_tos(), p + 1); +- if (!realm) { +- return NT_STATUS_NO_MEMORY; +- } ++ realm = p + 1; + + if (!strequal(realm, lp_realm())) { + DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); + if (!lp_allow_trusted_domains()) { + return NT_STATUS_LOGON_FAILURE; + } +- } +- +- if (logon_info && logon_info->info3.base.logon_domain.string) { +- domain = talloc_strdup(mem_ctx, +- logon_info->info3.base.logon_domain.string); +- if (!domain) { +- return NT_STATUS_NO_MEMORY; +- } +- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); ++ domain = realm; + } else { +- +- /* If we have winbind running, we can (and must) shorten the +- username by using the short netbios name. Otherwise we will +- have inconsistent user names. With Kerberos, we get the +- fully qualified realm, with ntlmssp we get the short +- name. And even w2k3 does use ntlmssp if you for example +- connect to an ip address. */ +- +- wbcErr wbc_status; +- struct wbcDomainInfo *info = NULL; +- +- DEBUG(10, ("Mapping [%s] to short name using winbindd\n", +- realm)); +- +- wbc_status = wbcDomainInfo(realm, &info); +- +- if (WBC_ERROR_IS_OK(wbc_status)) { +- domain = talloc_strdup(mem_ctx, +- info->short_name); +- wbcFreeMemory(info); +- } else { +- DEBUG(3, ("Could not find short name: %s\n", +- wbcErrorString(wbc_status))); +- domain = talloc_strdup(mem_ctx, realm); +- } +- if (!domain) { +- return NT_STATUS_NO_MEMORY; +- } +- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); ++ domain = lp_workgroup(); + } + + fuser = talloc_asprintf(mem_ctx, +@@ -175,7 +135,11 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + *ntuser = user; +- *ntdomain = domain; ++ *ntdomain = talloc_strdup(mem_ctx, domain); ++ if (*ntdomain == NULL) { ++ return NT_STATUS_NO_MEMORY; ++ } ++ + *_pw = pw; + + return NT_STATUS_OK; +@@ -282,7 +246,6 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + const char *cli_name, + const char *princ_name, +- struct PAC_LOGON_INFO *logon_info, + bool *is_mapped, + bool *mapped_to_guest, + char **ntuser, +-- +2.33.1 + + +From 5607df9a4601a89735c1f9a3eaa700310d89c79a Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 18:03:04 +0200 +Subject: [PATCH 39/39] CVE-2020-25717: s3:auth: simplify + make_session_info_krb5() by removing unused arguments + +This is only ever be called in standalone mode with an MIT realm, +so we don't have a PAC/info3 structure. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 2 +- + source3/auth/proto.h | 2 -- + source3/auth/user_krb5.c | 20 +------------------- + 3 files changed, 2 insertions(+), 22 deletions(-) + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index 8923aec0a4d..fa22a0b2339 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -227,7 +227,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + + status = make_session_info_krb5(mem_ctx, + ntuser, ntdomain, username, pw, +- NULL, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, ++ is_guest, is_mapped, + session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", +diff --git a/source3/auth/proto.h b/source3/auth/proto.h +index 46fae447347..fb7f663512b 100644 +--- a/source3/auth/proto.h ++++ b/source3/auth/proto.h +@@ -434,9 +434,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + char *ntdomain, + char *username, + struct passwd *pw, +- const struct netr_SamInfo3 *info3, + bool mapped_to_guest, bool username_was_mapped, +- DATA_BLOB *session_key, + struct auth_session_info **session_info); + + /* The following definitions come from auth/auth_samba4.c */ +diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c +index 7b69ca6c222..b8f37cbeee0 100644 +--- a/source3/auth/user_krb5.c ++++ b/source3/auth/user_krb5.c +@@ -150,9 +150,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + char *ntdomain, + char *username, + struct passwd *pw, +- const struct netr_SamInfo3 *info3, + bool mapped_to_guest, bool username_was_mapped, +- DATA_BLOB *session_key, + struct auth_session_info **session_info) + { + NTSTATUS status; +@@ -166,20 +164,6 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + return status; + } + +- } else if (info3) { +- /* pass the unmapped username here since map_username() +- will be called again in make_server_info_info3() */ +- +- status = make_server_info_info3(mem_ctx, +- ntuser, ntdomain, +- &server_info, +- info3); +- if (!NT_STATUS_IS_OK(status)) { +- DEBUG(1, ("make_server_info_info3 failed: %s!\n", +- nt_errstr(status))); +- return status; +- } +- + } else { + /* + * We didn't get a PAC, we have to make up the user +@@ -231,7 +215,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + + server_info->nss_token |= username_was_mapped; + +- status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info); ++ status = create_local_token(mem_ctx, server_info, NULL, ntuser, session_info); + talloc_free(server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("failed to create local token: %s\n", +@@ -261,9 +245,7 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, + char *ntdomain, + char *username, + struct passwd *pw, +- const struct netr_SamInfo3 *info3, + bool mapped_to_guest, bool username_was_mapped, +- DATA_BLOB *session_key, + struct auth_session_info **session_info) + { + return NT_STATUS_NOT_IMPLEMENTED; +-- +2.33.1 + diff --git a/SOURCES/CVE-2021-23192.patch b/SOURCES/CVE-2021-23192.patch new file mode 100644 index 0000000..5e14212 --- /dev/null +++ b/SOURCES/CVE-2021-23192.patch @@ -0,0 +1,4996 @@ +From d6310598bd205240950410d59a3453f45c45d644 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 2 Apr 2021 12:20:38 +0200 +Subject: [PATCH 1/9] rpc: Give dcerpc_util.c its own header + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +(cherry picked from commit 8945d99758d8bedd374f1c51304b87a6cf10498c) +--- + librpc/rpc/dcerpc_util.c | 1 + + librpc/rpc/dcerpc_util.h | 103 ++++++++++++++++++++ + librpc/rpc/dcesrv_auth.c | 1 + + librpc/rpc/dcesrv_core.c | 1 + + librpc/rpc/dcesrv_reply.c | 1 + + librpc/rpc/rpc_common.h | 74 -------------- + source3/librpc/rpc/dcerpc_helpers.c | 1 + + source3/rpc_client/cli_pipe.c | 1 + + source3/rpc_client/rpc_transport_np.c | 1 + + source3/rpc_server/rpc_ncacn_np.c | 1 + + source4/librpc/rpc/dcerpc.c | 1 + + source4/librpc/rpc/dcerpc_roh_channel_out.c | 1 + + 12 files changed, 113 insertions(+), 74 deletions(-) + create mode 100644 librpc/rpc/dcerpc_util.h + +diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c +index 42e8e611019..925fb70ad7c 100644 +--- a/librpc/rpc/dcerpc_util.c ++++ b/librpc/rpc/dcerpc_util.c +@@ -25,6 +25,7 @@ + #include "lib/tsocket/tsocket.h" + #include "lib/util/tevent_ntstatus.h" + #include "librpc/rpc/dcerpc.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "rpc_common.h" + #include "lib/util/bitmap.h" +diff --git a/librpc/rpc/dcerpc_util.h b/librpc/rpc/dcerpc_util.h +new file mode 100644 +index 00000000000..0ecaf428c3c +--- /dev/null ++++ b/librpc/rpc/dcerpc_util.h +@@ -0,0 +1,103 @@ ++/* ++ Unix SMB/CIFS implementation. ++ ++ Copyright (C) Stefan Metzmacher 2010-2011 ++ Copyright (C) Andrew Tridgell 2010-2011 ++ Copyright (C) Simo Sorce 2010 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef __LIBRPC_RPC_DCERPC_UTIL_H__ ++#define __LIBRPC_RPC_DCERPC_UTIL_H__ ++ ++#include "replace.h" ++#include ++#include "lib/util/data_blob.h" ++#include "librpc/rpc/rpc_common.h" ++#include "librpc/gen_ndr/dcerpc.h" ++ ++void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v); ++uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob); ++void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v); ++uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob); ++uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob); ++uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob); ++uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob); ++uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob); ++const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx, ++ enum dcerpc_transport_t transport, ++ const struct ndr_interface_table *table); ++ ++NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, ++ const DATA_BLOB *blob, ++ struct ncacn_packet *r); ++ ++/** ++* @brief Pull a dcerpc_auth structure, taking account of any auth ++* padding in the blob. For request/response packets we pass ++* the whole data blob, so auth_data_only must be set to false ++* as the blob contains data+pad+auth and no just pad+auth. ++* ++* @param pkt - The ncacn_packet strcuture ++* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements ++* @param pkt_trailer - The packet trailer data, usually the trailing ++* auth_info blob, but in the request/response case ++* this is the stub_and_verifier blob. ++* @param auth - A preallocated dcerpc_auth *empty* structure ++* @param auth_length - The length of the auth trail, sum of auth header ++* lenght and pkt->auth_length ++* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob ++* (+ padding) or also other data. ++* ++* @return - A NTSTATUS error code. ++*/ ++NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, ++ TALLOC_CTX *mem_ctx, ++ const DATA_BLOB *pkt_trailer, ++ struct dcerpc_auth *auth, ++ uint32_t *auth_length, ++ bool auth_data_only); ++NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, ++ enum dcerpc_pkt_type ptype, ++ size_t max_auth_info, ++ uint8_t required_flags, ++ uint8_t optional_flags); ++NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ enum dcerpc_pkt_type ptype, ++ uint8_t required_flags, ++ uint8_t optional_flags, ++ uint8_t payload_offset, ++ DATA_BLOB *payload_and_verifier, ++ DATA_BLOB *raw_packet, ++ const struct ncacn_packet *pkt); ++NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ DATA_BLOB *raw_packet, ++ size_t sig_size, ++ uint8_t payload_offset, ++ const DATA_BLOB *payload, ++ const struct ncacn_packet *pkt); ++struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct tstream_context *stream); ++NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct ncacn_packet **pkt, ++ DATA_BLOB *buffer); ++ ++#endif +diff --git a/librpc/rpc/dcesrv_auth.c b/librpc/rpc/dcesrv_auth.c +index 8ac90f2a2bd..f7919ebf575 100644 +--- a/librpc/rpc/dcesrv_auth.c ++++ b/librpc/rpc/dcesrv_auth.c +@@ -23,6 +23,7 @@ + #include "includes.h" + #include "librpc/rpc/dcesrv_core.h" + #include "librpc/rpc/dcesrv_core_proto.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "auth/credentials/credentials.h" + #include "auth/gensec/gensec.h" +diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c +index 06f6c4b2382..74730f22c7c 100644 +--- a/librpc/rpc/dcesrv_core.c ++++ b/librpc/rpc/dcesrv_core.c +@@ -24,6 +24,7 @@ + #include "includes.h" + #include "librpc/rpc/dcesrv_core.h" + #include "librpc/rpc/dcesrv_core_proto.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "librpc/gen_ndr/auth.h" + #include "auth/gensec/gensec.h" + #include "lib/util/dlinklist.h" +diff --git a/librpc/rpc/dcesrv_reply.c b/librpc/rpc/dcesrv_reply.c +index 96bd98f53e1..5b4429956e7 100644 +--- a/librpc/rpc/dcesrv_reply.c ++++ b/librpc/rpc/dcesrv_reply.c +@@ -23,6 +23,7 @@ + #include "includes.h" + #include "librpc/rpc/dcesrv_core.h" + #include "librpc/rpc/dcesrv_core_proto.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "auth/gensec/gensec.h" + #include "lib/util/dlinklist.h" + #include "param/param.h" +diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h +index 82fe2eb7e80..55a35f31096 100644 +--- a/librpc/rpc/rpc_common.h ++++ b/librpc/rpc/rpc_common.h +@@ -165,80 +165,6 @@ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t); + enum dcerpc_transport_t dcerpc_transport_by_name(const char *name); + enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower); + +-/* The following definitions come from ../librpc/rpc/dcerpc_util.c */ +- +-void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v); +-uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob); +-void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v); +-uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob); +-uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob); +-uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob); +-uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob); +-uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob); +-const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx, +- enum dcerpc_transport_t transport, +- const struct ndr_interface_table *table); +- +-NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, +- const DATA_BLOB *blob, +- struct ncacn_packet *r); +- +-/** +-* @brief Pull a dcerpc_auth structure, taking account of any auth +-* padding in the blob. For request/response packets we pass +-* the whole data blob, so auth_data_only must be set to false +-* as the blob contains data+pad+auth and no just pad+auth. +-* +-* @param pkt - The ncacn_packet strcuture +-* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements +-* @param pkt_trailer - The packet trailer data, usually the trailing +-* auth_info blob, but in the request/response case +-* this is the stub_and_verifier blob. +-* @param auth - A preallocated dcerpc_auth *empty* structure +-* @param auth_length - The length of the auth trail, sum of auth header +-* lenght and pkt->auth_length +-* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob +-* (+ padding) or also other data. +-* +-* @return - A NTSTATUS error code. +-*/ +-NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, +- TALLOC_CTX *mem_ctx, +- const DATA_BLOB *pkt_trailer, +- struct dcerpc_auth *auth, +- uint32_t *auth_length, +- bool auth_data_only); +-NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, +- enum dcerpc_pkt_type ptype, +- size_t max_auth_info, +- uint8_t required_flags, +- uint8_t optional_flags); +-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- enum dcerpc_pkt_type ptype, +- uint8_t required_flags, +- uint8_t optional_flags, +- uint8_t payload_offset, +- DATA_BLOB *payload_and_verifier, +- DATA_BLOB *raw_packet, +- const struct ncacn_packet *pkt); +-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- DATA_BLOB *raw_packet, +- size_t sig_size, +- uint8_t payload_offset, +- const DATA_BLOB *payload, +- const struct ncacn_packet *pkt); +-struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct tstream_context *stream); +-NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req, +- TALLOC_CTX *mem_ctx, +- struct ncacn_packet **pkt, +- DATA_BLOB *buffer); +- + /* The following definitions come from ../librpc/rpc/binding_handle.c */ + + struct dcerpc_binding_handle_ops { +diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c +index 1f67987561c..c609efd5b07 100644 +--- a/source3/librpc/rpc/dcerpc_helpers.c ++++ b/source3/librpc/rpc/dcerpc_helpers.c +@@ -20,6 +20,7 @@ + + #include "includes.h" + #include "librpc/rpc/dcerpc.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "librpc/crypto/gse.h" + #include "auth/gensec/gensec.h" +diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c +index 8f52acadec8..3d16f1092db 100644 +--- a/source3/rpc_client/cli_pipe.c ++++ b/source3/rpc_client/cli_pipe.c +@@ -30,6 +30,7 @@ + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "librpc/gen_ndr/ndr_netlogon_c.h" + #include "librpc/rpc/dcerpc.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "rpc_dce.h" + #include "cli_pipe.h" + #include "libsmb/libsmb.h" +diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c +index 9dc5c5634fc..b24023661ff 100644 +--- a/source3/rpc_client/rpc_transport_np.c ++++ b/source3/rpc_client/rpc_transport_np.c +@@ -19,6 +19,7 @@ + + #include "includes.h" + #include "../lib/util/tevent_ntstatus.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "rpc_client/rpc_transport.h" + #include "librpc/ndr/ndr_table.h" + #include "libcli/smb/smbXcli_base.h" +diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c +index 494b002e714..a874a2376d1 100644 +--- a/source3/rpc_server/rpc_ncacn_np.c ++++ b/source3/rpc_server/rpc_ncacn_np.c +@@ -37,6 +37,7 @@ + #include "rpc_server/rpc_config.h" + #include "librpc/ndr/ndr_table.h" + #include "rpc_server/rpc_server.h" ++#include "librpc/rpc/dcerpc_util.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_RPC_SRV +diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c +index 87a99a8df89..f97263dcc5b 100644 +--- a/source4/librpc/rpc/dcerpc.c ++++ b/source4/librpc/rpc/dcerpc.c +@@ -26,6 +26,7 @@ + #include "lib/events/events.h" + #include "librpc/rpc/dcerpc.h" + #include "librpc/rpc/dcerpc_proto.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "librpc/gen_ndr/ndr_misc.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "auth/gensec/gensec.h" +diff --git a/source4/librpc/rpc/dcerpc_roh_channel_out.c b/source4/librpc/rpc/dcerpc_roh_channel_out.c +index e431689d419..2abafb0bab5 100644 +--- a/source4/librpc/rpc/dcerpc_roh_channel_out.c ++++ b/source4/librpc/rpc/dcerpc_roh_channel_out.c +@@ -37,6 +37,7 @@ + #include "librpc/rpc/dcerpc.h" + #include "librpc/rpc/dcerpc_roh.h" + #include "librpc/rpc/dcerpc_proto.h" ++#include "librpc/rpc/dcerpc_util.h" + #include "libcli/http/http.h" + + struct roh_request_state { +-- +2.25.1 + + +From fc8592c7e3aa24c3b6819641908f21311840e6cb Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 2 Apr 2021 13:41:21 +0200 +Subject: [PATCH 2/9] librpc: Remove the gensec dependency from library + dcerpc-binding + +This means yet another library, but having to depend on gensec just +for dcerpc_parse_binding() and basic packet parsing seems like a bit +overkill to me. + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +Autobuild-User(master): Jeremy Allison +Autobuild-Date(master): Tue Apr 6 23:33:14 UTC 2021 on sn-devel-184 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +(cherry picked from commit 4d3b6506d30e4bf302f832493dad00a83b73d370) +--- + libcli/auth/wscript_build | 10 +- + librpc/rpc/dcerpc_pkt_auth.c | 497 +++++++++++++++++++++++++++++++++++ + librpc/rpc/dcerpc_pkt_auth.h | 58 ++++ + librpc/rpc/dcerpc_util.c | 464 -------------------------------- + librpc/rpc/dcerpc_util.h | 18 -- + librpc/rpc/dcesrv_auth.c | 1 + + librpc/wscript_build | 25 +- + source3/wscript_build | 8 +- + source4/librpc/rpc/dcerpc.c | 1 + + source4/librpc/wscript_build | 21 +- + 10 files changed, 613 insertions(+), 490 deletions(-) + create mode 100644 librpc/rpc/dcerpc_pkt_auth.c + create mode 100644 librpc/rpc/dcerpc_pkt_auth.h + +diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build +index 2a6a7468e45..24ab68fac1e 100644 +--- a/libcli/auth/wscript_build ++++ b/libcli/auth/wscript_build +@@ -30,7 +30,15 @@ bld.SAMBA_SUBSYSTEM('COMMON_SCHANNEL', + + bld.SAMBA_SUBSYSTEM('NETLOGON_CREDS_CLI', + source='netlogon_creds_cli.c', +- deps='dbwrap util_tdb tevent-util samba-hostconfig RPC_NDR_NETLOGON NDR_NETLOGON' ++ deps=''' ++ dbwrap ++ util_tdb ++ tevent-util ++ samba-hostconfig ++ gensec ++ RPC_NDR_NETLOGON ++ NDR_NETLOGON ++ ''' + ) + + bld.SAMBA_SUBSYSTEM('PAM_ERRORS', +diff --git a/librpc/rpc/dcerpc_pkt_auth.c b/librpc/rpc/dcerpc_pkt_auth.c +new file mode 100644 +index 00000000000..322d7497893 +--- /dev/null ++++ b/librpc/rpc/dcerpc_pkt_auth.c +@@ -0,0 +1,497 @@ ++/* ++ Unix SMB/CIFS implementation. ++ raw dcerpc operations ++ ++ Copyright (C) Andrew Tridgell 2003-2005 ++ Copyright (C) Jelmer Vernooij 2004-2005 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "replace.h" ++#include "system/network.h" ++#include ++#include "lib/util/talloc_stack.h" ++#include "lib/util/debug.h" ++#include "lib/util/byteorder.h" ++#include "lib/util/samba_util.h" ++#include "librpc/rpc/dcerpc.h" ++#include "librpc/rpc/dcerpc_util.h" ++#include "librpc/rpc/dcerpc_pkt_auth.h" ++#include "librpc/gen_ndr/ndr_dcerpc.h" ++#include "rpc_common.h" ++#include "lib/util/bitmap.h" ++#include "auth/gensec/gensec.h" ++#include "lib/util/mkdir_p.h" ++#include "lib/crypto/gnutls_helpers.h" ++#include ++ ++NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ enum dcerpc_pkt_type ptype, ++ uint8_t required_flags, ++ uint8_t optional_flags, ++ uint8_t payload_offset, ++ DATA_BLOB *payload_and_verifier, ++ DATA_BLOB *raw_packet, ++ const struct ncacn_packet *pkt) ++{ ++ NTSTATUS status; ++ struct dcerpc_auth auth; ++ uint32_t auth_length; ++ ++ if (auth_state == NULL) { ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ status = dcerpc_verify_ncacn_packet_header(pkt, ptype, ++ payload_and_verifier->length, ++ required_flags, optional_flags); ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; ++ } ++ ++ switch (auth_state->auth_level) { ++ case DCERPC_AUTH_LEVEL_PRIVACY: ++ case DCERPC_AUTH_LEVEL_INTEGRITY: ++ case DCERPC_AUTH_LEVEL_PACKET: ++ break; ++ ++ case DCERPC_AUTH_LEVEL_CONNECT: ++ if (pkt->auth_length != 0) { ++ break; ++ } ++ return NT_STATUS_OK; ++ case DCERPC_AUTH_LEVEL_NONE: ++ if (pkt->auth_length != 0) { ++ return NT_STATUS_ACCESS_DENIED; ++ } ++ return NT_STATUS_OK; ++ ++ default: ++ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; ++ } ++ ++ if (pkt->auth_length == 0) { ++ return NT_STATUS_RPC_PROTOCOL_ERROR; ++ } ++ ++ if (gensec == NULL) { ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ status = dcerpc_pull_auth_trailer(pkt, mem_ctx, ++ payload_and_verifier, ++ &auth, &auth_length, false); ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; ++ } ++ ++ if (payload_and_verifier->length < auth_length) { ++ /* ++ * should be checked in dcerpc_pull_auth_trailer() ++ */ ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ payload_and_verifier->length -= auth_length; ++ ++ if (payload_and_verifier->length < auth.auth_pad_length) { ++ /* ++ * should be checked in dcerpc_pull_auth_trailer() ++ */ ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ if (auth.auth_type != auth_state->auth_type) { ++ return NT_STATUS_ACCESS_DENIED; ++ } ++ ++ if (auth.auth_level != auth_state->auth_level) { ++ return NT_STATUS_ACCESS_DENIED; ++ } ++ ++ if (auth.auth_context_id != auth_state->auth_context_id) { ++ return NT_STATUS_ACCESS_DENIED; ++ } ++ ++ /* check signature or unseal the packet */ ++ switch (auth_state->auth_level) { ++ case DCERPC_AUTH_LEVEL_PRIVACY: ++ status = gensec_unseal_packet(gensec, ++ raw_packet->data + payload_offset, ++ payload_and_verifier->length, ++ raw_packet->data, ++ raw_packet->length - ++ auth.credentials.length, ++ &auth.credentials); ++ if (!NT_STATUS_IS_OK(status)) { ++ return NT_STATUS_RPC_SEC_PKG_ERROR; ++ } ++ memcpy(payload_and_verifier->data, ++ raw_packet->data + payload_offset, ++ payload_and_verifier->length); ++ break; ++ ++ case DCERPC_AUTH_LEVEL_INTEGRITY: ++ case DCERPC_AUTH_LEVEL_PACKET: ++ status = gensec_check_packet(gensec, ++ payload_and_verifier->data, ++ payload_and_verifier->length, ++ raw_packet->data, ++ raw_packet->length - ++ auth.credentials.length, ++ &auth.credentials); ++ if (!NT_STATUS_IS_OK(status)) { ++ return NT_STATUS_RPC_SEC_PKG_ERROR; ++ } ++ break; ++ ++ case DCERPC_AUTH_LEVEL_CONNECT: ++ /* for now we ignore possible signatures here */ ++ break; ++ ++ default: ++ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; ++ } ++ ++ /* ++ * remove the indicated amount of padding ++ * ++ * A possible overflow is checked above. ++ */ ++ payload_and_verifier->length -= auth.auth_pad_length; ++ ++ return NT_STATUS_OK; ++} ++ ++NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ DATA_BLOB *raw_packet, ++ size_t sig_size, ++ uint8_t payload_offset, ++ const DATA_BLOB *payload, ++ const struct ncacn_packet *pkt) ++{ ++ TALLOC_CTX *frame = talloc_stackframe(); ++ NTSTATUS status; ++ enum ndr_err_code ndr_err; ++ struct ndr_push *ndr = NULL; ++ uint32_t payload_length; ++ uint32_t whole_length; ++ DATA_BLOB blob = data_blob_null; ++ DATA_BLOB sig = data_blob_null; ++ struct dcerpc_auth _out_auth_info; ++ struct dcerpc_auth *out_auth_info = NULL; ++ ++ *raw_packet = data_blob_null; ++ ++ if (auth_state == NULL) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ switch (auth_state->auth_level) { ++ case DCERPC_AUTH_LEVEL_PRIVACY: ++ case DCERPC_AUTH_LEVEL_INTEGRITY: ++ case DCERPC_AUTH_LEVEL_PACKET: ++ if (sig_size == 0) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ if (gensec == NULL) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ _out_auth_info = (struct dcerpc_auth) { ++ .auth_type = auth_state->auth_type, ++ .auth_level = auth_state->auth_level, ++ .auth_context_id = auth_state->auth_context_id, ++ }; ++ out_auth_info = &_out_auth_info; ++ break; ++ ++ case DCERPC_AUTH_LEVEL_CONNECT: ++ /* ++ * TODO: let the gensec mech decide if it wants to generate a ++ * signature that might be needed for schannel... ++ */ ++ if (sig_size != 0) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ if (gensec == NULL) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ break; ++ ++ case DCERPC_AUTH_LEVEL_NONE: ++ if (sig_size != 0) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ break; ++ ++ default: ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ ndr = ndr_push_init_ctx(frame); ++ if (ndr == NULL) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ TALLOC_FREE(frame); ++ return ndr_map_error2ntstatus(ndr_err); ++ } ++ ++ if (out_auth_info != NULL) { ++ /* ++ * pad to 16 byte multiple in the payload portion of the ++ * packet. This matches what w2k3 does. Note that we can't use ++ * ndr_push_align() as that is relative to the start of the ++ * whole packet, whereas w2k8 wants it relative to the start ++ * of the stub. ++ */ ++ out_auth_info->auth_pad_length = ++ DCERPC_AUTH_PAD_LENGTH(payload->length); ++ ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ TALLOC_FREE(frame); ++ return ndr_map_error2ntstatus(ndr_err); ++ } ++ ++ payload_length = payload->length + ++ out_auth_info->auth_pad_length; ++ ++ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, ++ out_auth_info); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ TALLOC_FREE(frame); ++ return ndr_map_error2ntstatus(ndr_err); ++ } ++ ++ whole_length = ndr->offset; ++ ++ ndr_err = ndr_push_zero(ndr, sig_size); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ TALLOC_FREE(frame); ++ return ndr_map_error2ntstatus(ndr_err); ++ } ++ } else { ++ payload_length = payload->length; ++ whole_length = ndr->offset; ++ } ++ ++ /* extract the whole packet as a blob */ ++ blob = ndr_push_blob(ndr); ++ ++ /* ++ * Setup the frag and auth length in the packet buffer. ++ * This is needed if the GENSEC mech does AEAD signing ++ * of the packet headers. The signature itself will be ++ * appended later. ++ */ ++ dcerpc_set_frag_length(&blob, blob.length); ++ dcerpc_set_auth_length(&blob, sig_size); ++ ++ /* sign or seal the packet */ ++ switch (auth_state->auth_level) { ++ case DCERPC_AUTH_LEVEL_PRIVACY: ++ status = gensec_seal_packet(gensec, ++ frame, ++ blob.data + payload_offset, ++ payload_length, ++ blob.data, ++ whole_length, ++ &sig); ++ if (!NT_STATUS_IS_OK(status)) { ++ TALLOC_FREE(frame); ++ return status; ++ } ++ break; ++ ++ case DCERPC_AUTH_LEVEL_INTEGRITY: ++ case DCERPC_AUTH_LEVEL_PACKET: ++ status = gensec_sign_packet(gensec, ++ frame, ++ blob.data + payload_offset, ++ payload_length, ++ blob.data, ++ whole_length, ++ &sig); ++ if (!NT_STATUS_IS_OK(status)) { ++ TALLOC_FREE(frame); ++ return status; ++ } ++ break; ++ ++ case DCERPC_AUTH_LEVEL_CONNECT: ++ case DCERPC_AUTH_LEVEL_NONE: ++ break; ++ ++ default: ++ TALLOC_FREE(frame); ++ return NT_STATUS_INTERNAL_ERROR; ++ } ++ ++ if (sig.length != sig_size) { ++ TALLOC_FREE(frame); ++ return NT_STATUS_RPC_SEC_PKG_ERROR; ++ } ++ ++ if (sig_size != 0) { ++ memcpy(blob.data + whole_length, sig.data, sig_size); ++ } ++ ++ *raw_packet = blob; ++ talloc_steal(mem_ctx, raw_packet->data); ++ TALLOC_FREE(frame); ++ return NT_STATUS_OK; ++} ++ ++#ifdef DEVELOPER ++ ++/* ++ * Save valid, well-formed DCE/RPC stubs to use as a seed for ++ * ndr_fuzz_X ++ */ ++void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx, ++ DATA_BLOB raw_blob, ++ const char *dump_dir, ++ const char *iface_name, ++ int flags, ++ int opnum, ++ bool ndr64) ++{ ++ char *fname = NULL; ++ const char *sub_dir = NULL; ++ TALLOC_CTX *temp_ctx = talloc_new(mem_ctx); ++ DATA_BLOB blob; ++ int ret, rc; ++ uint8_t digest[20]; ++ DATA_BLOB digest_blob; ++ char *digest_hex; ++ uint16_t fuzz_flags = 0; ++ ++ /* ++ * We want to save the 'stub' in a per-pipe subdirectory, with ++ * the ndr_fuzz_X header 4 byte header. For the sake of ++ * convenience (this is a developer only function), we mkdir ++ * -p the sub-directories when they are needed. ++ */ ++ ++ if (dump_dir == NULL) { ++ return; ++ } ++ ++ temp_ctx = talloc_stackframe(); ++ ++ sub_dir = talloc_asprintf(temp_ctx, "%s/%s", ++ dump_dir, ++ iface_name); ++ if (sub_dir == NULL) { ++ talloc_free(temp_ctx); ++ return; ++ } ++ ret = mkdir_p(sub_dir, 0755); ++ if (ret && errno != EEXIST) { ++ DBG_ERR("could not create %s\n", sub_dir); ++ talloc_free(temp_ctx); ++ return; ++ } ++ ++ blob.length = raw_blob.length + 4; ++ blob.data = talloc_array(sub_dir, ++ uint8_t, ++ blob.length); ++ if (blob.data == NULL) { ++ DBG_ERR("could not allocate for fuzz seeds! (%s)\n", ++ iface_name); ++ talloc_free(temp_ctx); ++ return; ++ } ++ ++ if (ndr64) { ++ fuzz_flags = 4; ++ } ++ if (flags & NDR_IN) { ++ fuzz_flags |= 1; ++ } else if (flags & NDR_OUT) { ++ fuzz_flags |= 2; ++ } ++ ++ SSVAL(blob.data, 0, fuzz_flags); ++ SSVAL(blob.data, 2, opnum); ++ ++ memcpy(&blob.data[4], ++ raw_blob.data, ++ raw_blob.length); ++ ++ /* ++ * This matches how oss-fuzz names the corpus input files, due ++ * to a preference from libFuzzer ++ */ ++ rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, ++ blob.data, ++ blob.length, ++ digest); ++ if (rc < 0) { ++ /* ++ * This prints a better error message, eg if SHA1 is ++ * disabled ++ */ ++ NTSTATUS status = gnutls_error_to_ntstatus(rc, ++ NT_STATUS_HASH_NOT_SUPPORTED); ++ DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s", ++ nt_errstr(status)); ++ talloc_free(temp_ctx); ++ return; ++ } ++ ++ digest_blob.data = digest; ++ digest_blob.length = sizeof(digest); ++ digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob); ++ ++ fname = talloc_asprintf(temp_ctx, "%s/%s", ++ sub_dir, ++ digest_hex); ++ if (fname == NULL) { ++ talloc_free(temp_ctx); ++ return; ++ } ++ ++ /* ++ * If this fails, it is most likely because that file already ++ * exists. This is fine, it means we already have this ++ * sample ++ */ ++ file_save(fname, ++ blob.data, ++ blob.length); ++ ++ talloc_free(temp_ctx); ++} ++ ++#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */ +diff --git a/librpc/rpc/dcerpc_pkt_auth.h b/librpc/rpc/dcerpc_pkt_auth.h +new file mode 100644 +index 00000000000..c0d23b91c05 +--- /dev/null ++++ b/librpc/rpc/dcerpc_pkt_auth.h +@@ -0,0 +1,58 @@ ++/* ++ Unix SMB/CIFS implementation. ++ ++ Copyright (C) Stefan Metzmacher 2010-2011 ++ Copyright (C) Andrew Tridgell 2010-2011 ++ Copyright (C) Simo Sorce 2010 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef __LIBRPC_RPC_DCERPC_PKT_AUTH_H__ ++#define __LIBRPC_RPC_DCERPC_PKT_AUTH_H__ ++ ++#include "replace.h" ++#include ++#include "lib/util/data_blob.h" ++#include "libcli/util/ntstatus.h" ++#include "librpc/rpc/rpc_common.h" ++#include "librpc/gen_ndr/dcerpc.h" ++ ++NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ enum dcerpc_pkt_type ptype, ++ uint8_t required_flags, ++ uint8_t optional_flags, ++ uint8_t payload_offset, ++ DATA_BLOB *payload_and_verifier, ++ DATA_BLOB *raw_packet, ++ const struct ncacn_packet *pkt); ++NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, ++ struct gensec_security *gensec, ++ TALLOC_CTX *mem_ctx, ++ DATA_BLOB *raw_packet, ++ size_t sig_size, ++ uint8_t payload_offset, ++ const DATA_BLOB *payload, ++ const struct ncacn_packet *pkt); ++struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct tstream_context *stream); ++NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct ncacn_packet **pkt, ++ DATA_BLOB *buffer); ++ ++#endif +diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c +index 925fb70ad7c..c878a2af094 100644 +--- a/librpc/rpc/dcerpc_util.c ++++ b/librpc/rpc/dcerpc_util.c +@@ -29,10 +29,6 @@ + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "rpc_common.h" + #include "lib/util/bitmap.h" +-#include "auth/gensec/gensec.h" +-#include "lib/util/mkdir_p.h" +-#include "lib/crypto/gnutls_helpers.h" +-#include + + #undef strncasecmp + +@@ -486,340 +482,6 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, + return NT_STATUS_OK; + } + +-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- enum dcerpc_pkt_type ptype, +- uint8_t required_flags, +- uint8_t optional_flags, +- uint8_t payload_offset, +- DATA_BLOB *payload_and_verifier, +- DATA_BLOB *raw_packet, +- const struct ncacn_packet *pkt) +-{ +- NTSTATUS status; +- struct dcerpc_auth auth; +- uint32_t auth_length; +- +- if (auth_state == NULL) { +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- status = dcerpc_verify_ncacn_packet_header(pkt, ptype, +- payload_and_verifier->length, +- required_flags, optional_flags); +- if (!NT_STATUS_IS_OK(status)) { +- return status; +- } +- +- switch (auth_state->auth_level) { +- case DCERPC_AUTH_LEVEL_PRIVACY: +- case DCERPC_AUTH_LEVEL_INTEGRITY: +- case DCERPC_AUTH_LEVEL_PACKET: +- break; +- +- case DCERPC_AUTH_LEVEL_CONNECT: +- if (pkt->auth_length != 0) { +- break; +- } +- return NT_STATUS_OK; +- case DCERPC_AUTH_LEVEL_NONE: +- if (pkt->auth_length != 0) { +- return NT_STATUS_ACCESS_DENIED; +- } +- return NT_STATUS_OK; +- +- default: +- return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; +- } +- +- if (pkt->auth_length == 0) { +- return NT_STATUS_RPC_PROTOCOL_ERROR; +- } +- +- if (gensec == NULL) { +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- status = dcerpc_pull_auth_trailer(pkt, mem_ctx, +- payload_and_verifier, +- &auth, &auth_length, false); +- if (!NT_STATUS_IS_OK(status)) { +- return status; +- } +- +- if (payload_and_verifier->length < auth_length) { +- /* +- * should be checked in dcerpc_pull_auth_trailer() +- */ +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- payload_and_verifier->length -= auth_length; +- +- if (payload_and_verifier->length < auth.auth_pad_length) { +- /* +- * should be checked in dcerpc_pull_auth_trailer() +- */ +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- if (auth.auth_type != auth_state->auth_type) { +- return NT_STATUS_ACCESS_DENIED; +- } +- +- if (auth.auth_level != auth_state->auth_level) { +- return NT_STATUS_ACCESS_DENIED; +- } +- +- if (auth.auth_context_id != auth_state->auth_context_id) { +- return NT_STATUS_ACCESS_DENIED; +- } +- +- /* check signature or unseal the packet */ +- switch (auth_state->auth_level) { +- case DCERPC_AUTH_LEVEL_PRIVACY: +- status = gensec_unseal_packet(gensec, +- raw_packet->data + payload_offset, +- payload_and_verifier->length, +- raw_packet->data, +- raw_packet->length - +- auth.credentials.length, +- &auth.credentials); +- if (!NT_STATUS_IS_OK(status)) { +- return NT_STATUS_RPC_SEC_PKG_ERROR; +- } +- memcpy(payload_and_verifier->data, +- raw_packet->data + payload_offset, +- payload_and_verifier->length); +- break; +- +- case DCERPC_AUTH_LEVEL_INTEGRITY: +- case DCERPC_AUTH_LEVEL_PACKET: +- status = gensec_check_packet(gensec, +- payload_and_verifier->data, +- payload_and_verifier->length, +- raw_packet->data, +- raw_packet->length - +- auth.credentials.length, +- &auth.credentials); +- if (!NT_STATUS_IS_OK(status)) { +- return NT_STATUS_RPC_SEC_PKG_ERROR; +- } +- break; +- +- case DCERPC_AUTH_LEVEL_CONNECT: +- /* for now we ignore possible signatures here */ +- break; +- +- default: +- return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; +- } +- +- /* +- * remove the indicated amount of padding +- * +- * A possible overflow is checked above. +- */ +- payload_and_verifier->length -= auth.auth_pad_length; +- +- return NT_STATUS_OK; +-} +- +-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- DATA_BLOB *raw_packet, +- size_t sig_size, +- uint8_t payload_offset, +- const DATA_BLOB *payload, +- const struct ncacn_packet *pkt) +-{ +- TALLOC_CTX *frame = talloc_stackframe(); +- NTSTATUS status; +- enum ndr_err_code ndr_err; +- struct ndr_push *ndr = NULL; +- uint32_t payload_length; +- uint32_t whole_length; +- DATA_BLOB blob = data_blob_null; +- DATA_BLOB sig = data_blob_null; +- struct dcerpc_auth _out_auth_info; +- struct dcerpc_auth *out_auth_info = NULL; +- +- *raw_packet = data_blob_null; +- +- if (auth_state == NULL) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- switch (auth_state->auth_level) { +- case DCERPC_AUTH_LEVEL_PRIVACY: +- case DCERPC_AUTH_LEVEL_INTEGRITY: +- case DCERPC_AUTH_LEVEL_PACKET: +- if (sig_size == 0) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- if (gensec == NULL) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- _out_auth_info = (struct dcerpc_auth) { +- .auth_type = auth_state->auth_type, +- .auth_level = auth_state->auth_level, +- .auth_context_id = auth_state->auth_context_id, +- }; +- out_auth_info = &_out_auth_info; +- break; +- +- case DCERPC_AUTH_LEVEL_CONNECT: +- /* +- * TODO: let the gensec mech decide if it wants to generate a +- * signature that might be needed for schannel... +- */ +- if (sig_size != 0) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- if (gensec == NULL) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- break; +- +- case DCERPC_AUTH_LEVEL_NONE: +- if (sig_size != 0) { +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- break; +- +- default: +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- ndr = ndr_push_init_ctx(frame); +- if (ndr == NULL) { +- TALLOC_FREE(frame); +- return NT_STATUS_NO_MEMORY; +- } +- +- ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); +- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +- TALLOC_FREE(frame); +- return ndr_map_error2ntstatus(ndr_err); +- } +- +- if (out_auth_info != NULL) { +- /* +- * pad to 16 byte multiple in the payload portion of the +- * packet. This matches what w2k3 does. Note that we can't use +- * ndr_push_align() as that is relative to the start of the +- * whole packet, whereas w2k8 wants it relative to the start +- * of the stub. +- */ +- out_auth_info->auth_pad_length = +- DCERPC_AUTH_PAD_LENGTH(payload->length); +- ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length); +- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +- TALLOC_FREE(frame); +- return ndr_map_error2ntstatus(ndr_err); +- } +- +- payload_length = payload->length + +- out_auth_info->auth_pad_length; +- +- ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, +- out_auth_info); +- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +- TALLOC_FREE(frame); +- return ndr_map_error2ntstatus(ndr_err); +- } +- +- whole_length = ndr->offset; +- +- ndr_err = ndr_push_zero(ndr, sig_size); +- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +- TALLOC_FREE(frame); +- return ndr_map_error2ntstatus(ndr_err); +- } +- } else { +- payload_length = payload->length; +- whole_length = ndr->offset; +- } +- +- /* extract the whole packet as a blob */ +- blob = ndr_push_blob(ndr); +- +- /* +- * Setup the frag and auth length in the packet buffer. +- * This is needed if the GENSEC mech does AEAD signing +- * of the packet headers. The signature itself will be +- * appended later. +- */ +- dcerpc_set_frag_length(&blob, blob.length); +- dcerpc_set_auth_length(&blob, sig_size); +- +- /* sign or seal the packet */ +- switch (auth_state->auth_level) { +- case DCERPC_AUTH_LEVEL_PRIVACY: +- status = gensec_seal_packet(gensec, +- frame, +- blob.data + payload_offset, +- payload_length, +- blob.data, +- whole_length, +- &sig); +- if (!NT_STATUS_IS_OK(status)) { +- TALLOC_FREE(frame); +- return status; +- } +- break; +- +- case DCERPC_AUTH_LEVEL_INTEGRITY: +- case DCERPC_AUTH_LEVEL_PACKET: +- status = gensec_sign_packet(gensec, +- frame, +- blob.data + payload_offset, +- payload_length, +- blob.data, +- whole_length, +- &sig); +- if (!NT_STATUS_IS_OK(status)) { +- TALLOC_FREE(frame); +- return status; +- } +- break; +- +- case DCERPC_AUTH_LEVEL_CONNECT: +- case DCERPC_AUTH_LEVEL_NONE: +- break; +- +- default: +- TALLOC_FREE(frame); +- return NT_STATUS_INTERNAL_ERROR; +- } +- +- if (sig.length != sig_size) { +- TALLOC_FREE(frame); +- return NT_STATUS_RPC_SEC_PKG_ERROR; +- } +- +- if (sig_size != 0) { +- memcpy(blob.data + whole_length, sig.data, sig_size); +- } +- +- *raw_packet = blob; +- talloc_steal(mem_ctx, raw_packet->data); +- TALLOC_FREE(frame); +- return NT_STATUS_OK; +-} +- + struct dcerpc_read_ncacn_packet_state { + #if 0 + struct { +@@ -1474,129 +1136,3 @@ void dcerpc_log_packet(const char *packet_log_dir, + free(name); + } + } +- +- +-#ifdef DEVELOPER +- +-/* +- * Save valid, well-formed DCE/RPC stubs to use as a seed for +- * ndr_fuzz_X +- */ +-void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx, +- DATA_BLOB raw_blob, +- const char *dump_dir, +- const char *iface_name, +- int flags, +- int opnum, +- bool ndr64) +-{ +- char *fname = NULL; +- const char *sub_dir = NULL; +- TALLOC_CTX *temp_ctx = talloc_new(mem_ctx); +- DATA_BLOB blob; +- int ret, rc; +- uint8_t digest[20]; +- DATA_BLOB digest_blob; +- char *digest_hex; +- uint16_t fuzz_flags = 0; +- +- /* +- * We want to save the 'stub' in a per-pipe subdirectory, with +- * the ndr_fuzz_X header 4 byte header. For the sake of +- * convenience (this is a developer only function), we mkdir +- * -p the sub-directories when they are needed. +- */ +- +- if (dump_dir == NULL) { +- return; +- } +- +- temp_ctx = talloc_stackframe(); +- +- sub_dir = talloc_asprintf(temp_ctx, "%s/%s", +- dump_dir, +- iface_name); +- if (sub_dir == NULL) { +- talloc_free(temp_ctx); +- return; +- } +- ret = mkdir_p(sub_dir, 0755); +- if (ret && errno != EEXIST) { +- DBG_ERR("could not create %s\n", sub_dir); +- talloc_free(temp_ctx); +- return; +- } +- +- blob.length = raw_blob.length + 4; +- blob.data = talloc_array(sub_dir, +- uint8_t, +- blob.length); +- if (blob.data == NULL) { +- DBG_ERR("could not allocate for fuzz seeds! (%s)\n", +- iface_name); +- talloc_free(temp_ctx); +- return; +- } +- +- if (ndr64) { +- fuzz_flags = 4; +- } +- if (flags & NDR_IN) { +- fuzz_flags |= 1; +- } else if (flags & NDR_OUT) { +- fuzz_flags |= 2; +- } +- +- SSVAL(blob.data, 0, fuzz_flags); +- SSVAL(blob.data, 2, opnum); +- +- memcpy(&blob.data[4], +- raw_blob.data, +- raw_blob.length); +- +- /* +- * This matches how oss-fuzz names the corpus input files, due +- * to a preference from libFuzzer +- */ +- rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, +- blob.data, +- blob.length, +- digest); +- if (rc < 0) { +- /* +- * This prints a better error message, eg if SHA1 is +- * disabled +- */ +- NTSTATUS status = gnutls_error_to_ntstatus(rc, +- NT_STATUS_HASH_NOT_SUPPORTED); +- DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s", +- nt_errstr(status)); +- talloc_free(temp_ctx); +- return; +- } +- +- digest_blob.data = digest; +- digest_blob.length = sizeof(digest); +- digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob); +- +- fname = talloc_asprintf(temp_ctx, "%s/%s", +- sub_dir, +- digest_hex); +- if (fname == NULL) { +- talloc_free(temp_ctx); +- return; +- } +- +- /* +- * If this fails, it is most likely because that file already +- * exists. This is fine, it means we already have this +- * sample +- */ +- file_save(fname, +- blob.data, +- blob.length); +- +- talloc_free(temp_ctx); +-} +- +-#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */ +diff --git a/librpc/rpc/dcerpc_util.h b/librpc/rpc/dcerpc_util.h +index 0ecaf428c3c..a9bc7bd3832 100644 +--- a/librpc/rpc/dcerpc_util.h ++++ b/librpc/rpc/dcerpc_util.h +@@ -74,24 +74,6 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, + size_t max_auth_info, + uint8_t required_flags, + uint8_t optional_flags); +-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- enum dcerpc_pkt_type ptype, +- uint8_t required_flags, +- uint8_t optional_flags, +- uint8_t payload_offset, +- DATA_BLOB *payload_and_verifier, +- DATA_BLOB *raw_packet, +- const struct ncacn_packet *pkt); +-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state, +- struct gensec_security *gensec, +- TALLOC_CTX *mem_ctx, +- DATA_BLOB *raw_packet, +- size_t sig_size, +- uint8_t payload_offset, +- const DATA_BLOB *payload, +- const struct ncacn_packet *pkt); + struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tstream_context *stream); +diff --git a/librpc/rpc/dcesrv_auth.c b/librpc/rpc/dcesrv_auth.c +index f7919ebf575..8dda86d88e2 100644 +--- a/librpc/rpc/dcesrv_auth.c ++++ b/librpc/rpc/dcesrv_auth.c +@@ -24,6 +24,7 @@ + #include "librpc/rpc/dcesrv_core.h" + #include "librpc/rpc/dcesrv_core_proto.h" + #include "librpc/rpc/dcerpc_util.h" ++#include "librpc/rpc/dcerpc_pkt_auth.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "auth/credentials/credentials.h" + #include "auth/gensec/gensec.h" +diff --git a/librpc/wscript_build b/librpc/wscript_build +index e4632d538a4..59d6c31363d 100644 +--- a/librpc/wscript_build ++++ b/librpc/wscript_build +@@ -655,12 +655,24 @@ bld.SAMBA_LIBRARY('ndr', + ) + + bld.SAMBA_LIBRARY('dcerpc-binding', +- source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c', +- deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util gensec', ++ source=''' ++ rpc/dcerpc_error.c ++ rpc/binding.c ++ rpc/dcerpc_util.c ++ rpc/binding_handle.c ++ ''', ++ deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util', + pc_files=[], + public_headers='rpc/rpc_common.h', + vnum='0.0.1') + ++bld.SAMBA_LIBRARY('dcerpc-pkt-auth', ++ private_library=True, ++ source=''' ++ rpc/dcerpc_pkt_auth.c ++ ''', ++ deps='dcerpc-binding gensec') ++ + bld.SAMBA_LIBRARY('dcerpc-server-core', + source=''' + rpc/dcesrv_core.c +@@ -669,7 +681,14 @@ bld.SAMBA_LIBRARY('dcerpc-server-core', + rpc/dcesrv_reply.c + rpc/dcesrv_handles.c + ''', +- deps='ndr dcerpc-binding samba-util-core gnutls GNUTLS_HELPERS', ++ deps=''' ++ ndr ++ dcerpc-binding ++ samba-util-core ++ gnutls ++ GNUTLS_HELPERS ++ dcerpc-pkt-auth ++ ''', + pc_files=[], + public_headers='rpc/dcesrv_core.h', + autoproto='rpc/dcesrv_core_proto.h', +diff --git a/source3/wscript_build b/source3/wscript_build +index 5d04fcb41d1..a143477a506 100644 +--- a/source3/wscript_build ++++ b/source3/wscript_build +@@ -1034,9 +1034,11 @@ bld.SAMBA3_LIBRARY('cli_spoolss', + rpc_client/init_spoolss.c + ''', + deps=''' +- RPC_NDR_SPOOLSS +- smbconf +- secrets3''', ++ RPC_NDR_SPOOLSS ++ smbconf ++ secrets3 ++ gensec ++ ''', + private_library=True) + + bld.SAMBA3_SUBSYSTEM('LIBCLI_WINREG', +diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c +index f97263dcc5b..4847e8a0200 100644 +--- a/source4/librpc/rpc/dcerpc.c ++++ b/source4/librpc/rpc/dcerpc.c +@@ -27,6 +27,7 @@ + #include "librpc/rpc/dcerpc.h" + #include "librpc/rpc/dcerpc_proto.h" + #include "librpc/rpc/dcerpc_util.h" ++#include "librpc/rpc/dcerpc_pkt_auth.h" + #include "librpc/gen_ndr/ndr_misc.h" + #include "librpc/gen_ndr/ndr_dcerpc.h" + #include "auth/gensec/gensec.h" +diff --git a/source4/librpc/wscript_build b/source4/librpc/wscript_build +index ea9c4853d7a..511008d919d 100644 +--- a/source4/librpc/wscript_build ++++ b/source4/librpc/wscript_build +@@ -157,7 +157,26 @@ bld.SAMBA_LIBRARY('dcerpc', + rpc/dcerpc_roh_channel_in.c rpc/dcerpc_roh_channel_out.c rpc/dcerpc_roh.c + rpc/dcerpc_connect.c rpc/dcerpc_secondary.c''', + pc_files='dcerpc.pc', +- deps='samba_socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 ndr NDR_DCERPC RPC_NDR_EPMAPPER NDR_SCHANNEL RPC_NDR_NETLOGON RPC_NDR_MGMT gensec LIBCLI_AUTH smbclient-raw LP_RESOLVE tevent-util dcerpc-binding param_options http', ++ deps=''' ++ samba_socket ++ LIBCLI_RESOLVE ++ LIBCLI_SMB ++ LIBCLI_SMB2 ++ ndr ++ NDR_DCERPC ++ RPC_NDR_EPMAPPER ++ NDR_SCHANNEL ++ RPC_NDR_NETLOGON ++ RPC_NDR_MGMT ++ gensec ++ LIBCLI_AUTH ++ smbclient-raw ++ LP_RESOLVE ++ tevent-util ++ dcerpc-binding ++ dcerpc-pkt-auth ++ param_options ++ http''', + autoproto='rpc/dcerpc_proto.h', + public_deps='samba-credentials tevent talloc', + public_headers='''rpc/dcerpc.h''', +-- +2.25.1 + + +From fba123a44e0afd9d2377e3e45b0b2d88aecb2136 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 13 Nov 2020 11:25:41 +0100 +Subject: [PATCH 3/9] CVE-2021-23192: dcesrv_core: add better debugging to + dcesrv_fault_disconnect() + +It's better to see the location that triggered the fault. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + librpc/rpc/dcesrv_core.c | 29 ++++++++++++++++++++++++----- + 1 file changed, 24 insertions(+), 5 deletions(-) + +diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c +index 74730f22c7c..0c2d83b4b17 100644 +--- a/librpc/rpc/dcesrv_core.c ++++ b/librpc/rpc/dcesrv_core.c +@@ -705,19 +705,38 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason) + return NT_STATUS_OK; + } + +-static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call, +- uint32_t fault_code) ++static NTSTATUS _dcesrv_fault_disconnect_flags(struct dcesrv_call_state *call, ++ uint32_t fault_code, ++ uint8_t extra_flags, ++ const char *func, ++ const char *location) + { ++ const char *reason = NULL; ++ ++ reason = talloc_asprintf(call, "%s:%s: fault=%u (%s) flags=0x%x", ++ func, location, ++ fault_code, ++ dcerpc_errstr(call, fault_code), ++ extra_flags); ++ if (reason == NULL) { ++ reason = location; ++ } ++ + /* + * We add the call to the pending_call_list + * in order to defer the termination. + */ +- dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect"); + +- return dcesrv_fault_with_flags(call, fault_code, +- DCERPC_PFC_FLAG_DID_NOT_EXECUTE); ++ dcesrv_call_disconnect_after(call, reason); ++ ++ return dcesrv_fault_with_flags(call, fault_code, extra_flags); + } + ++#define dcesrv_fault_disconnect(call, fault_code) \ ++ _dcesrv_fault_disconnect_flags(call, fault_code, \ ++ DCERPC_PFC_FLAG_DID_NOT_EXECUTE, \ ++ __func__, __location__) ++ + static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c) + { + DLIST_REMOVE(c->conn->contexts, c); +-- +2.25.1 + + +From 937d9c1b4926aa4b511d1eb4f9b1729fb20ac9fa Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 13 Nov 2020 11:27:19 +0100 +Subject: [PATCH 4/9] CVE-2021-23192: dcesrv_core: add + dcesrv_fault_disconnect0() that skips DCERPC_PFC_FLAG_DID_NOT_EXECUTE + +That makes the callers much simpler and allow better debugging. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + librpc/rpc/dcesrv_core.c | 47 ++++++++++++++-------------------------- + 1 file changed, 16 insertions(+), 31 deletions(-) + +diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c +index 0c2d83b4b17..ffaa9019d4b 100644 +--- a/librpc/rpc/dcesrv_core.c ++++ b/librpc/rpc/dcesrv_core.c +@@ -736,6 +736,9 @@ static NTSTATUS _dcesrv_fault_disconnect_flags(struct dcesrv_call_state *call, + _dcesrv_fault_disconnect_flags(call, fault_code, \ + DCERPC_PFC_FLAG_DID_NOT_EXECUTE, \ + __func__, __location__) ++#define dcesrv_fault_disconnect0(call, fault_code) \ ++ _dcesrv_fault_disconnect_flags(call, fault_code, 0, \ ++ __func__, __location__) + + static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c) + { +@@ -2097,10 +2100,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + * Note that we don't check against the negotiated + * max_recv_frag, but a hard coded value. + */ +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - frag_length too large"); +- return dcesrv_fault(call, +- DCERPC_NCA_S_PROTO_ERROR); ++ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR); + } + + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) { +@@ -2110,10 +2110,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + * if DCERPC_PFC_FLAG_CONC_MPX was negotiated. + */ + if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - " +- "existing pending call without CONN_MPX"); +- return dcesrv_fault(call, ++ return dcesrv_fault_disconnect0(call, + DCERPC_NCA_S_PROTO_ERROR); + } + } +@@ -2131,10 +2128,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + TALLOC_FREE(call); + call = dce_conn->incoming_fragmented_call_list; + } +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - " +- "existing fragmented call"); +- return dcesrv_fault(call, ++ return dcesrv_fault_disconnect0(call, + DCERPC_NCA_S_PROTO_ERROR); + } + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) { +@@ -2155,10 +2149,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + existing = dcesrv_find_fragmented_call(dce_conn, + call->pkt.call_id); + if (existing == NULL) { +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - " +- "no existing fragmented call"); +- return dcesrv_fault(call, ++ return dcesrv_fault_disconnect0(call, + DCERPC_NCA_S_PROTO_ERROR); + } + er = &existing->pkt.u.request; +@@ -2211,12 +2202,10 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + * here, because we don't want to set + * DCERPC_PFC_FLAG_DID_NOT_EXECUTE + */ +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - failed"); + if (call->fault_code == 0) { + call->fault_code = DCERPC_FAULT_ACCESS_DENIED; + } +- return dcesrv_fault(call, call->fault_code); ++ return dcesrv_fault_disconnect0(call, call->fault_code); + } + } + +@@ -2233,20 +2222,17 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + */ + available = dce_conn->max_total_request_size; + if (er->stub_and_verifier.length > available) { +- dcesrv_call_disconnect_after(existing, +- "dcesrv_auth_request - existing payload too large"); +- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); ++ return dcesrv_fault_disconnect0(existing, ++ DCERPC_FAULT_ACCESS_DENIED); + } + available -= er->stub_and_verifier.length; + if (nr->alloc_hint > available) { +- dcesrv_call_disconnect_after(existing, +- "dcesrv_auth_request - alloc hint too large"); +- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); ++ return dcesrv_fault_disconnect0(existing, ++ DCERPC_FAULT_ACCESS_DENIED); + } + if (nr->stub_and_verifier.length > available) { +- dcesrv_call_disconnect_after(existing, +- "dcesrv_auth_request - new payload too large"); +- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED); ++ return dcesrv_fault_disconnect0(existing, ++ DCERPC_FAULT_ACCESS_DENIED); + } + alloc_hint = er->stub_and_verifier.length + nr->alloc_hint; + /* allocate at least 1 byte */ +@@ -2285,9 +2271,8 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + * Up to 4 MByte are allowed by all fragments + */ + if (call->pkt.u.request.alloc_hint > dce_conn->max_total_request_size) { +- dcesrv_call_disconnect_after(call, +- "dcesrv_auth_request - initial alloc hint too large"); +- return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); ++ return dcesrv_fault_disconnect0(call, ++ DCERPC_FAULT_ACCESS_DENIED); + } + dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST); + return NT_STATUS_OK; +-- +2.25.1 + + +From 480bfd0a809705966d782839f02f899fc3f68241 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Wed, 11 Nov 2020 16:59:06 +0100 +Subject: [PATCH 5/9] CVE-2021-23192: python/tests/dcerpc: change + assertNotEquals() into assertNotEqual() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + python/samba/tests/dcerpc/raw_protocol.py | 288 +++++++++++----------- + python/samba/tests/dcerpc/raw_testcase.py | 14 +- + 2 files changed, 151 insertions(+), 151 deletions(-) + +diff --git a/python/samba/tests/dcerpc/raw_protocol.py b/python/samba/tests/dcerpc/raw_protocol.py +index dc13d41c6a2..cbd398d5290 100755 +--- a/python/samba/tests/dcerpc/raw_protocol.py ++++ b/python/samba/tests/dcerpc/raw_protocol.py +@@ -65,7 +65,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=rep_pfc_flags, auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -86,7 +86,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -108,7 +108,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -128,7 +128,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=rep_pfc_flags, auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertEqual(rep.u.secondary_address, "") + self.assertPadding(rep.u._pad1, 2) +@@ -149,7 +149,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -396,7 +396,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -469,7 +469,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -489,7 +489,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -521,7 +521,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -541,7 +541,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -562,7 +562,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, ctx1.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -589,7 +589,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -609,7 +609,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -630,7 +630,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -646,7 +646,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -705,7 +705,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -732,7 +732,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -765,7 +765,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -794,7 +794,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -826,7 +826,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -855,7 +855,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -876,7 +876,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, ctx1a.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -902,7 +902,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -928,7 +928,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -947,7 +947,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -966,7 +966,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -985,7 +985,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1004,7 +1004,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 1) +@@ -1023,7 +1023,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1049,7 +1049,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 2) +@@ -1073,7 +1073,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1085,7 +1085,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 2) +@@ -1109,7 +1109,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1122,7 +1122,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1134,7 +1134,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 2) +@@ -1158,7 +1158,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1171,7 +1171,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1197,7 +1197,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 2) +@@ -1221,7 +1221,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1233,7 +1233,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 0) + self.assertPadding(rep.u._pad1, 2) + self.assertEqual(rep.u.num_results, 2) +@@ -1257,7 +1257,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1282,7 +1282,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1318,7 +1318,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1352,7 +1352,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1424,7 +1424,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1459,7 +1459,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1494,7 +1494,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1617,7 +1617,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1638,7 +1638,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1658,7 +1658,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -1708,7 +1708,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, rep_both) + self.assertEqual(rep.u.max_recv_frag, rep_both) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1760,7 +1760,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu(ndr_print=True, hexdump=True) + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1775,7 +1775,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1791,7 +1791,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -1866,7 +1866,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + auth_length=0) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -1888,7 +1888,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1902,7 +1902,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1916,7 +1916,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -1994,7 +1994,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2014,7 +2014,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2036,7 +2036,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2052,7 +2052,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2098,7 +2098,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2128,7 +2128,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2195,7 +2195,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + dcerpc.DCERPC_PFC_FLAG_LAST | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2243,7 +2243,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2277,7 +2277,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2313,7 +2313,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST | + dcerpc.DCERPC_PFC_FLAG_LAST, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2341,7 +2341,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2376,7 +2376,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2390,7 +2390,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2415,7 +2415,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2450,7 +2450,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2464,7 +2464,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2503,7 +2503,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2517,7 +2517,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2552,7 +2552,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req1.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req1.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2600,7 +2600,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req2.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2650,7 +2650,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -2660,7 +2660,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -2691,7 +2691,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -2707,7 +2707,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2727,7 +2727,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -2747,7 +2747,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2805,7 +2805,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -2815,7 +2815,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -2846,7 +2846,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -2868,7 +2868,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -2926,7 +2926,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + assoc_group_id = rep.u.assoc_group_id + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) +@@ -2937,7 +2937,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -2961,7 +2961,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3009,7 +3009,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3019,7 +3019,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3047,7 +3047,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We get a fault back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3098,7 +3098,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3108,7 +3108,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3137,7 +3137,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3153,7 +3153,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -3173,7 +3173,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -3205,7 +3205,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3256,7 +3256,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3266,7 +3266,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3295,7 +3295,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3311,7 +3311,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -3331,7 +3331,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -3362,7 +3362,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3409,7 +3409,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3419,7 +3419,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3440,7 +3440,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3493,7 +3493,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3503,7 +3503,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3524,7 +3524,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3579,7 +3579,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3589,7 +3589,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3611,7 +3611,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3659,7 +3659,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3669,7 +3669,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3691,7 +3691,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3746,7 +3746,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3756,7 +3756,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3778,7 +3778,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3833,7 +3833,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3843,7 +3843,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3865,7 +3865,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -3930,7 +3930,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -3940,7 +3940,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -3984,7 +3984,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -4000,7 +4000,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4020,7 +4020,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4144,7 +4144,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -4154,7 +4154,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -4191,7 +4191,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -4256,7 +4256,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -4266,7 +4266,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -4295,7 +4295,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + rep = self.recv_pdu() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4315,7 +4315,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + # We don't get an auth_info back + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4375,7 +4375,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id) + self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag) + self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag) +- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id) ++ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id) + self.assertEqual(rep.u.secondary_address_size, 4) + self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port) + self.assertPadding(rep.u._pad1, 2) +@@ -4385,7 +4385,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.assertEqual(rep.u.ctx_list[0].reason, + dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED) + self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32) +- self.assertNotEquals(len(rep.u.auth_info), 0) ++ self.assertNotEqual(len(rep.u.auth_info), 0) + a = self.parse_auth(rep.u.auth_info) + + from_server = a.credentials +@@ -4406,7 +4406,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -4521,7 +4521,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=req.pfc_flags | response_fault_flags, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, ctx1.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -4688,7 +4688,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + (rep, rep_blob) = self.recv_pdu_raw() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=sig_size) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4756,7 +4756,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + pfc_flags=req.pfc_flags | + dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, ctx1.context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -4805,7 +4805,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + (rep, rep_blob) = self.recv_pdu_raw() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=sig_size) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +@@ -4870,7 +4870,7 @@ class TestDCERPC_BIND(RawDCERPCTest): + (rep, rep_blob) = self.recv_pdu_raw() + self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=sig_size) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py +index f1c097ebe6d..ed77d329cd5 100644 +--- a/python/samba/tests/dcerpc/raw_testcase.py ++++ b/python/samba/tests/dcerpc/raw_testcase.py +@@ -321,7 +321,7 @@ class RawDCERPCTest(TestCase): + pfc_flags=req.pfc_flags | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -361,7 +361,7 @@ class RawDCERPCTest(TestCase): + if assoc_group_id != 0: + self.assertEqual(rep.u.assoc_group_id, assoc_group_id) + else: +- self.assertNotEquals(rep.u.assoc_group_id, 0) ++ self.assertNotEqual(rep.u.assoc_group_id, 0) + assoc_group_id = rep.u.assoc_group_id + sda_str = self.secondary_address + sda_len = len(sda_str) + 1 +@@ -385,7 +385,7 @@ class RawDCERPCTest(TestCase): + self.assertEqual(rep.auth_length, 0) + self.assertEqual(len(rep.u.auth_info), 0) + return ack +- self.assertNotEquals(rep.auth_length, 0) ++ self.assertNotEqual(rep.auth_length, 0) + self.assertGreater(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH) + self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH) + +@@ -426,7 +426,7 @@ class RawDCERPCTest(TestCase): + pfc_flags=req.pfc_flags | + samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE, + auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, 0) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -451,7 +451,7 @@ class RawDCERPCTest(TestCase): + if finished: + self.assertEqual(rep.auth_length, 0) + else: +- self.assertNotEquals(rep.auth_length, 0) ++ self.assertNotEqual(rep.auth_length, 0) + self.assertGreaterEqual(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH) + self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH) + +@@ -547,7 +547,7 @@ class RawDCERPCTest(TestCase): + if fault_status: + self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id, + pfc_flags=fault_pfc_flags, auth_length=0) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, fault_context_id) + self.assertEqual(rep.u.cancel_count, 0) + self.assertEqual(rep.u.flags, 0) +@@ -563,7 +563,7 @@ class RawDCERPCTest(TestCase): + + self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, req.call_id, + auth_length=expected_auth_length) +- self.assertNotEquals(rep.u.alloc_hint, 0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) +-- +2.25.1 + + +From 4ec27da793964c3c49995ada3da047bae0174d26 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 17 Nov 2020 09:50:58 +0100 +Subject: [PATCH 6/9] CVE-2021-23192: python/tests/dcerpc: let + generate_request_auth() use g_auth_level in all places + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + python/samba/tests/dcerpc/raw_testcase.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py +index ed77d329cd5..53f7fa0a2a8 100644 +--- a/python/samba/tests/dcerpc/raw_testcase.py ++++ b/python/samba/tests/dcerpc/raw_testcase.py +@@ -922,12 +922,12 @@ class RawDCERPCTest(TestCase): + req_data = req_blob[ofs_stub:ofs_trailer] + req_whole = req_blob[0:ofs_sig] + +- if auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY: ++ if auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY: + # TODO: not yet supported here + self.assertTrue(False) +- elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET: ++ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET: + req_sig = auth_context["gensec"].sign_packet(req_data, req_whole) +- elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT: ++ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT: + self.assertEqual(auth_context["auth_type"], + dcerpc.DCERPC_AUTH_TYPE_NTLMSSP) + req_sig = b"\x01" +b"\x00" *15 +-- +2.25.1 + + +From 188f01b8ac8b84e9e41a769731cb4426658920cb Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 17 Nov 2020 17:43:06 +0100 +Subject: [PATCH 7/9] CVE-2021-23192: python/tests/dcerpc: fix + do_single_request(send_req=False) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + python/samba/tests/dcerpc/raw_testcase.py | 37 ++++++++++++----------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py +index 53f7fa0a2a8..22b56704fa3 100644 +--- a/python/samba/tests/dcerpc/raw_testcase.py ++++ b/python/samba/tests/dcerpc/raw_testcase.py +@@ -526,26 +526,25 @@ class RawDCERPCTest(TestCase): + if hexdump: + sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in))) + +- pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST +- pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST +- if object is not None: +- pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID +- +- req = self.generate_request_auth(call_id=call_id, +- context_id=ctx.context_id, +- pfc_flags=pfc_flags, +- object=object, +- opnum=io.opnum(), +- stub=stub_in, +- auth_context=auth_context) +- if send_req: ++ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST ++ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST ++ if object is not None: ++ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID ++ ++ req = self.generate_request_auth(call_id=call_id, ++ context_id=ctx.context_id, ++ pfc_flags=pfc_flags, ++ object=object, ++ opnum=io.opnum(), ++ stub=stub_in, ++ auth_context=auth_context) + self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump) + if recv_rep: + (rep, rep_blob) = self.recv_pdu_raw(timeout=timeout, + ndr_print=ndr_print, + hexdump=hexdump) + if fault_status: +- self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id, ++ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, call_id, + pfc_flags=fault_pfc_flags, auth_length=0) + self.assertNotEqual(rep.u.alloc_hint, 0) + self.assertEqual(rep.u.context_id, fault_context_id) +@@ -559,12 +558,16 @@ class RawDCERPCTest(TestCase): + expected_auth_length = 0 + if auth_context is not None and \ + auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET: +- expected_auth_length = req.auth_length ++ if send_req: ++ expected_auth_length = req.auth_length ++ else: ++ expected_auth_length = rep.auth_length ++ + +- self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, req.call_id, ++ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, call_id, + auth_length=expected_auth_length) + self.assertNotEqual(rep.u.alloc_hint, 0) +- self.assertEqual(rep.u.context_id, req.u.context_id & 0xff) ++ self.assertEqual(rep.u.context_id, ctx.context_id & 0xff) + self.assertEqual(rep.u.cancel_count, 0) + self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint) + stub_out = self.check_response_auth(rep, rep_blob, auth_context) +-- +2.25.1 + + +From 7cf3a4a33282ed5b135fcdc47a5cc7cdca370ee7 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 17 Nov 2020 18:14:46 +0100 +Subject: [PATCH 8/9] CVE-2021-23192: python/tests/dcerpc: add tests to check + how security contexts relate to fragmented requests + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + python/samba/tests/dcerpc/raw_protocol.py | 1273 +++++++++++++++++++++ + selftest/knownfail.d/dcerpc-auth-fraq | 20 + + 2 files changed, 1293 insertions(+) + create mode 100644 selftest/knownfail.d/dcerpc-auth-fraq + +diff --git a/python/samba/tests/dcerpc/raw_protocol.py b/python/samba/tests/dcerpc/raw_protocol.py +index cbd398d5290..3c9d0b136a5 100755 +--- a/python/samba/tests/dcerpc/raw_protocol.py ++++ b/python/samba/tests/dcerpc/raw_protocol.py +@@ -1683,6 +1683,1279 @@ class TestDCERPC_BIND(RawDCERPCTest): + def test_auth_none_packet_request(self): + return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_PACKET) + ++ def test_ntlmssp_multi_auth_first1_lastSame2(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR ++ auth_context_2nd = 2 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastNext2(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 2 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastSame111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = None ++ auth_context_2nd = 1 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastNext111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_lastNext111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastSameNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastNextNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastSameNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_lastNextNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_last(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def _test_generic_auth_first_2nd(self, ++ auth_type, ++ pfc_flags_2nd, ++ expected_fault, ++ auth_context_2nd=2, ++ skip_first=False, ++ expected_call_id=None, ++ expected_context_id=None, ++ conc_mpx=False, ++ not_executed=False, ++ forced_call_id=None, ++ forced_context_id=None, ++ forced_opnum=None, ++ forced_auth_context_id=None, ++ forced_auth_type=None, ++ forced_auth_level=None): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY ++ auth_context_id1=1 ++ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_PACKET ++ auth_context_id2=2 ++ ++ creds = self.get_user_creds() ++ ++ abstract = samba.dcerpc.mgmt.abstract_syntax() ++ transfer = base.transfer_syntax_ndr() ++ ++ tsf1_list = [transfer] ++ ctx = samba.dcerpc.dcerpc.ctx_list() ++ ctx.context_id = 1 ++ ctx.num_transfer_syntaxes = len(tsf1_list) ++ ctx.abstract_syntax = abstract ++ ctx.transfer_syntaxes = tsf1_list ++ ++ auth_context1 = self.get_auth_context_creds(creds=creds, ++ auth_type=auth_type, ++ auth_level=auth_level1, ++ auth_context_id=auth_context_id1, ++ hdr_signing=False) ++ auth_context2 = self.get_auth_context_creds(creds=creds, ++ auth_type=auth_type, ++ auth_level=auth_level2, ++ auth_context_id=auth_context_id2, ++ hdr_signing=False) ++ ++ bind_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST ++ if conc_mpx: ++ bind_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_CONC_MPX ++ ++ ack0 = self.do_generic_bind(call_id=0, ++ ctx=ctx, ++ pfc_flags=bind_pfc_flags) ++ ++ ack1 = self.do_generic_bind(call_id=1, ++ ctx=ctx, ++ auth_context=auth_context1, ++ assoc_group_id = ack0.u.assoc_group_id, ++ start_with_alter=True) ++ if auth_context_2nd == 2: ++ ack2 = self.do_generic_bind(call_id=2, ++ ctx=ctx, ++ auth_context=auth_context2, ++ assoc_group_id = ack0.u.assoc_group_id, ++ start_with_alter=True) ++ ++ ndr_print = self.do_ndr_print ++ hexdump = self.do_hexdump ++ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids() ++ io = inq_if_ids ++ if ndr_print: ++ sys.stderr.write("in: %s" % samba.ndr.ndr_print_in(io)) ++ stub_in = samba.ndr.ndr_pack_in(io) ++ stub_in += b'\xfe'*45 # add some padding in order to have some payload ++ if hexdump: ++ sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in))) ++ ++ call_id = 3 ++ context_id = ctx.context_id ++ opnum = io.opnum() ++ ++ if not skip_first: ++ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST ++ stub_in_tmp = stub_in[0:16] ++ req = self.generate_request_auth(call_id=call_id, ++ context_id=context_id, ++ pfc_flags=pfc_flags, ++ opnum=opnum, ++ alloc_hint=len(stub_in), ++ stub=stub_in_tmp, ++ auth_context=auth_context1) ++ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump) ++ rep = self.recv_pdu(timeout=0.01) ++ self.assertIsNone(rep) ++ self.assertIsConnected() ++ ++ # context_id, opnum and auth header values are completely ignored ++ if auth_context_2nd == 1: ++ auth_context_copy = auth_context1.copy() ++ elif auth_context_2nd == 2: ++ auth_context_copy = auth_context2.copy() ++ else: ++ auth_context_copy = None ++ ++ expected_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST ++ if expected_context_id is None: ++ expected_context_id = context_id ++ if expected_call_id is None: ++ expected_call_id = call_id ++ if not_executed: ++ expected_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE ++ ++ if forced_call_id is not None: ++ call_id = forced_call_id ++ if forced_context_id is not None: ++ context_id = forced_context_id ++ if forced_opnum is not None: ++ opnum = forced_opnum ++ if forced_auth_context_id is not None: ++ auth_context_copy["auth_context_id"] = forced_auth_context_id ++ if forced_auth_type is not None: ++ auth_context_copy["auth_type"] = forced_auth_type ++ if forced_auth_level is not None: ++ auth_context_copy["auth_level"] = forced_auth_level ++ ++ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST ++ stub_in_tmp = stub_in[16:-1] ++ req = self.generate_request_auth(call_id=call_id, ++ context_id=context_id, ++ pfc_flags=pfc_flags_2nd, ++ opnum=opnum, ++ alloc_hint=len(stub_in_tmp), ++ stub=stub_in_tmp, ++ auth_context=auth_context_copy) ++ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump) ++ if expected_fault is None: ++ self.do_single_request(call_id=3, ctx=ctx, io=io, send_req=False, auth_context=auth_context1) ++ return ++ rep = self.recv_pdu() ++ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, expected_call_id, ++ pfc_flags=expected_pfc_flags, ++ auth_length=0) ++ self.assertNotEqual(rep.u.alloc_hint, 0) ++ self.assertEqual(rep.u.context_id, expected_context_id) ++ self.assertEqual(rep.u.cancel_count, 0) ++ self.assertEqual(rep.u.flags, 0) ++ self.assertEqual(rep.u.status, expected_fault) ++ self.assertEqual(rep.u.reserved, 0) ++ self.assertEqual(len(rep.u.error_and_verifier), 0) ++ ++ if not_executed: ++ # still alive ++ rep = self.recv_pdu(timeout=0.01) ++ self.assertIsNone(rep) ++ self.assertIsConnected() ++ return ++ ++ # wait for a disconnect ++ rep = self.recv_pdu() ++ self.assertIsNone(rep) ++ self.assertNotConnected() ++ ++ def _test_generic_auth_first_last(self, ++ auth_type, ++ expected_fault, ++ auth_context_2nd=2, ++ expected_call_id=None, ++ expected_context_id=None, ++ conc_mpx=False, ++ not_executed=False, ++ forced_call_id=None, ++ forced_context_id=None, ++ forced_opnum=None, ++ forced_auth_context_id=None, ++ forced_auth_type=None, ++ forced_auth_level=None): ++ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST ++ return self._test_generic_auth_first_2nd(auth_type, ++ pfc_flags_2nd, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def _test_generic_auth_first_first(self, ++ auth_type, ++ expected_fault, ++ auth_context_2nd=2, ++ expected_call_id=None, ++ expected_context_id=None, ++ conc_mpx=False, ++ not_executed=False, ++ forced_call_id=None, ++ forced_context_id=None, ++ forced_opnum=None, ++ forced_auth_context_id=None, ++ forced_auth_type=None, ++ forced_auth_level=None): ++ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST ++ return self._test_generic_auth_first_2nd(auth_type, ++ pfc_flags_2nd, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstSame2(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR ++ auth_context_2nd = 2 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstNext2(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 2 ++ expected_call_id = 3 ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstSame111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstSame111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstNext111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = 3 ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstNext111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = 1 ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstSameNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = None ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstNextNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstSameNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = None ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_first1_firstNextNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = None ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = False ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ auth_context_2nd = None ++ expected_call_id = 4 ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = True ++ forced_call_id = 4 ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_first_first(auth_type, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def _test_generic_auth_middle(self, ++ auth_type, ++ expected_fault, ++ expected_context_id=None, ++ not_executed=False, ++ conc_mpx=False, ++ forced_context_id=None, ++ forced_opnum=None, ++ forced_auth_context_id=None, ++ forced_auth_type=None, ++ forced_auth_level=None): ++ auth_context_2nd = 1 ++ skip_first = True ++ pfc_flags_2nd = 0 ++ expected_call_id = None ++ forced_call_id = None ++ return self._test_generic_auth_first_2nd(auth_type, ++ pfc_flags_2nd, ++ expected_fault, ++ auth_context_2nd=auth_context_2nd, ++ skip_first=skip_first, ++ expected_call_id=expected_call_id, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_call_id=forced_call_id, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_alone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_alone(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_all_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_all_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_UNKNOWN_IF ++ expected_context_id = 0 ++ not_executed = True ++ conc_mpx = True ++ forced_context_id = 111 ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_auth_all_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = None ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_auth_all_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_context_id = None ++ forced_opnum = 111 ++ forced_auth_context_id = 111 ++ forced_auth_type = 111 ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_auth_context_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = 111 ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_auth_context_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = 111 ++ forced_auth_type = None ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_auth_type_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = 111 ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_auth_type_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = 111 ++ forced_auth_level = None ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_middle_auth_level_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR ++ expected_context_id = 0 ++ not_executed = False ++ conc_mpx = False ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ ++ def test_ntlmssp_auth_MPX_middle_auth_level_111(self): ++ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP ++ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED ++ expected_context_id = None ++ not_executed = False ++ conc_mpx = True ++ forced_context_id = None ++ forced_opnum = None ++ forced_auth_context_id = None ++ forced_auth_type = None ++ forced_auth_level = 111 ++ return self._test_generic_auth_middle(auth_type, ++ expected_fault, ++ expected_context_id=expected_context_id, ++ not_executed=not_executed, ++ conc_mpx=conc_mpx, ++ forced_context_id=forced_context_id, ++ forced_opnum=forced_opnum, ++ forced_auth_context_id=forced_auth_context_id, ++ forced_auth_type=forced_auth_type, ++ forced_auth_level=forced_auth_level) ++ + def _test_neg_xmit_check_values(self, + req_xmit=None, + req_recv=None, +diff --git a/selftest/knownfail.d/dcerpc-auth-fraq b/selftest/knownfail.d/dcerpc-auth-fraq +new file mode 100644 +index 00000000000..f3c62b65e9e +--- /dev/null ++++ b/selftest/knownfail.d/dcerpc-auth-fraq +@@ -0,0 +1,20 @@ ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_all_111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_alone ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_all_111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_context_111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_level_111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_type_111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSame111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_firstSame2 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext2 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame111 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame2 ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone ++^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone111 +-- +2.25.1 + + +From 43b09da3138606e2d0fbc033e8bc50fa82687946 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 16 Nov 2020 14:15:06 +0100 +Subject: [PATCH 9/9] CVE-2021-23192: dcesrv_core: only the first fragment + specifies the auth_contexts + +All other fragments blindly inherit it. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + librpc/rpc/dcerpc_pkt_auth.c | 19 +++--- + librpc/rpc/dcerpc_pkt_auth.h | 1 + + librpc/rpc/dcesrv_auth.c | 28 +++++++++ + librpc/rpc/dcesrv_core.c | 86 +++++++++++++++++++++------ + selftest/knownfail.d/dcerpc-auth-fraq | 20 ------- + source4/librpc/rpc/dcerpc.c | 1 + + 6 files changed, 109 insertions(+), 46 deletions(-) + delete mode 100644 selftest/knownfail.d/dcerpc-auth-fraq + +diff --git a/librpc/rpc/dcerpc_pkt_auth.c b/librpc/rpc/dcerpc_pkt_auth.c +index 322d7497893..1cb191468b5 100644 +--- a/librpc/rpc/dcerpc_pkt_auth.c ++++ b/librpc/rpc/dcerpc_pkt_auth.c +@@ -39,6 +39,7 @@ + + NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, + struct gensec_security *gensec, ++ bool check_pkt_auth_fields, + TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t required_flags, +@@ -115,16 +116,18 @@ NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, + return NT_STATUS_INTERNAL_ERROR; + } + +- if (auth.auth_type != auth_state->auth_type) { +- return NT_STATUS_ACCESS_DENIED; +- } ++ if (check_pkt_auth_fields) { ++ if (auth.auth_type != auth_state->auth_type) { ++ return NT_STATUS_ACCESS_DENIED; ++ } + +- if (auth.auth_level != auth_state->auth_level) { +- return NT_STATUS_ACCESS_DENIED; +- } ++ if (auth.auth_level != auth_state->auth_level) { ++ return NT_STATUS_ACCESS_DENIED; ++ } + +- if (auth.auth_context_id != auth_state->auth_context_id) { +- return NT_STATUS_ACCESS_DENIED; ++ if (auth.auth_context_id != auth_state->auth_context_id) { ++ return NT_STATUS_ACCESS_DENIED; ++ } + } + + /* check signature or unseal the packet */ +diff --git a/librpc/rpc/dcerpc_pkt_auth.h b/librpc/rpc/dcerpc_pkt_auth.h +index c0d23b91c05..1dcee12f53c 100644 +--- a/librpc/rpc/dcerpc_pkt_auth.h ++++ b/librpc/rpc/dcerpc_pkt_auth.h +@@ -31,6 +31,7 @@ + + NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, + struct gensec_security *gensec, ++ bool check_pkt_auth_fields, + TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t required_flags, +diff --git a/librpc/rpc/dcesrv_auth.c b/librpc/rpc/dcesrv_auth.c +index 8dda86d88e2..9d8df6c42e2 100644 +--- a/librpc/rpc/dcesrv_auth.c ++++ b/librpc/rpc/dcesrv_auth.c +@@ -438,6 +438,10 @@ bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call) + return false; + } + ++ if (auth->auth_invalid) { ++ return false; ++ } ++ + /* We can't work without an existing gensec state */ + if (auth->gensec_security == NULL) { + return false; +@@ -524,6 +528,10 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call) + return false; + } + ++ if (auth->auth_invalid) { ++ return false; ++ } ++ + if (call->in_auth_info.auth_type != auth->auth_type) { + return false; + } +@@ -590,6 +598,7 @@ bool dcesrv_auth_pkt_pull(struct dcesrv_call_state *call, + .auth_level = auth->auth_level, + .auth_context_id = auth->auth_context_id, + }; ++ bool check_pkt_auth_fields; + NTSTATUS status; + + if (!auth->auth_started) { +@@ -605,8 +614,27 @@ bool dcesrv_auth_pkt_pull(struct dcesrv_call_state *call, + return false; + } + ++ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) { ++ /* ++ * The caller most likely checked this ++ * already, but we better double check. ++ */ ++ check_pkt_auth_fields = true; ++ } else { ++ /* ++ * The caller already found first fragment ++ * and is passing the auth_state of it. ++ * A server is supposed to use the ++ * setting of the first fragment and ++ * completely ignore the values ++ * on the remaining fragments ++ */ ++ check_pkt_auth_fields = false; ++ } ++ + status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth, + auth->gensec_security, ++ check_pkt_auth_fields, + call, + pkt->ptype, + required_flags, +diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c +index ffaa9019d4b..0bab4c10641 100644 +--- a/librpc/rpc/dcesrv_core.c ++++ b/librpc/rpc/dcesrv_core.c +@@ -1805,6 +1805,10 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) + struct ndr_pull *pull; + NTSTATUS status; + ++ if (auth->auth_invalid) { ++ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); ++ } ++ + if (!auth->auth_finished) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } +@@ -1968,6 +1972,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + enum dcerpc_AuthType auth_type = 0; + enum dcerpc_AuthLevel auth_level = 0; + uint32_t auth_context_id = 0; ++ bool auth_invalid = false; + + call = talloc_zero(dce_conn, struct dcesrv_call_state); + if (!call) { +@@ -1999,12 +2004,16 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + + if (call->auth_state == NULL) { + struct dcesrv_auth *a = NULL; ++ bool check_type_level = true; + + auth_type = dcerpc_get_auth_type(&blob); + auth_level = dcerpc_get_auth_level(&blob); + auth_context_id = dcerpc_get_auth_context_id(&blob); + + if (call->pkt.ptype == DCERPC_PKT_REQUEST) { ++ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) { ++ check_type_level = false; ++ } + dce_conn->default_auth_level_connect = NULL; + if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) { + dce_conn->got_explicit_auth_level_connect = true; +@@ -2014,14 +2023,19 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + for (a = dce_conn->auth_states; a != NULL; a = a->next) { + num_auth_ctx++; + +- if (a->auth_type != auth_type) { ++ if (a->auth_context_id != auth_context_id) { + continue; + } +- if (a->auth_finished && a->auth_level != auth_level) { +- continue; ++ ++ if (a->auth_type != auth_type) { ++ auth_invalid = true; + } +- if (a->auth_context_id != auth_context_id) { +- continue; ++ if (a->auth_level != auth_level) { ++ auth_invalid = true; ++ } ++ ++ if (check_type_level && auth_invalid) { ++ a->auth_invalid = true; + } + + DLIST_PROMOTE(dce_conn->auth_states, a); +@@ -2048,6 +2062,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + /* + * This can never be valid. + */ ++ auth_invalid = true; + a->auth_invalid = true; + } + call->auth_state = a; +@@ -2116,6 +2131,18 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + } + /* only one request is possible in the fragmented list */ + if (dce_conn->incoming_fragmented_call_list != NULL) { ++ call->fault_code = DCERPC_NCA_S_PROTO_ERROR; ++ ++ existing = dcesrv_find_fragmented_call(dce_conn, ++ call->pkt.call_id); ++ if (existing != NULL && call->auth_state != existing->auth_state) { ++ call->context = dcesrv_find_context(call->conn, ++ call->pkt.u.request.context_id); ++ ++ if (call->pkt.auth_length != 0 && existing->context == call->context) { ++ call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR; ++ } ++ } + if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { + /* + * Without DCERPC_PFC_FLAG_CONC_MPX +@@ -2125,11 +2152,14 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + * This is important to get the + * call_id and context_id right. + */ ++ dce_conn->incoming_fragmented_call_list->fault_code = call->fault_code; + TALLOC_FREE(call); + call = dce_conn->incoming_fragmented_call_list; + } +- return dcesrv_fault_disconnect0(call, +- DCERPC_NCA_S_PROTO_ERROR); ++ if (existing != NULL) { ++ call->context = existing->context; ++ } ++ return dcesrv_fault_disconnect0(call, call->fault_code); + } + if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) { + return dcesrv_fault_disconnect(call, +@@ -2142,17 +2172,43 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); + } + } else { +- const struct dcerpc_request *nr = &call->pkt.u.request; +- const struct dcerpc_request *er = NULL; + int cmp; + + existing = dcesrv_find_fragmented_call(dce_conn, + call->pkt.call_id); + if (existing == NULL) { ++ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { ++ /* ++ * Without DCERPC_PFC_FLAG_CONC_MPX ++ * we need to return the FAULT on the ++ * already existing call. ++ * ++ * This is important to get the ++ * call_id and context_id right. ++ */ ++ if (dce_conn->incoming_fragmented_call_list != NULL) { ++ TALLOC_FREE(call); ++ call = dce_conn->incoming_fragmented_call_list; ++ } ++ return dcesrv_fault_disconnect0(call, ++ DCERPC_NCA_S_PROTO_ERROR); ++ } ++ if (dce_conn->incoming_fragmented_call_list != NULL) { ++ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR); ++ } ++ call->context = dcesrv_find_context(call->conn, ++ call->pkt.u.request.context_id); ++ if (call->context == NULL) { ++ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF, ++ DCERPC_PFC_FLAG_DID_NOT_EXECUTE); ++ } ++ if (auth_invalid) { ++ return dcesrv_fault_disconnect0(call, ++ DCERPC_FAULT_ACCESS_DENIED); ++ } + return dcesrv_fault_disconnect0(call, + DCERPC_NCA_S_PROTO_ERROR); + } +- er = &existing->pkt.u.request; + + if (call->pkt.ptype != existing->pkt.ptype) { + /* trying to play silly buggers are we? */ +@@ -2165,14 +2221,8 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, + return dcesrv_fault_disconnect(existing, + DCERPC_NCA_S_PROTO_ERROR); + } +- if (nr->context_id != er->context_id) { +- return dcesrv_fault_disconnect(existing, +- DCERPC_NCA_S_PROTO_ERROR); +- } +- if (nr->opnum != er->opnum) { +- return dcesrv_fault_disconnect(existing, +- DCERPC_NCA_S_PROTO_ERROR); +- } ++ call->auth_state = existing->auth_state; ++ call->context = existing->context; + } + } + +diff --git a/selftest/knownfail.d/dcerpc-auth-fraq b/selftest/knownfail.d/dcerpc-auth-fraq +deleted file mode 100644 +index f3c62b65e9e..00000000000 +--- a/selftest/knownfail.d/dcerpc-auth-fraq ++++ /dev/null +@@ -1,20 +0,0 @@ +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_all_111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_alone +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_all_111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_context_111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_level_111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_type_111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSame111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_firstSame2 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext2 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame111 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame2 +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone +-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone111 +diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c +index 4847e8a0200..baf6df6e498 100644 +--- a/source4/librpc/rpc/dcerpc.c ++++ b/source4/librpc/rpc/dcerpc.c +@@ -726,6 +726,7 @@ static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c, + + status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth, + c->security_state.generic_state, ++ true, /* check_pkt_auth_fields */ + mem_ctx, + ptype, + required_flags, +-- +2.25.1 + diff --git a/SOURCES/samba-4.14-IPA-DC-add-missing-checks.patch b/SOURCES/samba-4.14-IPA-DC-add-missing-checks.patch new file mode 100644 index 0000000..7e33d59 --- /dev/null +++ b/SOURCES/samba-4.14-IPA-DC-add-missing-checks.patch @@ -0,0 +1,51 @@ +From c11dab13dd30af3e0beb69e8d47c3bfd85e18a91 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 12 Nov 2021 19:06:01 +0200 +Subject: [PATCH] IPA DC: add missing checks + +When introducing FreeIPA support, two places were forgotten: + + - schannel gensec module needs to be aware of IPA DC + - _lsa_QueryInfoPolicy should treat IPA DC as PDC + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14903 + +Signed-off-by: Alexander Bokovoy +Reviewed-by: Guenther Deschner + +Autobuild-User(master): Alexander Bokovoy +Autobuild-Date(master): Sat Nov 13 07:01:26 UTC 2021 on sn-devel-184 + +(cherry picked from commit c69b66f649c1d47a7367f7efe25b8df32369a3a5) +--- + auth/gensec/schannel.c | 1 + + source3/rpc_server/lsa/srv_lsa_nt.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c +index 0cdae141ead..6ebbe8f3179 100644 +--- a/auth/gensec/schannel.c ++++ b/auth/gensec/schannel.c +@@ -1080,6 +1080,7 @@ static NTSTATUS schannel_server_start(struct gensec_security *gensec_security) + case ROLE_DOMAIN_BDC: + case ROLE_DOMAIN_PDC: + case ROLE_ACTIVE_DIRECTORY_DC: ++ case ROLE_IPA_DC: + return NT_STATUS_OK; + default: + return NT_STATUS_NOT_IMPLEMENTED; +diff --git a/source3/rpc_server/lsa/srv_lsa_nt.c b/source3/rpc_server/lsa/srv_lsa_nt.c +index d6d606ddeca..36774be3e32 100644 +--- a/source3/rpc_server/lsa/srv_lsa_nt.c ++++ b/source3/rpc_server/lsa/srv_lsa_nt.c +@@ -683,6 +683,7 @@ NTSTATUS _lsa_QueryInfoPolicy(struct pipes_struct *p, + switch (lp_server_role()) { + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: ++ case ROLE_IPA_DC: + name = get_global_sam_name(); + sid = dom_sid_dup(p->mem_ctx, get_global_sam_sid()); + if (!sid) { +-- +2.33.1 + diff --git a/SOURCES/samba-4.14-fix-winbind-no-trusted-domain.patch b/SOURCES/samba-4.14-fix-winbind-no-trusted-domain.patch new file mode 100644 index 0000000..4924872 --- /dev/null +++ b/SOURCES/samba-4.14-fix-winbind-no-trusted-domain.patch @@ -0,0 +1,41 @@ +From 2edaf32b4204b9fe363c441c25b6989fe76911a4 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 9 Nov 2021 20:50:20 +0100 +Subject: [PATCH] s3:winbindd: fix "allow trusted domains = no" regression + +add_trusted_domain() should only reject domains +based on is_allowed_domain(), which now also +checks "allow trusted domains = no", if we don't +have an explicit trust to the domain (SEC_CHAN_NULL). + +We use at least SEC_CHAN_LOCAL for local domains like +BUILTIN. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14899 + +Signed-off-by: Stefan Metzmacher + +Autobuild-User(master): Stefan Metzmacher +Autobuild-Date(master): Wed Nov 10 11:21:31 UTC 2021 on sn-devel-184 + +(cherry picked from commit a7f6c60cb037b4bc9eee276236539b8282213935) +--- + source3/winbindd/winbindd_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c +index 42ddbfd2f44..9d54e462c42 100644 +--- a/source3/winbindd/winbindd_util.c ++++ b/source3/winbindd/winbindd_util.c +@@ -134,7 +134,7 @@ static NTSTATUS add_trusted_domain(const char *domain_name, + return NT_STATUS_INVALID_PARAMETER; + } + +- if (!is_allowed_domain(domain_name)) { ++ if (secure_channel_type == SEC_CHAN_NULL && !is_allowed_domain(domain_name)) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + +-- +2.33.1 + diff --git a/SOURCES/samba-4.14-krb5pac.patch b/SOURCES/samba-4.14-krb5pac.patch new file mode 100644 index 0000000..ff3e1ca --- /dev/null +++ b/SOURCES/samba-4.14-krb5pac.patch @@ -0,0 +1,298 @@ +From 97829843013e2f0d81b6ed61d155a04217e40205 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 1 Sep 2021 15:39:19 +1200 +Subject: [PATCH 1/6] krb5pac.idl: Add ticket checksum PAC buffer type + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +Reviewed-by: Isaac Boukris +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 +(cherry picked from commit ff2f38fae79220e16765e17671972f9a55eb7cce) +--- + librpc/idl/krb5pac.idl | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index fb360c1257f..3239d7656b6 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -112,7 +112,8 @@ interface krb5pac + PAC_TYPE_KDC_CHECKSUM = 7, + PAC_TYPE_LOGON_NAME = 10, + PAC_TYPE_CONSTRAINED_DELEGATION = 11, +- PAC_TYPE_UPN_DNS_INFO = 12 ++ PAC_TYPE_UPN_DNS_INFO = 12, ++ PAC_TYPE_TICKET_CHECKSUM = 16 + } PAC_TYPE; + + typedef struct { +@@ -128,6 +129,7 @@ interface krb5pac + [case(PAC_TYPE_CONSTRAINED_DELEGATION)][subcontext(0xFFFFFC01)] + PAC_CONSTRAINED_DELEGATION_CTR constrained_delegation; + [case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info; ++ [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum; + /* when new PAC info types are added they are supposed to be done + in such a way that they are backwards compatible with existing + servers. This makes it safe to just use a [default] for +-- +2.33.1 + + +From 99cc0e06e5fe2776371b808432af39de00f76cdf Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 1 Sep 2021 15:40:59 +1200 +Subject: [PATCH 2/6] security.idl: Add well-known SIDs for FAST + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +Reviewed-by: Isaac Boukris +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14881 +(cherry picked from commit 0092b4a3ed58b2c256d4dd9117cce927a3edde12) +--- + librpc/idl/security.idl | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl +index 06bf7449a70..3df96dedbdd 100644 +--- a/librpc/idl/security.idl ++++ b/librpc/idl/security.idl +@@ -295,6 +295,9 @@ interface security + const string SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1"; + const string SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2"; + ++ const string SID_COMPOUNDED_AUTHENTICATION = "S-1-5-21-0-0-0-496"; ++ const string SID_CLAIMS_VALID = "S-1-5-21-0-0-0-497"; ++ + /* + * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx + */ +-- +2.33.1 + + +From 693bcdb2f9b64af390d619c9b39293c581900151 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 29 Sep 2021 16:15:26 +1300 +Subject: [PATCH 3/6] krb5pac.idl: Add missing buffer type values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +Backported-by: Andreas Schneider +--- + librpc/idl/krb5pac.idl | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index 3239d7656b6..515150ab9cd 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -113,6 +113,9 @@ interface krb5pac + PAC_TYPE_LOGON_NAME = 10, + PAC_TYPE_CONSTRAINED_DELEGATION = 11, + PAC_TYPE_UPN_DNS_INFO = 12, ++ PAC_TYPE_CLIENT_CLAIMS_INFO = 13, ++ PAC_TYPE_DEVICE_INFO = 14, ++ PAC_TYPE_DEVICE_CLAIMS_INFO = 15, + PAC_TYPE_TICKET_CHECKSUM = 16 + } PAC_TYPE; + +-- +2.33.1 + + +From 97323751c1b6b97e72eb80b8b99485d94696b30b Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 26 Oct 2021 20:33:38 +1300 +Subject: [PATCH 4/6] CVE-2020-25719 krb5pac.idl: Add PAC_ATTRIBUTES_INFO PAC + buffer type + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + librpc/idl/krb5pac.idl | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index 515150ab9cd..7a8d16464eb 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -97,6 +97,16 @@ interface krb5pac + PAC_UPN_DNS_FLAGS flags; + } PAC_UPN_DNS_INFO; + ++ typedef [bitmap32bit] bitmap { ++ PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED = 0x00000001, ++ PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY = 0x00000002 ++ } PAC_ATTRIBUTE_INFO_FLAGS; ++ ++ typedef struct { ++ uint32 flags_length; /* length in bits */ ++ PAC_ATTRIBUTE_INFO_FLAGS flags; ++ } PAC_ATTRIBUTES_INFO; ++ + typedef [public] struct { + PAC_LOGON_INFO *info; + } PAC_LOGON_INFO_CTR; +@@ -116,7 +126,8 @@ interface krb5pac + PAC_TYPE_CLIENT_CLAIMS_INFO = 13, + PAC_TYPE_DEVICE_INFO = 14, + PAC_TYPE_DEVICE_CLAIMS_INFO = 15, +- PAC_TYPE_TICKET_CHECKSUM = 16 ++ PAC_TYPE_TICKET_CHECKSUM = 16, ++ PAC_TYPE_ATTRIBUTES_INFO = 17 + } PAC_TYPE; + + typedef struct { +@@ -133,6 +144,7 @@ interface krb5pac + PAC_CONSTRAINED_DELEGATION_CTR constrained_delegation; + [case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info; + [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum; ++ [case(PAC_TYPE_ATTRIBUTES_INFO)] PAC_ATTRIBUTES_INFO attributes_info; + /* when new PAC info types are added they are supposed to be done + in such a way that they are backwards compatible with existing + servers. This makes it safe to just use a [default] for +-- +2.33.1 + + +From 9867beabf3b0be026d900e26ac91af655fb50cfe Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 26 Oct 2021 20:33:49 +1300 +Subject: [PATCH 5/6] CVE-2020-25719 krb5pac.idl: Add PAC_REQUESTER_SID PAC + buffer type + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + librpc/idl/krb5pac.idl | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index 7a8d16464eb..52fb40c4bbb 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -107,6 +107,10 @@ interface krb5pac + PAC_ATTRIBUTE_INFO_FLAGS flags; + } PAC_ATTRIBUTES_INFO; + ++ typedef struct { ++ dom_sid sid; ++ } PAC_REQUESTER_SID; ++ + typedef [public] struct { + PAC_LOGON_INFO *info; + } PAC_LOGON_INFO_CTR; +@@ -127,7 +131,8 @@ interface krb5pac + PAC_TYPE_DEVICE_INFO = 14, + PAC_TYPE_DEVICE_CLAIMS_INFO = 15, + PAC_TYPE_TICKET_CHECKSUM = 16, +- PAC_TYPE_ATTRIBUTES_INFO = 17 ++ PAC_TYPE_ATTRIBUTES_INFO = 17, ++ PAC_TYPE_REQUESTER_SID = 18 + } PAC_TYPE; + + typedef struct { +@@ -145,6 +150,7 @@ interface krb5pac + [case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info; + [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum; + [case(PAC_TYPE_ATTRIBUTES_INFO)] PAC_ATTRIBUTES_INFO attributes_info; ++ [case(PAC_TYPE_REQUESTER_SID)] PAC_REQUESTER_SID requester_sid; + /* when new PAC info types are added they are supposed to be done + in such a way that they are backwards compatible with existing + servers. This makes it safe to just use a [default] for +-- +2.33.1 + + +From fb92457cfd11745be73660eb90519b625f6a5d97 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 27 Sep 2021 11:20:19 +1300 +Subject: [PATCH 6/6] CVE-2020-25721 krb5pac: Add new buffers for + samAccountName and objectSID + +These appear when PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID is set. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + librpc/idl/krb5pac.idl | 18 ++++++++++++++++-- + librpc/ndr/ndr_krb5pac.c | 4 ++-- + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index 52fb40c4bbb..bbe4a253e3a 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -86,15 +86,29 @@ interface krb5pac + } PAC_CONSTRAINED_DELEGATION; + + typedef [bitmap32bit] bitmap { +- PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001 ++ PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001, ++ PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID = 0x00000002 + } PAC_UPN_DNS_FLAGS; + ++ typedef struct { ++ [value(2*strlen_m(samaccountname))] uint16 samaccountname_size; ++ [relative_short,subcontext(0),subcontext_size(samaccountname_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *samaccountname; ++ [value(ndr_size_dom_sid(objectsid, ndr->flags))] uint16 objectsid_size; ++ [relative_short,subcontext(0),subcontext_size(objectsid_size)] dom_sid *objectsid; ++ } PAC_UPN_DNS_INFO_SAM_NAME_AND_SID; ++ ++ typedef [nodiscriminant] union { ++ [case(PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_SAM_NAME_AND_SID sam_name_and_sid; ++ [default]; ++ } PAC_UPN_DNS_INFO_EX; ++ + typedef struct { + [value(2*strlen_m(upn_name))] uint16 upn_name_size; + [relative_short,subcontext(0),subcontext_size(upn_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *upn_name; + [value(2*strlen_m(dns_domain_name))] uint16 dns_domain_name_size; + [relative_short,subcontext(0),subcontext_size(dns_domain_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *dns_domain_name; + PAC_UPN_DNS_FLAGS flags; ++ [switch_is(flags & PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_EX ex; + } PAC_UPN_DNS_INFO; + + typedef [bitmap32bit] bitmap { +@@ -160,7 +174,7 @@ interface krb5pac + + typedef [public,nopush,nopull] struct { + PAC_TYPE type; +- [value(_ndr_size_PAC_INFO(info, type, 0))] uint32 _ndr_size; ++ [value(_ndr_size_PAC_INFO(info, type, LIBNDR_FLAG_ALIGN8))] uint32 _ndr_size; + /* + * We need to have two subcontexts to get the padding right, + * the outer subcontext uses NDR_ROUND(_ndr_size, 8), while +diff --git a/librpc/ndr/ndr_krb5pac.c b/librpc/ndr/ndr_krb5pac.c +index a9ae2c4a789..57b28df9e52 100644 +--- a/librpc/ndr/ndr_krb5pac.c ++++ b/librpc/ndr/ndr_krb5pac.c +@@ -41,7 +41,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type)); +- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0))); ++ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,LIBNDR_FLAG_ALIGN8))); + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); +@@ -59,7 +59,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const + { + struct ndr_push *_ndr_info_pad; + struct ndr_push *_ndr_info; +- size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, 0); ++ size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8); + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8))); + NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size)); + NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type)); +-- +2.33.1 + diff --git a/SPECS/samba.spec b/SPECS/samba.spec index 8d636fa..057aab7 100644 --- a/SPECS/samba.spec +++ b/SPECS/samba.spec @@ -108,7 +108,7 @@ %define samba_requires_eq() %(LC_ALL="C" echo '%*' | xargs -r rpm -q --qf 'Requires: %%{name} = %%{epoch}:%%{version}\\n' | sed -e 's/ (none):/ /' -e 's/ 0:/ /' | grep -v "is not") -%global baserelease 2 +%global baserelease 7 %global samba_version 4.14.5 %global talloc_version 2.3.2 @@ -178,6 +178,12 @@ Source14: samba.pamd Source201: README.downgrade Patch0: samba-4.14-raise-dfs-enoent-debug-level.patch +Patch1: CVE-2016-2124.patch +Patch2: CVE-2021-23192.patch +Patch3: CVE-2020-25717.patch +Patch4: samba-4.14-krb5pac.patch +Patch5: samba-4.14-fix-winbind-no-trusted-domain.patch +Patch6: samba-4.14-IPA-DC-add-missing-checks.patch Requires(pre): /usr/sbin/groupadd Requires(post): systemd @@ -1692,6 +1698,7 @@ fi %{_libdir}/samba/libctdb-event-client-samba4.so %{_libdir}/samba/libdbwrap-samba4.so %{_libdir}/samba/libdcerpc-samba-samba4.so +%{_libdir}/samba/libdcerpc-pkt-auth-samba4.so %{_libdir}/samba/libevents-samba4.so %{_libdir}/samba/libflag-mapping-samba4.so %{_libdir}/samba/libgenrand-samba4.so @@ -3908,6 +3915,26 @@ fi %endif %changelog +* Mon Nov 22 2021 Andreas Schneider - 4.14.5-7 +- related: rhbz#2021171 - Fix CVE-2020-25717 +- Fix running ktest (selftest) + +* Sat Nov 13 2021 Alexander Bokovoy - 4.14.5-6 +- related: rhbz#2021171 - Fix CVE-2020-25717 +- Add missing checks for IPA DC server role + +* Tue Nov 09 2021 Andreas Schneider - 4.14.5-5 +- resolves: rhbz#2021493 - Add missing PAC buffer types to krb5pac.idl +- related: rbhz#2021171 - Fix regression with 'allow trusted domains = no' + +* Fri Nov 05 2021 Andreas Schneider - 4.14.4-4 +- resolves: rhbz#2021163 + Fix CVE-2016-2124 +- resolves: rhbz#2021167 + Fix CVE-2021-23192 +- resolves: rhbz#2021171 + Fix CVE-2020-25717 + * Tue Jul 13 2021 Andreas Schneider - 4.14.4-2 - related: rhbz#1980346 - Rebuild for libtalloc 0.11.0