From 9aa816f5017bd38cbb9af2af5a7c385647e4f76d Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Tue, 7 Jan 2020 19:25:53 +0200 Subject: [PATCH 001/142] s3-rpcserver: fix security level check for DsRGetForestTrustInformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Harmonize _netr_DsRGetForestTrustInformation with source4/ logic which didn't change since DCE RPC channel refactoring. With the current code we return RPC faul as can be seen in the logs: 2019/12/11 17:12:55.463081, 1, pid=20939, effective(1284200000, 1284200000), real(1284200000, 0), class=rpc_parse] ../librpc/ndr/ndr.c:471(ndr_print_function_debug) netr_DsRGetForestTrustInformation: struct netr_DsRGetForestTrustInformation in: struct netr_DsRGetForestTrustInformation server_name : * server_name : '\\some-dc.example.com' trusted_domain_name : NULL flags : 0x00000000 (0) [2019/12/11 17:12:55.463122, 4, pid=20939, effective(1284200000, 1284200000), real(1284200000, 0), class=rpc_srv] ../source3/rpc_server/srv_pipe.c:1561(api_rpcTNP) api_rpcTNP: fault(5) return. This is due to this check in processing a request: if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE) && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) { p->fault_state = DCERPC_FAULT_ACCESS_DENIED; return WERR_ACCESS_DENIED; } and since we get AuthZ response, Successful AuthZ: [netlogon,ncacn_np] user [EXAMPLE]\[admin] [S-1-5-21-1234567-890123456-500] at [Wed, 11 Dec 2019 17:12:55.461164 UTC] Remote host [ipv4:Y.Y.Y.Y:59017] local host [ipv4:X.X.X.X:445] [2019/12/11 17:12:55.461584, 4, pid=20939, effective(0, 0), real(0, 0)] ../lib/audit_logging/audit_logging.c:141(audit_log_json) JSON Authorization: {"timestamp": "2019-12-11T17:12:55.461491+0000", "type": "Authorization", "Authorization": {"version": {"major": 1, "minor": 1}, "localAddress": "ipv4:X.X.X.X:445", "remoteAddress": "ipv4:Y.Y.Y.Y:59017", "serviceDescription": "netlogon", "authType": "ncacn_np", "domain": "EXAMPLE", "account": "admin", "sid": "S-1-5-21-1234567-890123456-500", "sessionId": "c5a2386f-f2cc-4241-9a9e-d104cf5859d5", "logonServer": "SOME-DC", "transportProtection": "SMB", "accountFlags": "0x00000010"}} this means we are actually getting anonymous DCE/RPC access to netlogon on top of authenticated SMB connection. In such case we have exactly auth_type set to DCERPC_AUTH_TYPE_NONE and auth_level set to DCERPC_AUTH_LEVEL_NONE in the pipe->auth. Thus, returning an error. Update the code to follow the same security level check as in s4 variant of the call. Signed-off-by: Alexander Bokovoy Reviewed-by: Guenther Deschner Autobuild-User(master): Günther Deschner Autobuild-Date(master): Mon Jan 13 15:05:28 UTC 2020 on sn-devel-184 (cherry picked from commit c6d880a115095c336b8b74f45854a99abb1bbb87) --- source3/rpc_server/netlogon/srv_netlog_nt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index d799ba4feef..87613b99fde 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -2425,10 +2425,10 @@ WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p, { NTSTATUS status; struct lsa_ForestTrustInformation *info, **info_ptr; + enum security_user_level security_level; - if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE) - && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) { - p->fault_state = DCERPC_FAULT_ACCESS_DENIED; + security_level = security_session_user_level(p->session_info, NULL); + if (security_level < SECURITY_USER) { return WERR_ACCESS_DENIED; } -- 2.39.0 From e71fddb9ad5275a222d96bdcee06571a9a8c73c8 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 27 May 2020 16:50:45 +0200 Subject: [PATCH 002/142] Add a test to check dNSHostName with netbios aliases BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider --- selftest/knownfail.d/nb_alias_dnshostname | 2 ++ testprogs/blackbox/test_net_ads.sh | 14 ++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 selftest/knownfail.d/nb_alias_dnshostname diff --git a/selftest/knownfail.d/nb_alias_dnshostname b/selftest/knownfail.d/nb_alias_dnshostname new file mode 100644 index 00000000000..3c14e9931b9 --- /dev/null +++ b/selftest/knownfail.d/nb_alias_dnshostname @@ -0,0 +1,2 @@ +^samba4.blackbox.net_ads.nb_alias check dNSHostName +^samba4.blackbox.net_ads.nb_alias check main SPN diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index 95c0cf76f90..6073ea972f9 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -220,6 +220,20 @@ testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samac ##Goodbye... testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` +# netbios aliases tests +testit "join nb_alias" $VALGRIND $net_tool --option=netbiosaliases=nb_alias1,nb_alias2 ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` + +testit "testjoin nb_alias" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1` + +testit_grep "nb_alias check dNSHostName" $fqdn $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ dNSHostName || failed=`expr $failed + 1` +testit_grep "nb_alias check main SPN" ${uc_netbios}.${lc_realm} $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` + +testit_grep "nb_alias1 SPN" nb_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` +testit_grep "nb_alias2 SPN" nb_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` + +##Goodbye... +testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` + # # Test createcomputer option of 'net ads join' # -- 2.39.0 From e80e373485818eb7faebf5c9aae10d82fbc4e2e2 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 27 May 2020 15:52:46 +0200 Subject: [PATCH 003/142] Fix accidental overwrite of dnsHostName by the last netbios alias BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider --- selftest/knownfail.d/nb_alias_dnshostname | 2 -- source3/libnet/libnet_join.c | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 selftest/knownfail.d/nb_alias_dnshostname diff --git a/selftest/knownfail.d/nb_alias_dnshostname b/selftest/knownfail.d/nb_alias_dnshostname deleted file mode 100644 index 3c14e9931b9..00000000000 --- a/selftest/knownfail.d/nb_alias_dnshostname +++ /dev/null @@ -1,2 +0,0 @@ -^samba4.blackbox.net_ads.nb_alias check dNSHostName -^samba4.blackbox.net_ads.nb_alias check main SPN diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 9d4f656ffec..a31011b0ff8 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -507,6 +507,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, ADS_STATUS status; ADS_MODLIST mods; fstring my_fqdn; + fstring my_alias; const char **spn_array = NULL; size_t num_spns = 0; char *spn = NULL; @@ -587,11 +588,11 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, /* * Add HOST/netbiosname.domainname */ - fstr_sprintf(my_fqdn, "%s.%s", + fstr_sprintf(my_alias, "%s.%s", *netbios_aliases, lp_dnsdomain()); - spn = talloc_asprintf(frame, "HOST/%s", my_fqdn); + spn = talloc_asprintf(frame, "HOST/%s", my_alias); if (spn == NULL) { status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); goto done; -- 2.39.0 From 7ca5f9b2956ec41777837a7e14800a4345505ed6 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Thu, 24 Oct 2019 19:04:51 +0300 Subject: [PATCH 004/142] Refactor ads_keytab_add_entry() to make it iterable so we can more easily add msDS-AdditionalDnsHostName entries. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider --- source3/libads/kerberos_keytab.c | 197 +++++++++++++++++-------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c index 97d5535041c..0f450a09df5 100644 --- a/source3/libads/kerberos_keytab.c +++ b/source3/libads/kerberos_keytab.c @@ -228,18 +228,16 @@ out: return ok; } -/********************************************************************** - Adds a single service principal, i.e. 'host' to the system keytab -***********************************************************************/ - -int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) +static int add_kt_entry_etypes(krb5_context context, TALLOC_CTX *tmpctx, + ADS_STRUCT *ads, const char *salt_princ_s, + krb5_keytab keytab, krb5_kvno kvno, + const char *srvPrinc, const char *my_fqdn, + krb5_data *password, bool update_ads) { krb5_error_code ret = 0; - krb5_context context = NULL; - krb5_keytab keytab = NULL; - krb5_data password; - krb5_kvno kvno; - krb5_enctype enctypes[6] = { + char *princ_s = NULL; + char *short_princ_s = NULL; + krb5_enctype enctypes[6] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96 @@ -251,65 +249,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) ENCTYPE_ARCFOUR_HMAC, 0 }; - char *princ_s = NULL; - char *short_princ_s = NULL; - char *salt_princ_s = NULL; - char *password_s = NULL; - char *my_fqdn; - TALLOC_CTX *tmpctx = NULL; - int i; - - ret = smb_krb5_init_context_common(&context); - if (ret) { - DBG_ERR("kerberos init context failed (%s)\n", - error_message(ret)); - return -1; - } - - ret = ads_keytab_open(context, &keytab); - if (ret != 0) { - goto out; - } - - /* retrieve the password */ - if (!secrets_init()) { - DEBUG(1, (__location__ ": secrets_init failed\n")); - ret = -1; - goto out; - } - password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); - if (!password_s) { - DEBUG(1, (__location__ ": failed to fetch machine password\n")); - ret = -1; - goto out; - } - ZERO_STRUCT(password); - password.data = password_s; - password.length = strlen(password_s); - - /* we need the dNSHostName value here */ - tmpctx = talloc_init(__location__); - if (!tmpctx) { - DEBUG(0, (__location__ ": talloc_init() failed!\n")); - ret = -1; - goto out; - } - - my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name()); - if (!my_fqdn) { - DEBUG(0, (__location__ ": unable to determine machine " - "account's dns name in AD!\n")); - ret = -1; - goto out; - } - - /* make sure we have a single instance of a the computer account */ - if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) { - DEBUG(0, (__location__ ": unable to determine machine " - "account's short name in AD!\n")); - ret = -1; - goto out; - } + size_t i; /* Construct our principal */ if (strchr_m(srvPrinc, '@')) { @@ -358,22 +298,6 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) } } - kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name()); - if (kvno == -1) { - /* -1 indicates failure, everything else is OK */ - DEBUG(1, (__location__ ": ads_get_machine_kvno failed to " - "determine the system's kvno.\n")); - ret = -1; - goto out; - } - - salt_princ_s = kerberos_secrets_fetch_salt_princ(); - if (salt_princ_s == NULL) { - DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n"); - ret = -1; - goto out; - } - for (i = 0; enctypes[i]; i++) { /* add the fqdn principal to the keytab */ @@ -383,11 +307,11 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) princ_s, salt_princ_s, enctypes[i], - &password, + password, false, false); if (ret) { - DEBUG(1, (__location__ ": Failed to add entry to keytab\n")); + DBG_WARNING("Failed to add entry to keytab\n"); goto out; } @@ -399,16 +323,109 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) short_princ_s, salt_princ_s, enctypes[i], - &password, + password, false, false); if (ret) { - DEBUG(1, (__location__ - ": Failed to add short entry to keytab\n")); + DBG_WARNING("Failed to add short entry to keytab\n"); goto out; } } } +out: + return ret; +} + +/********************************************************************** + Adds a single service principal, i.e. 'host' to the system keytab +***********************************************************************/ + +int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) +{ + krb5_error_code ret = 0; + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_data password; + krb5_kvno kvno; + char *salt_princ_s = NULL; + char *password_s = NULL; + char *my_fqdn; + TALLOC_CTX *tmpctx = NULL; + + ret = smb_krb5_init_context_common(&context); + if (ret) { + DBG_ERR("kerberos init context failed (%s)\n", + error_message(ret)); + return -1; + } + + ret = ads_keytab_open(context, &keytab); + if (ret != 0) { + goto out; + } + + /* retrieve the password */ + if (!secrets_init()) { + DBG_WARNING("secrets_init failed\n"); + ret = -1; + goto out; + } + password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + if (!password_s) { + DBG_WARNING("failed to fetch machine password\n"); + ret = -1; + goto out; + } + ZERO_STRUCT(password); + password.data = password_s; + password.length = strlen(password_s); + + /* we need the dNSHostName value here */ + tmpctx = talloc_init(__location__); + if (!tmpctx) { + DBG_ERR("talloc_init() failed!\n"); + ret = -1; + goto out; + } + + my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name()); + if (!my_fqdn) { + DBG_ERR("unable to determine machine account's dns name in " + "AD!\n"); + ret = -1; + goto out; + } + + /* make sure we have a single instance of a the computer account */ + if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) { + DBG_ERR("unable to determine machine account's short name in " + "AD!\n"); + ret = -1; + goto out; + } + + kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name()); + if (kvno == -1) { + /* -1 indicates failure, everything else is OK */ + DBG_WARNING("ads_get_machine_kvno failed to determine the " + "system's kvno.\n"); + ret = -1; + goto out; + } + + salt_princ_s = kerberos_secrets_fetch_salt_princ(); + if (salt_princ_s == NULL) { + DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n"); + ret = -1; + goto out; + } + + ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab, + kvno, srvPrinc, my_fqdn, &password, + update_ads); + if (ret != 0) { + goto out; + } out: SAFE_FREE(salt_princ_s); -- 2.39.0 From 087d6dd4c4f25860643ab5920a1b2c0c70e5551b Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 27 May 2020 17:55:12 +0200 Subject: [PATCH 005/142] Add a test for msDS-AdditionalDnsHostName entries in keytab BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider --- selftest/knownfail.d/dns_alias_keytab | 2 ++ testprogs/blackbox/test_net_ads.sh | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 selftest/knownfail.d/dns_alias_keytab diff --git a/selftest/knownfail.d/dns_alias_keytab b/selftest/knownfail.d/dns_alias_keytab new file mode 100644 index 00000000000..216592e1210 --- /dev/null +++ b/selftest/knownfail.d/dns_alias_keytab @@ -0,0 +1,2 @@ +^samba4.blackbox.net_ads.dns alias1 check keytab +^samba4.blackbox.net_ads.dns alias2 check keytab diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index 6073ea972f9..a40b477a173 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -217,6 +217,15 @@ testit_grep "dns alias SPN" $dns_alias2 $VALGRIND $net_tool ads search -P samacc testit_grep "dns alias addl" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` +dedicated_keytab_file="$PREFIX_ABS/test_dns_aliases_dedicated_krb5.keytab" + +testit "dns alias create_keytab" $VALGRIND $net_tool ads keytab create --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` + +testit_grep "dns alias1 check keytab" "host/${dns_alias1}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` +testit_grep "dns alias2 check keytab" "host/${dns_alias2}@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` + +rm -f $dedicated_keytab_file + ##Goodbye... testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` -- 2.39.0 From 1ae32dddad89cdb75ae2c8fb3e7378ce6f5ad6af Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 27 May 2020 15:36:28 +0200 Subject: [PATCH 006/142] Add msDS-AdditionalDnsHostName entries to the keytab BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider --- selftest/knownfail.d/dns_alias_keytab | 2 -- source3/libads/ads_proto.h | 5 +++ source3/libads/kerberos_keytab.c | 21 +++++++++++++ source3/libads/ldap.c | 45 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/dns_alias_keytab diff --git a/selftest/knownfail.d/dns_alias_keytab b/selftest/knownfail.d/dns_alias_keytab deleted file mode 100644 index 216592e1210..00000000000 --- a/selftest/knownfail.d/dns_alias_keytab +++ /dev/null @@ -1,2 +0,0 @@ -^samba4.blackbox.net_ads.dns alias1 check keytab -^samba4.blackbox.net_ads.dns alias2 check keytab diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h index 495ef5d3325..cd9c1082681 100644 --- a/source3/libads/ads_proto.h +++ b/source3/libads/ads_proto.h @@ -137,6 +137,11 @@ ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx, enum ads_extended_dn_flags flags, struct dom_sid *sid); char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ); +ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx, + ADS_STRUCT *ads, + const char *machine_name, + char ***hostnames_array, + size_t *num_hostnames); char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ); bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ); ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name, diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c index 0f450a09df5..818ec884a03 100644 --- a/source3/libads/kerberos_keytab.c +++ b/source3/libads/kerberos_keytab.c @@ -351,6 +351,8 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) char *password_s = NULL; char *my_fqdn; TALLOC_CTX *tmpctx = NULL; + char **hostnames_array = NULL; + size_t num_hostnames = 0; ret = smb_krb5_init_context_common(&context); if (ret) { @@ -427,6 +429,25 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads) goto out; } + if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads, + lp_netbios_name(), + &hostnames_array, + &num_hostnames))) { + size_t i; + + for (i = 0; i < num_hostnames; i++) { + + ret = add_kt_entry_etypes(context, tmpctx, ads, + salt_princ_s, keytab, + kvno, srvPrinc, + hostnames_array[i], + &password, update_ads); + if (ret != 0) { + goto out; + } + } + } + out: SAFE_FREE(salt_princ_s); TALLOC_FREE(tmpctx); diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index db2b72ab1b5..02a628ee0e6 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1377,6 +1377,7 @@ char *ads_parent_dn(const char *dn) "unicodePwd", /* Additional attributes Samba checks */ + "msDS-AdditionalDnsHostName", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", @@ -3663,6 +3664,50 @@ out: /******************************************************************** ********************************************************************/ +ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx, + ADS_STRUCT *ads, + const char *machine_name, + char ***hostnames_array, + size_t *num_hostnames) +{ + ADS_STATUS status; + LDAPMessage *res = NULL; + int count; + + status = ads_find_machine_acct(ads, + &res, + machine_name); + if (!ADS_ERR_OK(status)) { + DEBUG(1,("Host Account for %s not found... skipping operation.\n", + machine_name)); + return status; + } + + count = ads_count_replies(ads, res); + if (count != 1) { + status = ADS_ERROR(LDAP_NO_SUCH_OBJECT); + goto done; + } + + *hostnames_array = ads_pull_strings(ads, mem_ctx, res, + "msDS-AdditionalDnsHostName", + num_hostnames); + if (*hostnames_array == NULL) { + DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n", + machine_name)); + status = ADS_ERROR(LDAP_NO_SUCH_OBJECT); + goto done; + } + +done: + ads_msgfree(ads, res); + + return status; +} + +/******************************************************************** +********************************************************************/ + char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name ) { LDAPMessage *res = NULL; -- 2.39.0 From 939b9265a533393189ef3c513e77b2cb009a51d5 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 27 May 2020 15:54:12 +0200 Subject: [PATCH 007/142] Add net-ads-join dnshostname=fqdn option BUG: https://bugzilla.samba.org/show_bug.cgi?id=14396 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Fri May 29 13:33:28 UTC 2020 on sn-devel-184 --- docs-xml/manpages/net.8.xml | 7 ++++++- source3/libnet/libnet_join.c | 7 ++++++- source3/librpc/idl/libnet_join.idl | 1 + source3/utils/net_ads.c | 9 ++++++++- testprogs/blackbox/test_net_ads.sh | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml index 37dfa2af694..69e18df8b6c 100644 --- a/docs-xml/manpages/net.8.xml +++ b/docs-xml/manpages/net.8.xml @@ -454,7 +454,7 @@ The remote server must be specified with the -S option. [RPC|ADS] JOIN [TYPE] [--no-dns-updates] [-U username[%password]] -[createupn=UPN] [createcomputer=OU] [machinepass=PASS] +[dnshostname=FQDN] [createupn=UPN] [createcomputer=OU] [machinepass=PASS] [osName=string osVer=string] [options] @@ -469,6 +469,11 @@ be created. joining the domain. + +[FQDN] (ADS only) set the dnsHosName attribute during the join. +The default format is netbiosname.dnsdomain. + + [UPN] (ADS only) set the principalname attribute during the join. The default format is host/netbiosname@REALM. diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index a31011b0ff8..de558be4f91 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -546,7 +546,12 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } - fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, lp_dnsdomain()); + if (r->in.dnshostname != NULL) { + fstr_sprintf(my_fqdn, "%s", r->in.dnshostname); + } else { + fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, + lp_dnsdomain()); + } if (!strlower_m(my_fqdn)) { status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl index e45034d40da..03d919863b5 100644 --- a/source3/librpc/idl/libnet_join.idl +++ b/source3/librpc/idl/libnet_join.idl @@ -37,6 +37,7 @@ interface libnetjoin [in] string os_servicepack, [in] boolean8 create_upn, [in] string upn, + [in] string dnshostname, [in] boolean8 modify_config, [in,unique] ads_struct *ads, [in] boolean8 debug, diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 07a22098fb1..3cf8fbbf7c8 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -1710,6 +1710,8 @@ static int net_ads_join_usage(struct net_context *c, int argc, const char **argv { d_printf(_("net ads join [--no-dns-updates] [options]\n" "Valid options:\n")); + d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n" + " The default is in the form netbiosname.dnsdomain\n")); d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n" " The default UPN is in the form host/netbiosname@REALM.\n")); d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n" @@ -1830,6 +1832,7 @@ int net_ads_join(struct net_context *c, int argc, const char **argv) const char *domain = lp_realm(); WERROR werr = WERR_NERR_SETUPNOTJOINED; bool createupn = false; + const char *dnshostname = NULL; const char *machineupn = NULL; const char *machine_password = NULL; const char *create_in_ou = NULL; @@ -1870,7 +1873,10 @@ int net_ads_join(struct net_context *c, int argc, const char **argv) /* process additional command line args */ for ( i=0; iin.domain_name_type = domain_name_type; r->in.create_upn = createupn; r->in.upn = machineupn; + r->in.dnshostname = dnshostname; r->in.account_ou = create_in_ou; r->in.os_name = os_name; r->in.os_version = os_version; diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index a40b477a173..85257f445d8 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -277,6 +277,21 @@ rm -f $dedicated_keytab_file testit "leave+createupn" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` +# +# Test dnshostname option of 'net ads join' +# +testit "join+dnshostname" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD dnshostname="alt.hostname.$HOSTNAME" || failed=`expr $failed + 1` + +testit_grep "check dnshostname opt" "dNSHostName: alt.hostname.$HOSTNAME" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "CN=$HOSTNAME,CN=Computers,$base_dn" || failed=`expr $failed + 1` + +testit "create_keytab+dnshostname" $VALGRIND $net_tool ads keytab create --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` + +testit_grep "check dnshostname+keytab" "host/alt.hostname.$HOSTNAME@$REALM" $net_tool ads keytab list --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` + +rm -f $dedicated_keytab_file + +testit "leave+dnshostname" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` + rm -rf $BASEDIR/$WORKDIR exit $failed -- 2.39.0 From 25a6679a5260dafde7a7d2aed9bfe43eaf083b1c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:04:57 +0200 Subject: [PATCH 008/142] CVE-2020-1472(ZeroLogon): libcli/auth: add netlogon_creds_random_challenge() It's good to have just a single isolated function that will generate random challenges, in future we can add some logic in order to avoid weak values, which are likely to be rejected by a server. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- libcli/auth/credentials.c | 8 ++++++++ libcli/auth/proto.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index b6c8ba281ba..dbbef9e7a3c 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -26,9 +26,17 @@ #include "libcli/auth/libcli_auth.h" #include "../libcli/security/dom_sid.h" + +void netlogon_creds_random_challenge(struct netr_Credential *challenge) +{ + ZERO_STRUCTP(challenge); + generate_random_buffer(challenge->data, sizeof(challenge->data)); +} + static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds, const struct netr_Credential *in, struct netr_Credential *out) + { if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { AES_KEY key; diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h index 82febe74440..82797d453ed 100644 --- a/libcli/auth/proto.h +++ b/libcli/auth/proto.h @@ -11,6 +11,8 @@ /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */ +void netlogon_creds_random_challenge(struct netr_Credential *challenge); + void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key); void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key); void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass); -- 2.39.0 From 1e8ad7efe35d8b79fef387ff709d6a499565c39a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:07:30 +0200 Subject: [PATCH 009/142] CVE-2020-1472(ZeroLogon): s4:torture/rpc: make use of netlogon_creds_random_challenge() This will avoid getting flakey tests once our server starts to reject weak challenges. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source4/torture/rpc/lsa.c | 2 +- source4/torture/rpc/netlogon.c | 34 ++++++++++++---------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index 21cc16afbaf..7bdc0cf679a 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -2847,7 +2847,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge failed"); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 026d86d50e4..e11014922f8 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -160,7 +160,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge failed"); @@ -229,7 +229,7 @@ bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tct r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge failed"); @@ -318,7 +318,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge failed"); @@ -390,7 +390,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge failed"); @@ -1278,7 +1278,7 @@ static bool test_ServerReqChallengeGlobal(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1367,7 +1367,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1456,7 +1456,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1546,7 +1546,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1638,8 +1638,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, r.in.credentials = &credentials1_random; r.out.return_credentials = &credentials_discard; - generate_random_buffer(credentials1_random.data, - sizeof(credentials1_random.data)); + netlogon_creds_random_challenge(&credentials1_random); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1651,7 +1650,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1662,16 +1661,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, r.in.credentials = &credentials1_random; r.out.return_credentials = &credentials_discard; - generate_random_buffer(credentials1_random.data, - sizeof(credentials1_random.data)); - - r.in.server_name = NULL; - r.in.computer_name = "CHALTEST3"; - r.in.credentials = &credentials1_random; - r.out.return_credentials = &credentials_discard; - - generate_random_buffer(credentials1_random.data, - sizeof(credentials1_random.data)); + netlogon_creds_random_challenge(&credentials1_random); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), "ServerReqChallenge failed on b1"); @@ -1747,7 +1737,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx, r.in.credentials = &credentials1; r.out.return_credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + netlogon_creds_random_challenge(&credentials1); torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), "ServerReqChallenge"); -- 2.39.0 From 74ee204ad4647d0d7a2097124652cbcd43406c7d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:08:38 +0200 Subject: [PATCH 010/142] CVE-2020-1472(ZeroLogon): libcli/auth: make use of netlogon_creds_random_challenge() in netlogon_creds_cli.c This will avoid getting rejected by the server if we generate a weak challenge. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- libcli/auth/netlogon_creds_cli.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 817d2cd041a..0f6ca11ff96 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -1177,8 +1177,7 @@ static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req) TALLOC_FREE(state->creds); - generate_random_buffer(state->client_challenge.data, - sizeof(state->client_challenge.data)); + netlogon_creds_random_challenge(&state->client_challenge); subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev, state->binding_handle, -- 2.39.0 From 10196846d019d0e2ccef51f32ddd39fc17ca60aa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:10:53 +0200 Subject: [PATCH 011/142] CVE-2020-1472(ZeroLogon): s3:rpc_server:netlogon: make use of netlogon_creds_random_challenge() This is not strictly needed, but makes things more clear. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 87613b99fde..86b2f343e82 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -840,8 +840,7 @@ NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p, pipe_state->client_challenge = *r->in.credentials; - generate_random_buffer(pipe_state->server_challenge.data, - sizeof(pipe_state->server_challenge.data)); + netlogon_creds_random_challenge(&pipe_state->server_challenge); *r->out.return_credentials = pipe_state->server_challenge; -- 2.39.0 From 215aca6d11b900ee3cf11568d27bce77e0567653 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:10:53 +0200 Subject: [PATCH 012/142] CVE-2020-1472(ZeroLogon): s4:rpc_server:netlogon: make use of netlogon_creds_random_challenge() This is not strictly needed, but makes things more clear. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 023adfd99e9..de260d8051d 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -90,8 +90,7 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal pipe_state->client_challenge = *r->in.credentials; - generate_random_buffer(pipe_state->server_challenge.data, - sizeof(pipe_state->server_challenge.data)); + netlogon_creds_random_challenge(&pipe_state->server_challenge); *r->out.return_credentials = pipe_state->server_challenge; -- 2.39.0 From 4551bf623426e8c543b287807d447feb69bb0f09 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:15:26 +0200 Subject: [PATCH 013/142] CVE-2020-1472(ZeroLogon): libcli/auth: add netlogon_creds_is_random_challenge() to avoid weak values This is the check Windows is using, so we won't generate challenges, which are rejected by Windows DCs (and future Samba DCs). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- libcli/auth/credentials.c | 23 ++++++++++++++++++++++- libcli/auth/proto.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index dbbef9e7a3c..64b424c099f 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -27,10 +27,31 @@ #include "../libcli/security/dom_sid.h" +bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge) +{ + /* + * If none of the first 5 bytes of the client challenge is unique, the + * server MUST fail session-key negotiation without further processing + * of the following steps. + */ + + if (challenge->data[1] == challenge->data[0] && + challenge->data[2] == challenge->data[0] && + challenge->data[3] == challenge->data[0] && + challenge->data[4] == challenge->data[0]) + { + return false; + } + + return true; +} + void netlogon_creds_random_challenge(struct netr_Credential *challenge) { ZERO_STRUCTP(challenge); - generate_random_buffer(challenge->data, sizeof(challenge->data)); + while (!netlogon_creds_is_random_challenge(challenge)) { + generate_random_buffer(challenge->data, sizeof(challenge->data)); + } } static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds, diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h index 82797d453ed..ad768682b9f 100644 --- a/libcli/auth/proto.h +++ b/libcli/auth/proto.h @@ -11,6 +11,7 @@ /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */ +bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge); void netlogon_creds_random_challenge(struct netr_Credential *challenge); void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key); -- 2.39.0 From f7e09421ace8fe60c0110770d909800d21ae6c8e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 16:17:29 +0200 Subject: [PATCH 014/142] CVE-2020-1472(ZeroLogon): libcli/auth: reject weak client challenges in netlogon_creds_server_init() This implements the note from MS-NRPC 3.1.4.1 Session-Key Negotiation: 7. If none of the first 5 bytes of the client challenge is unique, the server MUST fail session-key negotiation without further processing of the following steps. It lets ./zerologon_tester.py from https://github.com/SecuraBV/CVE-2020-1472.git report: "Attack failed. Target is probably patched." BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher [dbagnall@samba.org, abartlet@samba.org: wscript_build backport differs because 4.10 has no gnutls dependency] --- libcli/auth/credentials.c | 16 ++++++++++++++++ libcli/auth/wscript_build | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c index 64b424c099f..e2bc82809b7 100644 --- a/libcli/auth/credentials.c +++ b/libcli/auth/credentials.c @@ -25,6 +25,7 @@ #include "../lib/crypto/crypto.h" #include "libcli/auth/libcli_auth.h" #include "../libcli/security/dom_sid.h" +#include "lib/util/util_str_escape.h" bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge) @@ -451,6 +452,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me { struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState); + bool ok; if (!creds) { return NULL; @@ -463,6 +465,20 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data)); dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash)); + ok = netlogon_creds_is_random_challenge(client_challenge); + if (!ok) { + DBG_WARNING("CVE-2020-1472(ZeroLogon): " + "non-random client challenge rejected for " + "client_account[%s] client_computer_name[%s]\n", + log_escape(mem_ctx, client_account), + log_escape(mem_ctx, client_computer_name)); + dump_data(DBGLVL_WARNING, + client_challenge->data, + sizeof(client_challenge->data)); + talloc_free(creds); + return NULL; + } + creds->computer_name = talloc_strdup(creds, client_computer_name); if (!creds->computer_name) { talloc_free(creds); diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build index d319d9b879e..394505d166d 100644 --- a/libcli/auth/wscript_build +++ b/libcli/auth/wscript_build @@ -18,7 +18,7 @@ bld.SAMBA_SUBSYSTEM('NTLM_CHECK', bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH', source='credentials.c session.c smbencrypt.c smbdes.c', - public_deps='MSRPC_PARSE', + public_deps='MSRPC_PARSE util_str_escape', public_headers='credentials.h:domain_credentials.h' ) -- 2.39.0 From 6bc86fb69bf50c89a334fd2dcbce6999a2360fb7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 19:20:25 +0200 Subject: [PATCH 015/142] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: protect netr_ServerPasswordSet2 against unencrypted passwords BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index de260d8051d..acbf077c6c7 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -722,7 +722,10 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal struct NL_PASSWORD_VERSION version = {}; const uint32_t *new_version = NULL; NTSTATUS nt_status; - DATA_BLOB new_password; + DATA_BLOB new_password = data_blob_null; + size_t confounder_len; + DATA_BLOB dec_blob = data_blob_null; + DATA_BLOB enc_blob = data_blob_null; int ret; struct samr_CryptPassword password_buf; @@ -780,6 +783,61 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal return NT_STATUS_WRONG_PASSWORD; } + /* + * Make sure the length field was encrypted, + * otherwise we are under attack. + */ + if (new_password.length == r->in.new_password->length) { + DBG_WARNING("Length[%zu] field not encrypted\n", + new_password.length); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * We don't allow empty passwords for machine accounts. + */ + if (new_password.length < 2) { + DBG_WARNING("Empty password Length[%zu]\n", + new_password.length); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * Make sure the confounder part of CryptPassword + * buffer was encrypted, otherwise we are under attack. + */ + confounder_len = 512 - new_password.length; + enc_blob = data_blob_const(r->in.new_password->data, confounder_len); + dec_blob = data_blob_const(password_buf.data, confounder_len); + if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", + confounder_len); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * Check that the password part was actually encrypted, + * otherwise we are under attack. + */ + enc_blob = data_blob_const(r->in.new_password->data + confounder_len, + new_password.length); + dec_blob = data_blob_const(password_buf.data + confounder_len, + new_password.length); + if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + DBG_WARNING("Password buffer not encrypted Length[%zu]\n", + new_password.length); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * don't allow zero buffers + */ + if (all_zero(new_password.data, new_password.length)) { + DBG_WARNING("Password zero buffer Length[%zu]\n", + new_password.length); + return NT_STATUS_WRONG_PASSWORD; + } + /* fetch the old password hashes (at least one of both has to exist) */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, -- 2.39.0 From 1f8dec1cbb37f3406d999425590f8a923586ccac Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 16 Sep 2020 12:53:50 -0700 Subject: [PATCH 016/142] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: protect netr_ServerPasswordSet2 against unencrypted passwords BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 98 +++++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 86b2f343e82..fd9127b386f 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1326,9 +1326,14 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, { NTSTATUS status; struct netlogon_creds_CredentialState *creds = NULL; - DATA_BLOB plaintext; + DATA_BLOB plaintext = data_blob_null; + DATA_BLOB new_password = data_blob_null; + size_t confounder_len; + DATA_BLOB dec_blob = data_blob_null; + DATA_BLOB enc_blob = data_blob_null; struct samr_CryptPassword password_buf; struct _samr_Credentials_t cr = { CRED_TYPE_PLAIN_TEXT, {0}}; + bool ok; become_root(); status = netr_creds_server_step_check(p, p->mem_ctx, @@ -1364,18 +1369,99 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); } - if (!decode_pw_buffer(p->mem_ctx, - password_buf.data, - (char**) &plaintext.data, - &plaintext.length, - CH_UTF16)) { + if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &new_password)) { DEBUG(2,("_netr_ServerPasswordSet2: unable to extract password " "from a buffer. Rejecting auth request as a wrong password\n")); TALLOC_FREE(creds); return NT_STATUS_WRONG_PASSWORD; } + /* + * Make sure the length field was encrypted, + * otherwise we are under attack. + */ + if (new_password.length == r->in.new_password->length) { + DBG_WARNING("Length[%zu] field not encrypted\n", + new_password.length); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * We don't allow empty passwords for machine accounts. + */ + if (new_password.length < 2) { + DBG_WARNING("Empty password Length[%zu]\n", + new_password.length); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * Make sure the confounder part of CryptPassword + * buffer was encrypted, otherwise we are under attack. + */ + confounder_len = 512 - new_password.length; + enc_blob = data_blob_const(r->in.new_password->data, confounder_len); + dec_blob = data_blob_const(password_buf.data, confounder_len); + if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", + confounder_len); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * Check that the password part was actually encrypted, + * otherwise we are under attack. + */ + enc_blob = data_blob_const(r->in.new_password->data + confounder_len, + new_password.length); + dec_blob = data_blob_const(password_buf.data + confounder_len, + new_password.length); + if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { + DBG_WARNING("Password buffer not encrypted Length[%zu]\n", + new_password.length); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * don't allow zero buffers + */ + if (all_zero(new_password.data, new_password.length)) { + DBG_WARNING("Password zero buffer Length[%zu]\n", + new_password.length); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* Convert from UTF16 -> plaintext. */ + ok = convert_string_talloc(p->mem_ctx, + CH_UTF16, + CH_UNIX, + new_password.data, + new_password.length, + (void *)&plaintext.data, + &plaintext.length); + if (!ok) { + DBG_WARNING("unable to extract password from a buffer. " + "Rejecting auth request as a wrong password\n"); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * We don't allow empty passwords for machine accounts. + */ + cr.creds.password = (const char*) plaintext.data; + if (strlen(cr.creds.password) == 0) { + DBG_WARNING("Empty plaintext password\n"); + TALLOC_FREE(creds); + return NT_STATUS_WRONG_PASSWORD; + } + status = netr_set_machine_account_password(p->mem_ctx, p->session_info, p->msg_ctx, -- 2.39.0 From 2ad269be74481789ded62a3dcb538709c6d6e291 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 10:18:45 +0200 Subject: [PATCH 017/142] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: refactor dcesrv_netr_creds_server_step_check() We should debug more details about the failing request. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index acbf077c6c7..b4326a4ecaa 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -623,26 +623,47 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc NTSTATUS nt_status; int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); bool schannel_global_required = (schannel == true); + struct netlogon_creds_CredentialState *creds = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + uint16_t opnum = dce_call->pkt.u.request.opnum; + const char *opname = ""; - if (schannel_global_required) { - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - - dcesrv_call_auth_info(dce_call, &auth_type, NULL); - - if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DBG_ERR("[%s] is not using schannel\n", - computer_name); - return NT_STATUS_ACCESS_DENIED; - } + if (opnum < ndr_table_netlogon.num_calls) { + opname = ndr_table_netlogon.calls[opnum].name; } + dcesrv_call_auth_info(dce_call, &auth_type, NULL); + nt_status = schannel_check_creds_state(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, computer_name, received_authenticator, return_authenticator, - creds_out); - return nt_status; + &creds); + if (!NT_STATUS_IS_OK(nt_status)) { + ZERO_STRUCTP(return_authenticator); + return nt_status; + } + + if (schannel_global_required) { + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + *creds_out = creds; + return NT_STATUS_OK; + } + + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return NT_STATUS_ACCESS_DENIED; + } + + *creds_out = creds; + return NT_STATUS_OK; } /* -- 2.39.0 From 57941290adb9a2fd4be9aa4a70f879a684b38dfd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Sep 2020 10:56:53 +0200 Subject: [PATCH 018/142] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: support "server require schannel:WORKSTATION$ = no" This allows to add expections for individual workstations, when using "server schannel = yes". "server schannel = auto" is very insecure and will be removed soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b4326a4ecaa..e7bafb31e83 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -623,6 +623,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc NTSTATUS nt_status; int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); bool schannel_global_required = (schannel == true); + bool schannel_required = schannel_global_required; struct netlogon_creds_CredentialState *creds = NULL; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; @@ -645,7 +646,13 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc return nt_status; } - if (schannel_global_required) { + schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, + NULL, + "server require schannel", + creds->account_name, + schannel_global_required); + + if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; return NT_STATUS_OK; -- 2.39.0 From 779b37e825fe406892ff77be18c098d314cd387d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Sep 2020 13:37:26 +0200 Subject: [PATCH 019/142] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: log warnings about unsecure configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should give admins wawrnings until they have a secure configuration. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme Reviewed-by: Günther Deschner --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index e7bafb31e83..7668a9eb923 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -624,10 +624,12 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; + const char *explicit_opt = NULL; struct netlogon_creds_CredentialState *creds = NULL; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; + static bool warned_global_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -646,11 +648,18 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc return nt_status; } - schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx, NULL, "server require schannel", - creds->account_name, - schannel_global_required); + creds->account_name); + if (explicit_opt != NULL) { + schannel_required = lp_bool(explicit_opt); + } if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { @@ -664,11 +673,62 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc opname, opnum, log_escape(mem_ctx, creds->account_name), log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' is needed! \n", + log_escape(mem_ctx, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); return NT_STATUS_ACCESS_DENIED; } + if (!schannel_global_required && !warned_global_once) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Please configure 'server schannel = yes', " + "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); + warned_global_once = true; + } + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) WITH schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(mem_ctx, creds->account_name)); + + *creds_out = creds; + return NT_STATUS_OK; + } + + + if (explicit_opt != NULL) { + DBG_INFO("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_INFO("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' still needed!\n", + log_escape(mem_ctx, creds->account_name)); + } else { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' might be needed!\n", + log_escape(mem_ctx, creds->account_name)); + } + *creds_out = creds; return NT_STATUS_OK; } -- 2.39.0 From 60b83fbda31c53c592a02f0ed43356a912021021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 17 Sep 2020 14:57:22 +0200 Subject: [PATCH 020/142] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: refactor dcesrv_netr_creds_server_step_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should debug more details about the failing request. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Günther Deschner Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 43 +++++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index fd9127b386f..8541571b459 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -48,6 +48,7 @@ #include "../lib/tsocket/tsocket.h" #include "lib/param/param.h" #include "libsmb/dsgetdcname.h" +#include "lib/util/util_str_escape.h" extern userdom_struct current_user_info; @@ -1073,19 +1074,21 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; struct loadparm_context *lp_ctx; + struct netlogon_creds_CredentialState *creds = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + uint16_t opnum = p->opnum; + const char *opname = ""; if (creds_out != NULL) { *creds_out = NULL; } - if (schannel_global_required) { - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DBG_ERR("[%s] is not using schannel\n", - computer_name); - return NT_STATUS_ACCESS_DENIED; - } + if (opnum < ndr_table_netlogon.num_calls) { + opname = ndr_table_netlogon.calls[opnum].name; } + auth_type = p->auth.auth_type; + lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); @@ -1094,9 +1097,33 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, status = schannel_check_creds_state(mem_ctx, lp_ctx, computer_name, received_authenticator, - return_authenticator, creds_out); + return_authenticator, &creds); talloc_unlink(mem_ctx, lp_ctx); - return status; + + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCTP(return_authenticator); + return status; + } + + if (schannel_global_required) { + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + *creds_out = creds; + return NT_STATUS_OK; + } + + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return NT_STATUS_ACCESS_DENIED; + } + + *creds_out = creds; + return NT_STATUS_OK; } -- 2.39.0 From c0a188b2696edb8f3ae9f7f56a820b11358bad98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 17 Sep 2020 14:23:16 +0200 Subject: [PATCH 021/142] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: support "server require schannel:WORKSTATION$ = no" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to add expections for individual workstations, when using "server schannel = yes". "server schannel = auto" is very insecure and will be removed soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Günther Deschner Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 8541571b459..f9b10103bd5 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1073,6 +1073,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, { NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; + bool schannel_required = schannel_global_required; struct loadparm_context *lp_ctx; struct netlogon_creds_CredentialState *creds = NULL; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; @@ -1105,7 +1106,11 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, return status; } - if (schannel_global_required) { + schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM, + "server require schannel", + creds->account_name, + schannel_global_required); + if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; return NT_STATUS_OK; -- 2.39.0 From c9550b81b55316cf5d667502885fc248a5999fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 17 Sep 2020 14:42:52 +0200 Subject: [PATCH 022/142] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: log warnings about unsecure configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Günther Deschner Signed-off-by: Stefan Metzmacher --- source3/rpc_server/netlogon/srv_netlog_nt.c | 70 +++++++++++++++++++-- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index f9b10103bd5..7f6704adbda 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1074,11 +1074,13 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; + const char *explicit_opt = NULL; struct loadparm_context *lp_ctx; struct netlogon_creds_CredentialState *creds = NULL; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = p->opnum; const char *opname = ""; + static bool warned_global_once = false; if (creds_out != NULL) { *creds_out = NULL; @@ -1106,10 +1108,20 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, return status; } - schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM, - "server require schannel", - creds->account_name, - schannel_global_required); + /* + * We don't use lp_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + + explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM, + "server require schannel", + creds->account_name, + NULL); + if (explicit_opt != NULL) { + schannel_required = lp_bool(explicit_opt); + } + if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; @@ -1122,11 +1134,61 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, opname, opnum, log_escape(mem_ctx, creds->account_name), log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' is needed! \n", + log_escape(mem_ctx, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); return NT_STATUS_ACCESS_DENIED; } + if (!schannel_global_required && !warned_global_once) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Please configure 'server schannel = yes', " + "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); + warned_global_once = true; + } + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) WITH schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(mem_ctx, creds->account_name)); + + *creds_out = creds; + return NT_STATUS_OK; + } + + if (explicit_opt != NULL) { + DBG_INFO("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_INFO("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' still needed!\n", + log_escape(mem_ctx, creds->account_name)); + } else { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) without schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(mem_ctx, creds->account_name), + log_escape(mem_ctx, creds->computer_name)); + DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' might be needed!\n", + log_escape(mem_ctx, creds->account_name)); + } + *creds_out = creds; return NT_STATUS_OK; } -- 2.39.0 From 63f03e2e29e81f890a5d88c726cced6d3e7bbf5d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Sep 2020 17:27:54 +0200 Subject: [PATCH 023/142] CVE-2020-1472(ZeroLogon): docs-xml: document 'server require schannel:COMPUTERACCOUNT' BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher --- .../smbdotconf/security/serverschannel.xml | 69 +++++++++++++++---- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index 489492d79b1..b682d086f76 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -7,26 +7,65 @@ - This option is deprecated with Samba 4.8 and will be removed in future. - At the same time the default changed to yes, which will be the - hardcoded behavior in future. If you have the need for the behavior of "auto" - to be kept, please file a bug at https://bugzilla.samba.org. + This option is deprecated and will be removed in future, + as it is a security problem if not set to "yes" (which will be + the hardcoded behavior in future). - This controls whether the server offers or even demands the use of the netlogon schannel. - no does not offer the schannel, auto offers the schannel but does not enforce it, and yes denies access if the client is not able to speak netlogon schannel. - This is only the case for Windows NT4 before SP4. - - + Samba will complain in the log files at log level 0, + about the security problem if the option is not set to "yes". + - Please note that with this set to no, you will have to apply the WindowsXP - WinXP_SignOrSeal.reg registry patch found in the docs/registry subdirectory of the Samba distribution tarball. - + See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + + + If you still have legacy domain members use the option. + + + This option yields precedence to the option. + yes -auto + + + + + + If you still have legacy domain members, which required "server schannel = auto" before, + it is possible to specify explicit expection per computer account + by using 'server require schannel:COMPUTERACCOUNT = no' as option. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will complain in the log files at log level 0, + about the security problem if the option is not set to "no", + but the related computer is actually using the netlogon + secure channel (schannel) feature. + + + + Samba will warn in the log files at log level 5, + if a setting is still needed for the specified computer account. + + + + See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + + + This option takes precedence to the option. + + + server require schannel:LEGACYCOMPUTER1$ = no + server require schannel:NASBOX$ = no + server require schannel:LEGACYCOMPUTER2$ = no + + + -- 2.39.0 From 8a40da45b7f4e7a9110daf010383c4fce30bd9b6 Mon Sep 17 00:00:00 2001 From: Gary Lockyer Date: Fri, 18 Sep 2020 12:39:54 +1200 Subject: [PATCH 024/142] CVE-2020-1472(ZeroLogon): s4 torture rpc: Test empty machine acct pwd Ensure that an empty machine account password can't be set by netr_ServerPasswordSet2 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Gary Lockyer --- source4/torture/rpc/netlogon.c | 64 +++++++++++++++------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index e11014922f8..0ba45f0c1da 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -719,45 +719,39 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx, cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED); - if (!torture_setting_bool(tctx, "dangerous", false)) { - torture_comment(tctx, - "Not testing ability to set password to '', enable dangerous tests to perform this test\n"); + /* + * As a consequence of CVE-2020-1472(ZeroLogon) + * Samba explicitly disallows the setting of an empty machine account + * password. + * + * Note that this may fail against Windows, and leave a machine account + * with an empty password. + */ + password = ""; + encode_pw_buffer(password_buf.data, password, STR_UNICODE); + if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + netlogon_creds_aes_encrypt(creds, password_buf.data, 516); } else { - /* by changing the machine password to "" - * we check if the server uses password restrictions - * for ServerPasswordSet2 - * (win2k3 accepts "") - */ - password = ""; - encode_pw_buffer(password_buf.data, password, STR_UNICODE); - if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - netlogon_creds_aes_encrypt(creds, password_buf.data, 516); - } else { - netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); - } - memcpy(new_password.data, password_buf.data, 512); - new_password.length = IVAL(password_buf.data, 512); - - torture_comment(tctx, - "Testing ServerPasswordSet2 on machine account\n"); - torture_comment(tctx, - "Changing machine account password to '%s'\n", password); - - netlogon_creds_client_authenticator(creds, &credential); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r), - "ServerPasswordSet2 failed"); - torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 failed"); + netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); + } + memcpy(new_password.data, password_buf.data, 512); + new_password.length = IVAL(password_buf.data, 512); - if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) { - torture_comment(tctx, "Credential chaining failed\n"); - } + torture_comment(tctx, + "Testing ServerPasswordSet2 on machine account\n"); + torture_comment(tctx, + "Changing machine account password to '%s'\n", password); - cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED); - } + netlogon_creds_client_authenticator(creds, &credential); - torture_assert(tctx, test_SetupCredentials(p, tctx, machine_credentials, &creds), - "ServerPasswordSet failed to actually change the password"); + torture_assert_ntstatus_ok( + tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r), + "ServerPasswordSet2 failed"); + torture_assert_ntstatus_equal( + tctx, + r.out.result, + NT_STATUS_WRONG_PASSWORD, + "ServerPasswordSet2 did not return NT_STATUS_WRONG_PASSWORD"); /* now try a random password */ password = generate_random_password(tctx, 8, 255); -- 2.39.0 From 341a448cb69557410fa79dbb8a3d4adbab79d5b6 Mon Sep 17 00:00:00 2001 From: Gary Lockyer Date: Fri, 18 Sep 2020 15:57:34 +1200 Subject: [PATCH 025/142] CVE-2020-1472(ZeroLogon): s4 torture rpc: repeated bytes in client challenge Ensure that client challenges with the first 5 bytes identical are rejected. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Gary Lockyer [abartlet@samba.org: backported from master as test order was flipped] --- source4/torture/rpc/netlogon.c | 335 +++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 0ba45f0c1da..97c16688bc9 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -480,6 +480,325 @@ bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1, return true; } +static bool test_ServerReqChallenge( + struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct netr_ServerReqChallenge r; + struct netr_Credential credentials1, credentials2, credentials3; + const char *machine_name; + struct dcerpc_binding_handle *b = p->binding_handle; + struct netr_ServerAuthenticate2 a; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t out_negotiate_flags = 0; + const struct samr_Password *mach_password = NULL; + enum netr_SchannelType sec_chan_type = 0; + struct netlogon_creds_CredentialState *creds = NULL; + const char *account_name = NULL; + + machine_name = cli_credentials_get_workstation(credentials); + mach_password = cli_credentials_get_nt_hash(credentials, tctx); + account_name = cli_credentials_get_username(credentials); + sec_chan_type = cli_credentials_get_secure_channel_type(credentials); + + torture_comment(tctx, "Testing ServerReqChallenge\n"); + + r.in.server_name = NULL; + r.in.computer_name = machine_name; + r.in.credentials = &credentials1; + r.out.return_credentials = &credentials2; + + netlogon_creds_random_challenge(&credentials1); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), + "ServerReqChallenge failed"); + torture_assert_ntstatus_ok( + tctx, + r.out.result, + "ServerReqChallenge failed"); + a.in.server_name = NULL; + a.in.account_name = account_name; + a.in.secure_channel_type = sec_chan_type; + a.in.computer_name = machine_name; + a.in.negotiate_flags = &in_negotiate_flags; + a.out.negotiate_flags = &out_negotiate_flags; + a.in.credentials = &credentials3; + a.out.return_credentials = &credentials3; + + creds = netlogon_creds_client_init(tctx, a.in.account_name, + a.in.computer_name, + a.in.secure_channel_type, + &credentials1, &credentials2, + mach_password, &credentials3, + in_negotiate_flags); + + torture_assert(tctx, creds != NULL, "memory allocation"); + + torture_comment(tctx, "Testing ServerAuthenticate2\n"); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), + "ServerAuthenticate2 failed"); + torture_assert_ntstatus_equal( + tctx, + a.out.result, + NT_STATUS_OK, + "ServerAuthenticate2 unexpected"); + + return true; +} + +static bool test_ServerReqChallenge_zero_challenge( + struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct netr_ServerReqChallenge r; + struct netr_Credential credentials1, credentials2, credentials3; + const char *machine_name; + struct dcerpc_binding_handle *b = p->binding_handle; + struct netr_ServerAuthenticate2 a; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t out_negotiate_flags = 0; + const struct samr_Password *mach_password = NULL; + enum netr_SchannelType sec_chan_type = 0; + struct netlogon_creds_CredentialState *creds = NULL; + const char *account_name = NULL; + + machine_name = cli_credentials_get_workstation(credentials); + mach_password = cli_credentials_get_nt_hash(credentials, tctx); + account_name = cli_credentials_get_username(credentials); + sec_chan_type = cli_credentials_get_secure_channel_type(credentials); + + torture_comment(tctx, "Testing ServerReqChallenge\n"); + + r.in.server_name = NULL; + r.in.computer_name = machine_name; + r.in.credentials = &credentials1; + r.out.return_credentials = &credentials2; + + /* + * Set the client challenge to zero, this should fail + * CVE-2020-1472(ZeroLogon) + * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 + */ + ZERO_STRUCT(credentials1); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), + "ServerReqChallenge failed"); + torture_assert_ntstatus_ok( + tctx, + r.out.result, + "ServerReqChallenge failed"); + a.in.server_name = NULL; + a.in.account_name = account_name; + a.in.secure_channel_type = sec_chan_type; + a.in.computer_name = machine_name; + a.in.negotiate_flags = &in_negotiate_flags; + a.out.negotiate_flags = &out_negotiate_flags; + a.in.credentials = &credentials3; + a.out.return_credentials = &credentials3; + + creds = netlogon_creds_client_init(tctx, a.in.account_name, + a.in.computer_name, + a.in.secure_channel_type, + &credentials1, &credentials2, + mach_password, &credentials3, + in_negotiate_flags); + + torture_assert(tctx, creds != NULL, "memory allocation"); + + torture_comment(tctx, "Testing ServerAuthenticate2\n"); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), + "ServerAuthenticate2 failed"); + torture_assert_ntstatus_equal( + tctx, + a.out.result, + NT_STATUS_ACCESS_DENIED, + "ServerAuthenticate2 unexpected"); + + return true; +} + +static bool test_ServerReqChallenge_5_repeats( + struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct netr_ServerReqChallenge r; + struct netr_Credential credentials1, credentials2, credentials3; + const char *machine_name; + struct dcerpc_binding_handle *b = p->binding_handle; + struct netr_ServerAuthenticate2 a; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t out_negotiate_flags = 0; + const struct samr_Password *mach_password = NULL; + enum netr_SchannelType sec_chan_type = 0; + struct netlogon_creds_CredentialState *creds = NULL; + const char *account_name = NULL; + + machine_name = cli_credentials_get_workstation(credentials); + mach_password = cli_credentials_get_nt_hash(credentials, tctx); + account_name = cli_credentials_get_username(credentials); + sec_chan_type = cli_credentials_get_secure_channel_type(credentials); + + torture_comment(tctx, "Testing ServerReqChallenge\n"); + + r.in.server_name = NULL; + r.in.computer_name = machine_name; + r.in.credentials = &credentials1; + r.out.return_credentials = &credentials2; + + /* + * Set the first 5 bytes of the client challenge to the same value, + * this should fail CVE-2020-1472(ZeroLogon) + * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 + */ + credentials1.data[0] = 'A'; + credentials1.data[1] = 'A'; + credentials1.data[2] = 'A'; + credentials1.data[3] = 'A'; + credentials1.data[4] = 'A'; + credentials1.data[5] = 'B'; + credentials1.data[6] = 'C'; + credentials1.data[7] = 'D'; + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), + "ServerReqChallenge failed"); + torture_assert_ntstatus_ok( + tctx, + r.out.result, + "ServerReqChallenge failed"); + a.in.server_name = NULL; + a.in.account_name = account_name; + a.in.secure_channel_type = sec_chan_type; + a.in.computer_name = machine_name; + a.in.negotiate_flags = &in_negotiate_flags; + a.out.negotiate_flags = &out_negotiate_flags; + a.in.credentials = &credentials3; + a.out.return_credentials = &credentials3; + + creds = netlogon_creds_client_init(tctx, a.in.account_name, + a.in.computer_name, + a.in.secure_channel_type, + &credentials1, &credentials2, + mach_password, &credentials3, + in_negotiate_flags); + + torture_assert(tctx, creds != NULL, "memory allocation"); + + torture_comment(tctx, "Testing ServerAuthenticate2\n"); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), + "ServerAuthenticate2 failed"); + torture_assert_ntstatus_equal( + tctx, + a.out.result, + NT_STATUS_ACCESS_DENIED, + "ServerAuthenticate2 unexpected"); + + return true; +} + +static bool test_ServerReqChallenge_4_repeats( + struct torture_context *tctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct netr_ServerReqChallenge r; + struct netr_Credential credentials1, credentials2, credentials3; + const char *machine_name; + struct dcerpc_binding_handle *b = p->binding_handle; + struct netr_ServerAuthenticate2 a; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t out_negotiate_flags = 0; + const struct samr_Password *mach_password = NULL; + enum netr_SchannelType sec_chan_type = 0; + struct netlogon_creds_CredentialState *creds = NULL; + const char *account_name = NULL; + + machine_name = cli_credentials_get_workstation(credentials); + mach_password = cli_credentials_get_nt_hash(credentials, tctx); + account_name = cli_credentials_get_username(credentials); + sec_chan_type = cli_credentials_get_secure_channel_type(credentials); + + torture_comment(tctx, "Testing ServerReqChallenge\n"); + + r.in.server_name = NULL; + r.in.computer_name = machine_name; + r.in.credentials = &credentials1; + r.out.return_credentials = &credentials2; + + /* + * Set the first 4 bytes of the client challenge to the same + * value, this should pass as 5 bytes identical are needed to + * fail for CVE-2020-1472(ZeroLogon) + * + * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 + */ + credentials1.data[0] = 'A'; + credentials1.data[1] = 'A'; + credentials1.data[2] = 'A'; + credentials1.data[3] = 'A'; + credentials1.data[4] = 'B'; + credentials1.data[5] = 'C'; + credentials1.data[6] = 'D'; + credentials1.data[7] = 'E'; + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), + "ServerReqChallenge failed"); + torture_assert_ntstatus_ok( + tctx, + r.out.result, + "ServerReqChallenge failed"); + a.in.server_name = NULL; + a.in.account_name = account_name; + a.in.secure_channel_type = sec_chan_type; + a.in.computer_name = machine_name; + a.in.negotiate_flags = &in_negotiate_flags; + a.out.negotiate_flags = &out_negotiate_flags; + a.in.credentials = &credentials3; + a.out.return_credentials = &credentials3; + + creds = netlogon_creds_client_init(tctx, a.in.account_name, + a.in.computer_name, + a.in.secure_channel_type, + &credentials1, &credentials2, + mach_password, &credentials3, + in_negotiate_flags); + + torture_assert(tctx, creds != NULL, "memory allocation"); + + torture_comment(tctx, "Testing ServerAuthenticate2\n"); + + torture_assert_ntstatus_ok( + tctx, + dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), + "ServerAuthenticate2 failed"); + torture_assert_ntstatus_equal( + tctx, + a.out.result, + NT_STATUS_OK, + "ServerAuthenticate2 unexpected"); + + return true; +} + /* try a change password for our machine account */ @@ -4949,6 +5268,22 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx) torture_rpc_tcase_add_test(tcase, "lsa_over_netlogon", test_lsa_over_netlogon); torture_rpc_tcase_add_test_creds(tcase, "SetupCredentialsDowngrade", test_SetupCredentialsDowngrade); + torture_rpc_tcase_add_test_creds( + tcase, + "ServerReqChallenge", + test_ServerReqChallenge); + torture_rpc_tcase_add_test_creds( + tcase, + "ServerReqChallenge_zero_challenge", + test_ServerReqChallenge_zero_challenge); + torture_rpc_tcase_add_test_creds( + tcase, + "ServerReqChallenge_5_repeats", + test_ServerReqChallenge_5_repeats); + torture_rpc_tcase_add_test_creds( + tcase, + "ServerReqChallenge_4_repeats", + test_ServerReqChallenge_4_repeats); return suite; } -- 2.39.0 From 268303632f79d7395b452172c06b25ad68fe35fb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 10 Jul 2020 15:09:33 -0700 Subject: [PATCH 026/142] s4: torture: Add smb2.notify.handle-permissions test. Add knownfail entry. CVE-2020-14318 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434 Signed-off-by: Jeremy Allison (cherry picked from commit f100bd2f2e4f047942002a992c99104227a17f81) --- .../smb2_notify_handle_permissions | 2 + source4/torture/smb2/notify.c | 80 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions diff --git a/selftest/knownfail.d/smb2_notify_handle_permissions b/selftest/knownfail.d/smb2_notify_handle_permissions new file mode 100644 index 00000000000..c0ec8fc8153 --- /dev/null +++ b/selftest/knownfail.d/smb2_notify_handle_permissions @@ -0,0 +1,2 @@ +^samba3.smb2.notify.handle-permissions + diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c index ebb4f8a4f8e..b017491c8fb 100644 --- a/source4/torture/smb2/notify.c +++ b/source4/torture/smb2/notify.c @@ -2569,6 +2569,83 @@ done: return ok; } +/* + Test asking for a change notify on a handle without permissions. +*/ + +#define BASEDIR_HPERM BASEDIR "_HPERM" + +static bool torture_smb2_notify_handle_permissions( + struct torture_context *torture, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + union smb_notify notify; + union smb_open io; + struct smb2_handle h1 = {{0}}; + struct smb2_request *req; + + smb2_deltree(tree, BASEDIR_HPERM); + smb2_util_rmdir(tree, BASEDIR_HPERM); + + torture_comment(torture, + "TESTING CHANGE NOTIFY " + "ON A HANDLE WITHOUT PERMISSIONS\n"); + + /* + get a handle on the directory + */ + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.create_flags = 0; + io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + io.smb2.in.alloc_size = 0; + io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = BASEDIR_HPERM; + + status = smb2_create(tree, torture, &io.smb2); + CHECK_STATUS(status, NT_STATUS_OK); + h1 = io.smb2.out.file.handle; + + /* ask for a change notify, + on file or directory name changes */ + ZERO_STRUCT(notify.smb2); + notify.smb2.level = RAW_NOTIFY_SMB2; + notify.smb2.in.buffer_size = 1000; + notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME; + notify.smb2.in.file.handle = h1; + notify.smb2.in.recursive = true; + + req = smb2_notify_send(tree, ¬ify.smb2); + torture_assert_goto(torture, + req != NULL, + ret, + done, + "smb2_notify_send failed\n"); + + /* + * Cancel it, we don't really want to wait. + */ + smb2_cancel(req); + status = smb2_notify_recv(req, torture, ¬ify.smb2); + /* Handle h1 doesn't have permissions for ChangeNotify. */ + CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + +done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree, h1); + } + smb2_deltree(tree, BASEDIR_HPERM); + return ret; +} + /* basic testing of SMB2 change notify */ @@ -2602,6 +2679,9 @@ struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx) torture_smb2_notify_rmdir3); torture_suite_add_2smb2_test(suite, "rmdir4", torture_smb2_notify_rmdir4); + torture_suite_add_1smb2_test(suite, + "handle-permissions", + torture_smb2_notify_handle_permissions); suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests"); -- 2.39.0 From 448d4e99f8883a07589264cfca474c3dff8b5942 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Jul 2020 18:25:23 -0700 Subject: [PATCH 027/142] s3: smbd: Ensure change notifies can't get set unless the directory handle is open for SEC_DIR_LIST. Remove knownfail entry. CVE-2020-14318 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434 Signed-off-by: Jeremy Allison (cherry picked from commit f43ecce46a89c6380317fbb5f2ae38f48d3d42c8) --- selftest/knownfail.d/smb2_notify_handle_permissions | 2 -- source3/smbd/notify.c | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions diff --git a/selftest/knownfail.d/smb2_notify_handle_permissions b/selftest/knownfail.d/smb2_notify_handle_permissions deleted file mode 100644 index c0ec8fc8153..00000000000 --- a/selftest/knownfail.d/smb2_notify_handle_permissions +++ /dev/null @@ -1,2 +0,0 @@ -^samba3.smb2.notify.handle-permissions - diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 44c0b09432e..d23c03bce41 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -283,6 +283,14 @@ NTSTATUS change_notify_create(struct files_struct *fsp, uint32_t filter, char fullpath[len+1]; NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED; + /* + * Setting a changenotify needs READ/LIST access + * on the directory handle. + */ + if (!(fsp->access_mask & SEC_DIR_LIST)) { + return NT_STATUS_ACCESS_DENIED; + } + if (fsp->notify != NULL) { DEBUG(1, ("change_notify_create: fsp->notify != NULL, " "fname = %s\n", fsp->fsp_name->base_name)); -- 2.39.0 From 041c86926999594f13b884522b1d9fcc65f92a52 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 9 Jul 2020 21:49:25 +0200 Subject: [PATCH 028/142] CVE-2020-14323 winbind: Fix invalid lookupsids DoS A lookupsids request without extra_data will lead to "state->domain==NULL", which makes winbindd_lookupsids_recv trying to dereference it. Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134 Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436 Signed-off-by: Volker Lendecke (cherry picked from commit f17967ad73e9c1d2bd6e0b7c181f08079d2a8214) --- source3/winbindd/winbindd_lookupsids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/winbindd/winbindd_lookupsids.c b/source3/winbindd/winbindd_lookupsids.c index d28b5fa9f01..a289fd86f0f 100644 --- a/source3/winbindd/winbindd_lookupsids.c +++ b/source3/winbindd/winbindd_lookupsids.c @@ -47,7 +47,7 @@ struct tevent_req *winbindd_lookupsids_send(TALLOC_CTX *mem_ctx, DEBUG(3, ("lookupsids\n")); if (request->extra_len == 0) { - tevent_req_done(req); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } if (request->extra_data.data[request->extra_len-1] != '\0') { -- 2.39.0 From e6e77a3a503f9223ecbc2d32a1d24e20f834659f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 9 Jul 2020 21:48:57 +0200 Subject: [PATCH 029/142] CVE-2020-14323 torture4: Add a simple test for invalid lookup_sids winbind call We can't add this test before the fix, add it to knownfail and have the fix remove the knownfail entry again. As this crashes winbind, many tests after this one will fail. Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134 Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436 Signed-off-by: Volker Lendecke (cherry picked from commit d0ca2a63aaedf123205337aaa211426175ffcebf) --- source4/torture/winbind/struct_based.c | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c index 9745b621ca9..71f248c0d61 100644 --- a/source4/torture/winbind/struct_based.c +++ b/source4/torture/winbind/struct_based.c @@ -1110,6 +1110,29 @@ static bool torture_winbind_struct_lookup_name_sid(struct torture_context *tortu return true; } +static bool torture_winbind_struct_lookup_sids_invalid( + struct torture_context *torture) +{ + struct winbindd_request req = {0}; + struct winbindd_response rep = {0}; + bool strict = torture_setting_bool(torture, "strict mode", false); + bool ok; + + torture_comment(torture, + "Running WINBINDD_LOOKUP_SIDS (struct based)\n"); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSIDS, &req, &rep, + NSS_STATUS_NOTFOUND, + strict, + ok=false, + talloc_asprintf( + torture, + "invalid lookupsids succeeded")); + + return ok; +} + struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "struct"); @@ -1132,6 +1155,10 @@ struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx) torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent); torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent); torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid); + torture_suite_add_simple_test( + suite, + "lookup_sids_invalid", + torture_winbind_struct_lookup_sids_invalid); suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests"); -- 2.39.0 From 2b4763940d1826a2b4e5eaa1e2df338004cd9af0 Mon Sep 17 00:00:00 2001 From: Laurent Menase Date: Wed, 20 May 2020 12:31:53 +0200 Subject: [PATCH 030/142] winbind: Fix a memleak Bug: https://bugzilla.samba.org/show_bug.cgi?id=14388 Signed-off-by: Laurent Menase Reviewed-by: Volker Lendecke Reviewed-by: Noel Power Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Mon Sep 14 13:33:13 UTC 2020 on sn-devel-184 (cherry picked from commit 8f868b0ea0b4795668f7bc0b028cd85686b249fb) --- source3/winbindd/winbindd_ads.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 556b4523866..325ba1abd82 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -405,6 +405,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, DBG_NOTICE("ads query_user_list gave %d entries\n", count); done: + ads_msgfree(ads, res); return status; } -- 2.39.0 From accc423a4eb9170ab0dbe4b2ba90ce83790e7a16 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 17 Aug 2020 13:39:58 +0200 Subject: [PATCH 031/142] s3:tests: Add test for 'valid users = DOMAIN\%U' BUG: https://bugzilla.samba.org/show_bug.cgi?id=14467 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme (cherry picked from commit 53b6dd951249052772e1ffcf651b7efd0963b931) (cherry picked from commit 20d3cf455c631c6cea6d471333779cc15d0e8d8a) --- selftest/knownfail.d/samba3.substiutions | 1 + selftest/target/Samba3.pm | 4 ++++ source3/script/tests/test_substitutions.sh | 5 +++++ 3 files changed, 10 insertions(+) create mode 100644 selftest/knownfail.d/samba3.substiutions diff --git a/selftest/knownfail.d/samba3.substiutions b/selftest/knownfail.d/samba3.substiutions new file mode 100644 index 00000000000..f116d3b2fcf --- /dev/null +++ b/selftest/knownfail.d/samba3.substiutions @@ -0,0 +1 @@ +^samba3.substitutions.Test.login.to.share.with.substitution.for.valid.users diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 75960dbc790..9e4da0e6a08 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -423,6 +423,10 @@ sub setup_ad_member path = $share_dir/D_%D/u_%u/g_%g writeable = yes +[sub_valid_users] + path = $share_dir + valid users = ADDOMAIN/%U + "; my $ret = $self->provision($prefix, $dcvars->{DOMAIN}, diff --git a/source3/script/tests/test_substitutions.sh b/source3/script/tests/test_substitutions.sh index 1a46f11c85d..c813a8f9def 100755 --- a/source3/script/tests/test_substitutions.sh +++ b/source3/script/tests/test_substitutions.sh @@ -34,4 +34,9 @@ SMB_UNC="//$SERVER/sub_dug2" test_smbclient "Test login to share with substitution (Dug)" \ "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1) +SMB_UNC="//$SERVER/sub_valid_users" + +test_smbclient "Test login to share with substitution for valid users" \ + "ls" "$SMB_UNC" "-U$USERNAME%$PASSWORD" || failed=$(expr $failed + 1) + exit $failed -- 2.39.0 From 1c594e3734e3ffd2dfc615897ac95792878f2df4 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 17 Aug 2020 14:12:48 +0200 Subject: [PATCH 032/142] s3:smbd: Fix %U substitutions if it contains a domain name 'valid users = DOMAIN\%U' worked with Samba 3.6 and broke in a newer version. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14467 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme (cherry picked from commit 5de7c91e6d4e98f438157a7675c8582cabdd828d) (cherry picked from commit 60ddb7b20071b00f0cd7f1cb818022220eb0c279) --- selftest/knownfail.d/samba3.substiutions | 1 - source3/smbd/share_access.c | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/samba3.substiutions diff --git a/selftest/knownfail.d/samba3.substiutions b/selftest/knownfail.d/samba3.substiutions deleted file mode 100644 index f116d3b2fcf..00000000000 --- a/selftest/knownfail.d/samba3.substiutions +++ /dev/null @@ -1 +0,0 @@ -^samba3.substitutions.Test.login.to.share.with.substitution.for.valid.users diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c index 3cbf7f318a2..0705e197975 100644 --- a/source3/smbd/share_access.c +++ b/source3/smbd/share_access.c @@ -79,7 +79,23 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, enum lsa_SidType type; if (username != NULL) { - name = talloc_sub_basic(mem_ctx, username, domain, name); + size_t domain_len = strlen(domain); + + /* Check if username starts with domain name */ + if (domain_len > 0) { + const char *sep = lp_winbind_separator(); + int cmp = strncasecmp_m(username, domain, domain_len); + if (cmp == 0 && sep[0] == username[domain_len]) { + /* Move after the winbind separator */ + domain_len += 1; + } else { + domain_len = 0; + } + } + name = talloc_sub_basic(mem_ctx, + username + domain_len, + domain, + name); } if (sharename != NULL) { name = talloc_string_sub(mem_ctx, name, "%S", sharename); -- 2.39.0 From d93ddae23e1b378f771134e93d1b15e61e2278af Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 9 Jul 2020 11:48:26 +0200 Subject: [PATCH 033/142] docs: Fix documentation for require_membership_of of pam_winbind BUG: https://bugzilla.samba.org/show_bug.cgi?id=14358 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 4c74db6978c682f8ba4e74a6ee8157cfcbb54971) --- docs-xml/manpages/pam_winbind.8.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs-xml/manpages/pam_winbind.8.xml b/docs-xml/manpages/pam_winbind.8.xml index a9a227f1647..a61fb2d58e5 100644 --- a/docs-xml/manpages/pam_winbind.8.xml +++ b/docs-xml/manpages/pam_winbind.8.xml @@ -84,9 +84,11 @@ If this option is set, pam_winbind will only succeed if the user is a member of the given SID or NAME. A SID can be either a group-SID, an alias-SID or even an user-SID. It is also possible to give a NAME instead of the SID. That name must have the form: MYDOMAIN\mygroup or - MYDOMAIN\myuser. pam_winbind will, in that case, lookup the SID internally. Note that - NAME may not contain any spaces. It is thus recommended to only use SIDs. You can verify the list of SIDs a - user is a member of with wbinfo --user-sids=SID. + MYDOMAIN\myuser (where '\' character corresponds to the value of + winbind separator parameter). It is also possible to use a UPN in the form + user@REALM or group@REALM. pam_winbind will, in that case, lookup + the SID internally. Note that NAME may not contain any spaces. It is thus recommended to only use SIDs. You can + verify the list of SIDs a user is a member of with wbinfo --user-sids=SID. -- 2.39.0 From c9aea952eb3f8d83701abd6db4d48c8d93a8517a Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Fri, 17 Jul 2020 12:14:16 +0200 Subject: [PATCH 034/142] docs: Fix documentation for require_membership_of of pam_winbind.conf BUG: https://bugzilla.samba.org/show_bug.cgi?id=14358 Signed-off-by: Andreas Schneider Reviewed-by: Isaac Boukris (cherry picked from commit 71b7140fd0a33e7e8c5bf37c2897cea8224b3f01) --- docs-xml/manpages/pam_winbind.conf.5.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs-xml/manpages/pam_winbind.conf.5.xml b/docs-xml/manpages/pam_winbind.conf.5.xml index fcac1ee7036..d81a0bd6eba 100644 --- a/docs-xml/manpages/pam_winbind.conf.5.xml +++ b/docs-xml/manpages/pam_winbind.conf.5.xml @@ -69,9 +69,12 @@ If this option is set, pam_winbind will only succeed if the user is a member of the given SID or NAME. A SID can be either a group-SID, an alias-SID or even an user-SID. It is also possible to give a NAME instead of the SID. That name must have the form: MYDOMAIN\mygroup or - MYDOMAIN\myuser. pam_winbind will, in that case, lookup the SID internally. Note that - NAME may not contain any spaces. It is thus recommended to only use SIDs. You can verify the list of SIDs a - user is a member of with wbinfo --user-sids=SID. This setting is empty by default. + MYDOMAIN\myuser (where '\' character corresponds to the value of + winbind separator parameter). It is also possible to use a UPN in the form + user@REALM or group@REALM. pam_winbind will, in that case, lookup + the SID internally. Note that NAME may not contain any spaces. It is thus recommended to only use SIDs. You can + verify the list of SIDs a user is a member of with wbinfo --user-sids=SID. + This setting is empty by default. This option only operates during password authentication, and will not restrict access if a password is not required for any reason (such as SSH key-based login). -- 2.39.0 From b04be6ffd3a1c9eda1f1dc78d60ad7b3a9b7471d Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Thu, 11 Jun 2020 21:05:07 +0300 Subject: [PATCH 035/142] Fix a typo in recent net man page changes BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider (cherry picked from commit 4e51e832176a99f2a841c7a0d78fb0424f02956e) --- docs-xml/manpages/net.8.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-xml/manpages/net.8.xml b/docs-xml/manpages/net.8.xml index 69e18df8b6c..9b1d4458acc 100644 --- a/docs-xml/manpages/net.8.xml +++ b/docs-xml/manpages/net.8.xml @@ -470,7 +470,7 @@ joining the domain. -[FQDN] (ADS only) set the dnsHosName attribute during the join. +[FQDN] (ADS only) set the dnsHostName attribute during the join. The default format is netbiosname.dnsdomain. -- 2.39.0 From a5a7dac759c2570861732c68efefb62371a29565 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Tue, 16 Jun 2020 22:01:49 +0300 Subject: [PATCH 036/142] selftest: add tests for binary msDS-AdditionalDnsHostName Like the short names added implicitly by Windows DC. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider (cherry picked from commit 4605d7aec5caf494a23f2c9800d6689f710ffbce) --- selftest/knownfail.d/binary_addl_hostname | 3 +++ testprogs/blackbox/test_net_ads.sh | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 selftest/knownfail.d/binary_addl_hostname diff --git a/selftest/knownfail.d/binary_addl_hostname b/selftest/knownfail.d/binary_addl_hostname new file mode 100644 index 00000000000..559db1df507 --- /dev/null +++ b/selftest/knownfail.d/binary_addl_hostname @@ -0,0 +1,3 @@ +^samba4.blackbox.net_ads.dns alias1 check keytab +^samba4.blackbox.net_ads.dns alias2 check keytab +^samba4.blackbox.net_ads.addl short check keytab diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index 85257f445d8..eef4a31a6a7 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -41,6 +41,11 @@ if [ -x "$BINDIR/ldbdel" ]; then ldbdel="$BINDIR/ldbdel" fi +ldbmodify="ldbmodify" +if [ -x "$BINDIR/ldbmodify" ]; then + ldbmodify="$BINDIR/ldbmodify" +fi + # Load test functions . `dirname $0`/subunit.sh @@ -217,12 +222,29 @@ testit_grep "dns alias SPN" $dns_alias2 $VALGRIND $net_tool ads search -P samacc testit_grep "dns alias addl" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` +# Test binary msDS-AdditionalDnsHostName like ones added by Windows DC +short_alias_file="$PREFIX_ABS/short_alias_file" +printf 'short_alias\0$' > $short_alias_file +cat > $PREFIX_ABS/tmpldbmodify < Date: Thu, 11 Jun 2020 16:51:27 +0300 Subject: [PATCH 037/142] Properly handle msDS-AdditionalDnsHostName returned from Windows DC Windows DC adds short names for each specified msDS-AdditionalDnsHostName attribute, but these have a suffix of "\0$" and thus fail with ldap_get_values(), use ldap_get_values_len() instead. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Autobuild-User(master): Isaac Boukris Autobuild-Date(master): Thu Jun 18 16:43:47 UTC 2020 on sn-devel-184 (cherry picked from commit 9a447fb7e0701bf8b2fd922aed44d89f40420251) --- selftest/knownfail.d/binary_addl_hostname | 3 -- source3/libads/ldap.c | 38 +++++++++++++++++++++-- 2 files changed, 35 insertions(+), 6 deletions(-) delete mode 100644 selftest/knownfail.d/binary_addl_hostname diff --git a/selftest/knownfail.d/binary_addl_hostname b/selftest/knownfail.d/binary_addl_hostname deleted file mode 100644 index 559db1df507..00000000000 --- a/selftest/knownfail.d/binary_addl_hostname +++ /dev/null @@ -1,3 +0,0 @@ -^samba4.blackbox.net_ads.dns alias1 check keytab -^samba4.blackbox.net_ads.dns alias2 check keytab -^samba4.blackbox.net_ads.addl short check keytab diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 02a628ee0e6..2684bba63ec 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -3664,6 +3664,40 @@ out: /******************************************************************** ********************************************************************/ +static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, + LDAPMessage *msg, size_t *num_values) +{ + const char *field = "msDS-AdditionalDnsHostName"; + struct berval **values = NULL; + char **ret = NULL; + size_t i, converted_size; + + values = ldap_get_values_len(ads->ldap.ld, msg, field); + if (values == NULL) { + return NULL; + } + + *num_values = ldap_count_values_len(values); + + ret = talloc_array(mem_ctx, char *, *num_values + 1); + if (ret == NULL) { + ldap_value_free_len(values); + return NULL; + } + + for (i = 0; i < *num_values; i++) { + if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i]->bv_val, + &converted_size)) { + ldap_value_free_len(values); + return NULL; + } + } + ret[i] = NULL; + + ldap_value_free_len(values); + return ret; +} + ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *machine_name, @@ -3689,9 +3723,7 @@ ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx, goto done; } - *hostnames_array = ads_pull_strings(ads, mem_ctx, res, - "msDS-AdditionalDnsHostName", - num_hostnames); + *hostnames_array = get_addl_hosts(ads, mem_ctx, res, num_hostnames); if (*hostnames_array == NULL) { DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n", machine_name)); -- 2.39.0 From 9727953d482a3849d4ac1f40486bc567f6b77067 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sat, 20 Jun 2020 17:17:33 +0200 Subject: [PATCH 038/142] Fix usage of ldap_get_values_len for msDS-AdditionalDnsHostName BUG: https://bugzilla.samba.org/show_bug.cgi?id=14406 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Mon Jun 22 09:59:04 UTC 2020 on sn-devel-184 (cherry picked from commit f9dd67355ba35539d7ae1774d5135fd05d747b3f) --- source3/libads/ldap.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 2684bba63ec..d1ce9cee2f0 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -3686,8 +3686,12 @@ static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, } for (i = 0; i < *num_values; i++) { - if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i]->bv_val, - &converted_size)) { + ret[i] = NULL; + if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX, + values[i]->bv_val, + strnlen(values[i]->bv_val, + values[i]->bv_len), + &ret[i], &converted_size)) { ldap_value_free_len(values); return NULL; } -- 2.39.0 From ec4cfe786d8c3cb67bb0e9224ae1822902c672d3 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Tue, 15 Dec 2020 15:17:04 +0100 Subject: [PATCH 039/142] HACK:s3:winbind: Rely on the domain child for online check --- source3/winbindd/winbindd_cm.c | 9 +++++++++ source3/winbindd/winbindd_dual.c | 3 +++ 2 files changed, 12 insertions(+) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 4bd03ed8b7a..502331f7260 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -89,6 +89,8 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +extern bool wb_idmap_child; + struct dc_name_ip { fstring name; struct sockaddr_storage ss; @@ -176,6 +178,13 @@ static void msg_try_to_go_online(struct messaging_context *msg, continue; } + if (wb_child_domain() == NULL && !wb_idmap_child) { + DEBUG(5,("msg_try_to_go_online: domain %s " + "NOT CONNECTING IN MAIN PROCESS.\n", domainname)); + domain->online = true; + continue; + } + /* This call takes care of setting the online flag to true if we connected, or re-adding the offline handler if false. Bypasses online diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 6e3277e5529..35b76a367aa 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -1612,6 +1612,8 @@ static void child_handler(struct tevent_context *ev, struct tevent_fd *fde, } } +bool wb_idmap_child; + static bool fork_domain_child(struct winbindd_child *child) { int fdpair[2]; @@ -1715,6 +1717,7 @@ static bool fork_domain_child(struct winbindd_child *child) setproctitle("domain child [%s]", child_domain->name); } else if (child == idmap_child()) { setproctitle("idmap child"); + wb_idmap_child = true; } /* Handle online/offline messages. */ -- 2.39.0 From 958bed1a1e5c9f334a1859bef14f4fe1657c3e49 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 9 Sep 2020 16:00:52 +0200 Subject: [PATCH 040/142] s3:smbd: Use fsp al the talloc memory context Somehow the lck pointer gets freed before we call TALLOC_FREE(). Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner Reviewed-by: Alexander Bokovoy --- source3/smbd/open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index de557f53a20..9a24e331ab1 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -4239,7 +4239,7 @@ static NTSTATUS open_directory(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, + lck = get_share_mode_lock(fsp, fsp->file_id, conn->connectpath, smb_dname, &mtimespec); -- 2.39.0 From 2591ae5d6a1dbd71391801b7bdf20bd37c8e8375 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 3 Feb 2021 12:58:31 +0100 Subject: [PATCH 041/142] Revert "s3:smbd: Use fsp al the talloc memory context" This reverts commit 958bed1a1e5c9f334a1859bef14f4fe1657c3e49. --- source3/smbd/open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 9a24e331ab1..de557f53a20 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -4239,7 +4239,7 @@ static NTSTATUS open_directory(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - lck = get_share_mode_lock(fsp, fsp->file_id, + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, conn->connectpath, smb_dname, &mtimespec); -- 2.39.0 From 2438619ec7ef18816f6b92c87a094851223d2bb1 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 22 Jul 2020 22:42:09 -0700 Subject: [PATCH 042/142] nsswitch/nsstest.c: Avoid nss function conflicts with glibc nss.h glibc 2.32 will define these varibles [1] which results in conflicts with these static function names, therefore prefix these function names with samba_ to avoid it [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=499a92df8b9fc64a054cf3b7f728f8967fc1da7d Signed-off-by: Khem Raj Reviewed-by: Volker Lendecke Reviewed-by: Noel Power Autobuild-User(master): Noel Power Autobuild-Date(master): Tue Jul 28 10:52:00 UTC 2020 on sn-devel-184 (cherry picked from commit 6e496aa3635557b59792e469f7c7f8eccd822322) --- nsswitch/nsstest.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nsswitch/nsstest.c b/nsswitch/nsstest.c index 6d92806cffc..46f96795f39 100644 --- a/nsswitch/nsstest.c +++ b/nsswitch/nsstest.c @@ -137,7 +137,7 @@ static struct passwd *nss_getpwuid(uid_t uid) return &pwd; } -static void nss_setpwent(void) +static void samba_nss_setpwent(void) { NSS_STATUS (*_nss_setpwent)(void) = (NSS_STATUS(*)(void))find_fn("setpwent"); @@ -152,7 +152,7 @@ static void nss_setpwent(void) } } -static void nss_endpwent(void) +static void samba_nss_endpwent(void) { NSS_STATUS (*_nss_endpwent)(void) = (NSS_STATUS (*)(void))find_fn("endpwent"); @@ -284,7 +284,7 @@ again: return &grp; } -static void nss_setgrent(void) +static void samba_nss_setgrent(void) { NSS_STATUS (*_nss_setgrent)(void) = (NSS_STATUS (*)(void))find_fn("setgrent"); @@ -299,7 +299,7 @@ static void nss_setgrent(void) } } -static void nss_endgrent(void) +static void samba_nss_endgrent(void) { NSS_STATUS (*_nss_endgrent)(void) = (NSS_STATUS (*)(void))find_fn("endgrent"); @@ -396,7 +396,7 @@ static void nss_test_users(void) { struct passwd *pwd; - nss_setpwent(); + samba_nss_setpwent(); /* loop over all users */ while ((pwd = nss_getpwent())) { printf("Testing user %s\n", pwd->pw_name); @@ -418,14 +418,14 @@ static void nss_test_users(void) printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid); printf("\n"); } - nss_endpwent(); + samba_nss_endpwent(); } static void nss_test_groups(void) { struct group *grp; - nss_setgrent(); + samba_nss_setgrent(); /* loop over all groups */ while ((grp = nss_getgrent())) { printf("Testing group %s\n", grp->gr_name); @@ -446,7 +446,7 @@ static void nss_test_groups(void) printf("getgrgid: "); print_group(grp); printf("\n"); } - nss_endgrent(); + samba_nss_endgrent(); } static void nss_test_errors(void) -- 2.39.0 From d5410b038bb3b1d31783c0d825dc933497f6eeaa Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 3 Feb 2021 10:30:08 +0100 Subject: [PATCH 043/142] lib:util: Add basic memcache unit test BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme (cherry picked from commit bebbf621d6052f797c5cf19a2a9bbc13e699d3f0) --- lib/util/tests/test_memcache.c | 122 +++++++++++++++++++++++++++++++++ lib/util/wscript_build | 6 ++ selftest/tests.py | 2 + 3 files changed, 130 insertions(+) create mode 100644 lib/util/tests/test_memcache.c diff --git a/lib/util/tests/test_memcache.c b/lib/util/tests/test_memcache.c new file mode 100644 index 00000000000..8ea5e5b042e --- /dev/null +++ b/lib/util/tests/test_memcache.c @@ -0,0 +1,122 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) 2021 Andreas Schneider + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General 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 +#include +#include +#include +#include + +#include "lib/replace/replace.h" +#include "lib/util/talloc_stack.h" +#include "lib/util/memcache.h" + +static int setup_talloc_context(void **state) +{ + TALLOC_CTX *frame = talloc_stackframe(); + + *state = frame; + return 0; +} + +static int teardown_talloc_context(void **state) +{ + TALLOC_CTX *frame = *state; + TALLOC_FREE(frame); + return 0; +} + +static void torture_memcache_init(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + struct memcache *cache = NULL; + + cache = memcache_init(mem_ctx, 0); + assert_non_null(cache); + + TALLOC_FREE(cache); + + cache = memcache_init(mem_ctx, 10); + assert_non_null(cache); + + TALLOC_FREE(cache); +} + +static void torture_memcache_add_lookup_delete(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + struct memcache *cache = NULL; + DATA_BLOB key1, key2; + char *path1 = NULL, *path2 = NULL; + + cache = memcache_init(mem_ctx, 0); + assert_non_null(cache); + + key1 = data_blob_const("key1", 4); + path1 = talloc_strdup(mem_ctx, "/tmp/one"); + assert_non_null(path1); + + key2 = data_blob_const("key2", 4); + path2 = talloc_strdup(mem_ctx, "/tmp/two"); + assert_non_null(path1); + + memcache_add_talloc(cache, GETWD_CACHE, key1, &path1); + assert_null(path1); + + memcache_add_talloc(cache, GETWD_CACHE, key2, &path2); + assert_null(path2); + + path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1); + assert_non_null(path1); + assert_string_equal(path1, "/tmp/one"); + + path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2); + assert_non_null(path2); + assert_string_equal(path2, "/tmp/two"); + + memcache_delete(cache, GETWD_CACHE, key1); + path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1); + assert_null(path1); + + memcache_flush(cache, GETWD_CACHE); + path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2); + assert_null(path2); + + TALLOC_FREE(cache); +} + +int main(int argc, char *argv[]) +{ + int rc; + const struct CMUnitTest tests[] = { + cmocka_unit_test(torture_memcache_init), + cmocka_unit_test(torture_memcache_add_lookup_delete), + }; + + if (argc == 2) { + cmocka_set_test_filter(argv[1]); + } + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + rc = cmocka_run_group_tests(tests, + setup_talloc_context, + teardown_talloc_context); + + return rc; +} diff --git a/lib/util/wscript_build b/lib/util/wscript_build index fd3027eff77..229dbd5ef6a 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -256,3 +256,9 @@ else: deps='cmocka replace talloc samba-util', local_include=False, install=False) + + bld.SAMBA_BINARY('test_memcache', + source='tests/test_memcache.c', + deps='cmocka replace talloc samba-util', + local_include=False, + install=False) diff --git a/selftest/tests.py b/selftest/tests.py index e7639c4da27..e3f7d9acb4a 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -254,6 +254,8 @@ plantestsuite("samba.unittests.ms_fnmatch", "none", [os.path.join(bindir(), "default/lib/util/test_ms_fnmatch")]) plantestsuite("samba.unittests.util_paths", "none", [os.path.join(bindir(), "default/lib/util/test_util_paths")]) +plantestsuite("samba.unittests.memcache", "none", + [os.path.join(bindir(), "default/lib/util/test_memcache")]) plantestsuite("samba.unittests.ntlm_check", "none", [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")]) plantestsuite("samba.unittests.test_registry_regfio", "none", -- 2.39.0 From 7f6661b3c60319073d7fd58906b9a3728f421fed Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 3 Feb 2021 10:37:12 +0100 Subject: [PATCH 044/142] lib:util: Add cache oversize test for memcache BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme (cherry picked from commit 00543ab3b29e3fbfe8314e51919629803e14ede6) --- lib/util/tests/test_memcache.c | 39 ++++++++++++++++++++++++++++++++++ selftest/knownfail.d/memcache | 1 + 2 files changed, 40 insertions(+) create mode 100644 selftest/knownfail.d/memcache diff --git a/lib/util/tests/test_memcache.c b/lib/util/tests/test_memcache.c index 8ea5e5b042e..8a3997817c1 100644 --- a/lib/util/tests/test_memcache.c +++ b/lib/util/tests/test_memcache.c @@ -98,6 +98,44 @@ static void torture_memcache_add_lookup_delete(void **state) path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2); assert_null(path2); + TALLOC_FREE(path1); + TALLOC_FREE(path2); + TALLOC_FREE(cache); +} + +static void torture_memcache_add_oversize(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + struct memcache *cache = NULL; + DATA_BLOB key1, key2; + char *path1 = NULL, *path2 = NULL; + + cache = memcache_init(mem_ctx, 10); + assert_non_null(cache); + + key1 = data_blob_const("key1", 4); + path1 = talloc_strdup(mem_ctx, "/tmp/one"); + assert_non_null(path1); + + key2 = data_blob_const("key2", 4); + path2 = talloc_strdup(mem_ctx, "/tmp/two"); + assert_non_null(path1); + + memcache_add_talloc(cache, GETWD_CACHE, key1, &path1); + assert_null(path1); + + memcache_add_talloc(cache, GETWD_CACHE, key2, &path2); + assert_null(path2); + + path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1); + assert_null(path1); + + path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2); + assert_non_null(path2); + assert_string_equal(path2, "/tmp/two"); + + TALLOC_FREE(path1); + TALLOC_FREE(path2); TALLOC_FREE(cache); } @@ -107,6 +145,7 @@ int main(int argc, char *argv[]) const struct CMUnitTest tests[] = { cmocka_unit_test(torture_memcache_init), cmocka_unit_test(torture_memcache_add_lookup_delete), + cmocka_unit_test(torture_memcache_add_oversize), }; if (argc == 2) { diff --git a/selftest/knownfail.d/memcache b/selftest/knownfail.d/memcache new file mode 100644 index 00000000000..0a74ace3003 --- /dev/null +++ b/selftest/knownfail.d/memcache @@ -0,0 +1 @@ +^samba.unittests.memcache.torture_memcache_add_oversize -- 2.39.0 From 53c7f00510556aea15b640254934e514c1d88c25 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 2 Feb 2021 18:10:38 +0100 Subject: [PATCH 045/142] lib:util: Avoid free'ing our own pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG: https://bugzilla.samba.org/show_bug.cgi?id=14625 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Wed Feb 3 10:57:01 UTC 2021 on sn-devel-184 (cherry picked from commit 0bdbe50fac680be3fe21043246b8c75005611351) --- lib/util/memcache.c | 19 +++++++++++++++---- selftest/knownfail.d/memcache | 1 - 2 files changed, 15 insertions(+), 5 deletions(-) delete mode 100644 selftest/knownfail.d/memcache diff --git a/lib/util/memcache.c b/lib/util/memcache.c index 1e616bd0e9a..7b0b27eaddb 100644 --- a/lib/util/memcache.c +++ b/lib/util/memcache.c @@ -223,14 +223,25 @@ static void memcache_delete_element(struct memcache *cache, TALLOC_FREE(e); } -static void memcache_trim(struct memcache *cache) +static void memcache_trim(struct memcache *cache, struct memcache_element *e) { + struct memcache_element *tail = NULL; + if (cache->max_size == 0) { return; } - while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) { - memcache_delete_element(cache, DLIST_TAIL(cache->mru)); + for (tail = DLIST_TAIL(cache->mru); + (cache->size > cache->max_size) && (tail != NULL); + tail = DLIST_TAIL(cache->mru)) + { + if (tail == e) { + tail = DLIST_PREV(tail); + if (tail == NULL) { + break; + } + } + memcache_delete_element(cache, tail); } } @@ -351,7 +362,7 @@ void memcache_add(struct memcache *cache, enum memcache_number n, memcpy(&mtv, cache_value.data, sizeof(mtv)); cache->size += mtv.len; } - memcache_trim(cache); + memcache_trim(cache, e); } void memcache_add_talloc(struct memcache *cache, enum memcache_number n, diff --git a/selftest/knownfail.d/memcache b/selftest/knownfail.d/memcache deleted file mode 100644 index 0a74ace3003..00000000000 --- a/selftest/knownfail.d/memcache +++ /dev/null @@ -1 +0,0 @@ -^samba.unittests.memcache.torture_memcache_add_oversize -- 2.39.0 From 138662453fb421609b4fa30487a53a50c085895f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 5 Nov 2020 15:48:08 -0800 Subject: [PATCH 046/142] s3: spoolss: Make parameters in call to user_ok_token() match all other uses. We already have p->session_info->unix_info->unix_name, we don't need to go through a legacy call to uidtoname(p->session_info->unix_token->uid). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14568 Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Mon Nov 9 04:10:45 UTC 2020 on sn-devel-184 (cherry picked from commit e5e1759057a767f517bf480a2172a36623df2799) --- source3/rpc_server/spoolss/srv_spoolss_nt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index f32b465afb6..c0f1803c2fa 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -1869,7 +1869,8 @@ WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, return WERR_ACCESS_DENIED; } - if (!user_ok_token(uidtoname(p->session_info->unix_token->uid), NULL, + if (!user_ok_token(p->session_info->unix_info->unix_name, + p->session_info->info->domain_name, p->session_info->security_token, snum) || !W_ERROR_IS_OK(print_access_check(p->session_info, p->msg_ctx, -- 2.39.0 From 9550eb620ff23fb9f9414c9de596789aae64aef1 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 11 Nov 2020 13:42:06 +0100 Subject: [PATCH 047/142] s3:smbd: Fix possible null pointer dereference in token_contains_name() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14572 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy Autobuild-User(master): Alexander Bokovoy Autobuild-Date(master): Thu Nov 12 15:13:47 UTC 2020 on sn-devel-184 (cherry picked from commit 8036bf9717f83e83c3e4a9cf00fded42e9a5de15) --- source3/smbd/share_access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c index 0705e197975..64276c79fbe 100644 --- a/source3/smbd/share_access.c +++ b/source3/smbd/share_access.c @@ -79,7 +79,7 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx, enum lsa_SidType type; if (username != NULL) { - size_t domain_len = strlen(domain); + size_t domain_len = domain != NULL ? strlen(domain) : 0; /* Check if username starts with domain name */ if (domain_len > 0) { -- 2.39.0 From 49a19805c6837df04dce449841d011fc67e0a7df Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 20 Feb 2021 15:50:12 +0100 Subject: [PATCH 048/142] passdb: Simplify sids_to_unixids() Best reviewed with "git show -b", there's a "continue" statement that changes subsequent indentation. Decouple lookup status of ids from ID_TYPE_NOT_SPECIFIED Bug: https://bugzilla.samba.org/show_bug.cgi?id=14571 Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/passdb/lookup_sid.c | 123 +++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 22 deletions(-) diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 1bb15ccb8b4..186ba17fda6 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -29,6 +29,7 @@ #include "../libcli/security/security.h" #include "lib/winbind_util.h" #include "../librpc/gen_ndr/idmap.h" +#include "lib/util/bitmap.h" static bool lookup_unix_user_name(const char *name, struct dom_sid *sid) { @@ -1247,7 +1248,9 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, { struct wbcDomainSid *wbc_sids = NULL; struct wbcUnixId *wbc_ids = NULL; + struct bitmap *found = NULL; uint32_t i, num_not_cached; + uint32_t wbc_ids_size = 0; wbcErr err; bool ret = false; @@ -1255,6 +1258,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, if (wbc_sids == NULL) { return false; } + found = bitmap_talloc(wbc_sids, num_sids); + if (found == NULL) { + goto fail; + } + + /* + * We go through the requested SID array three times. + * First time to look for global_sid_Unix_Users + * and global_sid_Unix_Groups SIDS, and to look + * for mappings cached in the idmap_cache. + * + * Use bitmap_set() to mark an ids[] array entry as + * being mapped. + */ num_not_cached = 0; @@ -1266,17 +1283,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, &sids[i], &rid)) { ids[i].type = ID_TYPE_UID; ids[i].id = rid; + bitmap_set(found, i); continue; } if (sid_peek_check_rid(&global_sid_Unix_Groups, &sids[i], &rid)) { ids[i].type = ID_TYPE_GID; ids[i].id = rid; + bitmap_set(found, i); continue; } if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired) && !expired) { + bitmap_set(found, i); continue; } ids[i].type = ID_TYPE_NOT_SPECIFIED; @@ -1287,62 +1307,121 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, if (num_not_cached == 0) { goto done; } - wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached); + + /* + * For the ones that we couldn't map in the loop above, query winbindd + * via wbcSidsToUnixIds(). + */ + + wbc_ids_size = num_not_cached; + wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size); if (wbc_ids == NULL) { goto fail; } - for (i=0; i id is a union anyway */ - ids[i].type = (enum id_type)wbc_ids[num_not_cached].type; - ids[i].id = wbc_ids[num_not_cached].id.gid; - break; - } - num_not_cached += 1; + if (bitmap_query(found, i)) { + continue; } + + SMB_ASSERT(num_not_cached < wbc_ids_size); + + switch (wbc_ids[num_not_cached].type) { + case WBC_ID_TYPE_UID: + ids[i].type = ID_TYPE_UID; + ids[i].id = wbc_ids[num_not_cached].id.uid; + bitmap_set(found, i); + break; + case WBC_ID_TYPE_GID: + ids[i].type = ID_TYPE_GID; + ids[i].id = wbc_ids[num_not_cached].id.gid; + bitmap_set(found, i); + break; + case WBC_ID_TYPE_BOTH: + ids[i].type = ID_TYPE_BOTH; + ids[i].id = wbc_ids[num_not_cached].id.uid; + bitmap_set(found, i); + break; + case WBC_ID_TYPE_NOT_SPECIFIED: + /* + * wbcSidsToUnixIds() wasn't able to map this + * so we still need to check legacy_sid_to_XXX() + * below. Don't mark the bitmap entry + * as being found so the final loop knows + * to try and map this entry. + */ + ids[i].type = ID_TYPE_NOT_SPECIFIED; + ids[i].id = (uint32_t)-1; + break; + default: + /* + * A successful return from wbcSidsToUnixIds() + * cannot return anything other than the values + * checked for above. Ensure this is so. + */ + smb_panic(__location__); + break; + } + num_not_cached += 1; } + /* + * Third and final time through the SID array, + * try legacy_sid_to_gid()/legacy_sid_to_uid() + * for entries we haven't already been able to + * map. + * + * Use bitmap_set() to mark an ids[] array entry as + * being mapped. + */ + for (i=0; i Date: Thu, 24 Nov 2016 09:12:59 +0100 Subject: [PATCH 049/142] 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 6ee4929e8d7..a0a1f4baa56 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -620,6 +620,8 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se struct composite_context *c; struct sesssetup_state *state; NTSTATUS status; + 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; @@ -635,6 +637,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_MUST_USE_KERBEROS) { + composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); + return c; + } ZERO_STRUCT(io->out); composite_done(c); return c; @@ -642,9 +648,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_MUST_USE_KERBEROS) { + 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_MUST_USE_KERBEROS) { + 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.39.0 From 41cc796909aeade44c4f1e88923936ba4444278e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Oct 2016 10:40:28 +0200 Subject: [PATCH 050/142] 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 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 9bba2665663..9a69d4b7217 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -1455,6 +1455,13 @@ struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx, return req; } + if (krb5_state == CRED_MUST_USE_KERBEROS) { + 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.39.0 From 3c1688714ea93cdb7c3088b8a5e5da3025e43b42 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sat, 18 Jan 2020 08:06:45 +0100 Subject: [PATCH 051/142] s3/auth: use set_current_user_info() in auth3_generate_session_info_pac() This delays reloading config slightly, but I don't see how could affect observable behaviour other then log messages coming from the functions in between the different locations for lp_load_with_shares() like make_session_info_krb5() are sent to a different logfile if "log file" uses %U. Signed-off-by: Ralph Boehme Reviewed-by: Andreas Schneider (cherry picked from commit dc4b1e39ce1f2201a2d6ae2d4cffef2448f69a62) [scabrero@samba.org Prerequisite for CVE-2020-25717 backport] --- source3/auth/auth_generic.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c index 167d4e00367..0e9c423efef 100644 --- a/source3/auth/auth_generic.c +++ b/source3/auth/auth_generic.c @@ -159,12 +159,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, } } - /* setup the string used by %U */ - sub_set_smb_name(username); - - /* reload services so that the new %U is taken into account */ - lp_load_with_shares(get_dyn_CONFIGFILE()); - 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 */, @@ -176,6 +170,14 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, goto done; } + /* setup the string used by %U */ + set_current_user_info((*session_info)->unix_info->sanitized_username, + (*session_info)->unix_info->unix_name, + (*session_info)->info->domain_name); + + /* reload services so that the new %U is taken into account */ + lp_load_with_shares(get_dyn_CONFIGFILE()); + DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n", ntuser, ntdomain, rhost)); -- 2.39.0 From cf43f0a90b3025077479d37ad905fe730695e739 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 4 Nov 2021 11:51:08 +0100 Subject: [PATCH 052/142] selftest: Fix ktest usermap file The user was not mapped: user_in_list: checking user |KTEST/administrator| against |KTEST\Administrator| The user 'KTEST/administrator' has no mapping. Skip it next time. Signed-off-by: Samuel Cabrero [scabrero@samba.org Once smb_getpswnam() fallbacks are removed the user has to be mapped] --- selftest/target/Samba3.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 9e4da0e6a08..2eb5003112e 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1124,7 +1124,7 @@ sub setup_ktest open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map"); print USERMAP " -$ret->{USERNAME} = KTEST\\Administrator +$ret->{USERNAME} = KTEST/Administrator "; close(USERMAP); -- 2.39.0 From 703f43ea7817fa0ab423134a4c40bf9c37f90274 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Oct 2021 16:42:00 +0200 Subject: [PATCH 053/142] 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) (cherry picked from commit 89b9cb8b786c3e4eb8691b5363390b68d8228a2d) [scabrero@samba.org Backported to 4.10] --- selftest/target/Samba3.pm | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 2eb5003112e..bbbefea44b7 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1333,7 +1333,7 @@ sub check_or_start($$$$$) { $ENV{ENVNAME} = "$ENV{ENVNAME}.winbindd"; - if ($winbindd ne "yes") { + if ($winbindd ne "yes" and $winbindd ne "offline") { $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub { my $signame = shift; print("Skip winbindd received signal $signame"); @@ -2564,13 +2564,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 { if ($ret != 0) { -- 2.39.0 From eadbcf608a98c8ff90b2d5d91b61fc8100d2cc71 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Oct 2021 16:20:36 +0200 Subject: [PATCH 054/142] CVE-2020-25719 CVE-2020-25717: selftest: remove "gensec:require_pac" settings 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 --- selftest/selftest.pl | 2 -- selftest/target/Samba4.pm | 2 -- 2 files changed, 4 deletions(-) diff --git a/selftest/selftest.pl b/selftest/selftest.pl index f2968139cfd..8c273951ab3 100755 --- a/selftest/selftest.pl +++ b/selftest/selftest.pl @@ -637,8 +637,6 @@ sub write_clientconf($$$) client lanman auth = Yes log level = 1 torture:basedir = $clientdir -#We don't want to pass our self-tests if the PAC code is wrong - gensec:require_pac = true #We don't want to run 'speed' tests for very long torture:timelimit = 1 winbind separator = / diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index a7a6c4c9587..0f644661176 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -777,8 +777,6 @@ sub provision_raw_step1($$) notify:inotify = false ldb:nosync = true ldap server require strong auth = yes -#We don't want to pass our self-tests if the PAC code is wrong - gensec:require_pac = true log file = $ctx->{logdir}/log.\%m log level = $ctx->{server_loglevel} lanman auth = Yes -- 2.39.0 From 628493ea5f0cda3851ab13a41b8018daa228132b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Oct 2021 17:29:34 +0200 Subject: [PATCH 055/142] 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 [scabrero@samba.org Backported for 4.10 due to no logon_id for log_authentication() neither is_allowed_domain()] --- source3/winbindd/winbindd_dual_srv.c | 7 +++++++ source3/winbindd/winbindd_irpc.c | 7 +++++++ source3/winbindd/winbindd_pam.c | 13 ++++++++++--- source3/winbindd/winbindd_pam_auth_crap.c | 9 ++++++++- source3/winbindd/winbindd_util.c | 7 +++++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index ab14f5d51a0..0842241e02e 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -928,6 +928,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 8cbb0b93086..45615c2dc47 100644 --- a/source3/winbindd/winbindd_irpc.c +++ b/source3/winbindd/winbindd_irpc.c @@ -143,6 +143,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 35018fbe284..deed81d0a79 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1703,7 +1703,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( unsigned char local_nt_response[24]; 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; union netr_Validation *validation = NULL; @@ -2238,6 +2238,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", @@ -2420,7 +2427,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, const char *name_user = NULL; const char *name_domain = NULL; const char *workstation; - uint8_t authoritative = 0; + uint8_t authoritative = 1; uint32_t flags = 0; uint16_t validation_level; union netr_Validation *validation = NULL; @@ -2482,7 +2489,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; } @@ -2526,6 +2532,7 @@ done: } set_auth_errors(state->response, result); + state->response->data.auth.authoritative = authoritative; return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c index b7912db43df..40cab81b5ea 100644 --- a/source3/winbindd/winbindd_pam_auth_crap.c +++ b/source3/winbindd/winbindd_pam_auth_crap.c @@ -24,6 +24,7 @@ struct winbindd_pam_auth_crap_state { struct winbindd_response *response; + bool authoritative; uint32_t flags; }; @@ -45,7 +46,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) { @@ -124,6 +125,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); } @@ -184,6 +190,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 3245c70bb8e..315eb366a52 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -2062,6 +2062,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.39.0 From fc3b3940208c2f03ea3aeb4b6f7e609fa9f90648 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Oct 2021 17:29:34 +0200 Subject: [PATCH 056/142] 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 --- 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 3a3fa7eaa59..f754bd5cd44 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.39.0 From ecd3a8af56dcd1aad43999a253175aa04b298eef Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 057/142] 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 --- 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 e689dfd5e98..957cb410712 100644 --- a/source4/torture/rpc/samlogon.c +++ b/source4/torture/rpc/samlogon.c @@ -1385,7 +1385,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); @@ -1498,7 +1498,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 c237c82bbe7..72d0bf28fdd 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.39.0 From 3feb493c3dd5383712a41729ed6f770695acb8b7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 058/142] 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 --- 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 13f13934412..5e817eecd4b 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.39.0 From e1a1787d1d3b64adc743eab4f626068b438d0e5c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 059/142] 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 --- 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 fcd9050979d..da8f094a838 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.39.0 From e09409714301455ba7bbed1d80a9c90c05257aaf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 060/142] 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 --- 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 36c32e4a3dc..3f70732a837 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1766,7 +1766,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()); @@ -2235,7 +2235,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.39.0 From 26570ee2e981cc5d44eeeed020a051a4771470fe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 061/142] 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 [scabrero@samba.org Backported to 4.10 due to missing commit a5548af018643f2e78c482e33ef0e6073db149e4 to check return value of SMBOWFencrypt()] --- 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 64bc45e6a7c..48190e78bf8 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; SMBOWFencrypt(pdb_get_nt_passwd(pdb_entry), challenge_8, local_nt_response); -- 2.39.0 From 36af26aac042ce48ae912d0ab7ce398280d81c93 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 062/142] 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 --- 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 631740562c6..30fa1ed7816 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.39.0 From 8eec50d65a10baa4e282c4a833c3cb202cd33255 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 063/142] 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 [scabrero@samba.org Backported to 4.10 due to missing commits 7f75dec865256049e99f7fcf46317cd2d53e95d1 and 434030ba711e677fdd167a255d05c1cd4db943b7] --- 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 0e9c423efef..4ef2270cb34 100644 --- a/source3/auth/auth_generic.c +++ b/source3/auth/auth_generic.c @@ -415,7 +415,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; if (auth_context->check_ntlm_password_send != NULL) { struct tevent_context *ev = NULL; diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c index a71c75631d7..bf7ccb4348c 100644 --- a/source3/auth/auth_samba4.c +++ b/source3/auth/auth_samba4.c @@ -118,7 +118,7 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, NTSTATUS nt_status; struct auth_user_info_dc *user_info_dc; struct auth4_context *auth4_context; - uint8_t authoritative = 0; + uint8_t authoritative = 1; nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context); if (!NT_STATUS_IS_OK(nt_status)) { -- 2.39.0 From 46bc67c24c83940ef56cfa5dbbdb8544c290f200 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Oct 2021 17:42:41 +0200 Subject: [PATCH 064/142] 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 --- 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 140e89daeb1..eebada670be 100644 --- a/auth/ntlmssp/ntlmssp_server.c +++ b/auth/ntlmssp/ntlmssp_server.c @@ -830,7 +830,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.39.0 From 986642f066c3fdf187a8799898196a23cb9d532c Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Tue, 28 Sep 2021 10:43:40 +0200 Subject: [PATCH 065/142] 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 4c3dfff24f3..4aa91f4d404 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -3015,6 +3015,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter( lp_ctx, "ldap max search request size", "256000"); + 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 0db44e92d19..57d1d909099 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -963,6 +963,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.ldap_max_authenticated_request_size = 16777216; Globals.ldap_max_search_request_size = 256000; + Globals.min_domain_uid = 1000; + /* Now put back the settings that were set with lp_set_cmdline() */ apply_lp_set_cmdline(); } -- 2.39.0 From 16fa6601a3517c723e90dfb8b1a086df2616e668 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 19:57:18 +0200 Subject: [PATCH 066/142] 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 --- 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 4ef2270cb34..26a38f92b30 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.39.0 From 10a4bdbe4a16fec1bd9b212736a9d26500e0981e Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Tue, 28 Sep 2021 10:45:11 +0200 Subject: [PATCH 067/142] 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 --- 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 8ff20c33759..8801d3f0f0b 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -2078,6 +2078,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.39.0 From 58bea3837cfbeba5cd5c56060a42117fffedbda4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 17:40:30 +0200 Subject: [PATCH 068/142] 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 --- 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.39.0 From e78afbcff415d78cb29b65204fefeb0355d6651e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 18:08:20 +0200 Subject: [PATCH 069/142] 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 --- 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 8801d3f0f0b..6ee500493e6 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1873,7 +1873,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.39.0 From a3ffab81c235aae479262cca73cf4361f76f7f9d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 8 Oct 2021 12:33:16 +0200 Subject: [PATCH 070/142] 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 --- source3/auth/auth_util.c | 77 ++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 6ee500493e6..161e05c2106 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1908,7 +1908,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 */ @@ -1927,48 +1927,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.39.0 From 9a1bb168388205f5a2bfa459a5da63c5046eaa7a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Oct 2021 18:03:55 +0200 Subject: [PATCH 071/142] 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 --- 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 161e05c2106..c0e5cfd7fa8 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -551,13 +551,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.39.0 From bbe5c6693ba6954dab5bfef9f8c3778164cd879e Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Wed, 11 Nov 2020 18:50:45 +0200 Subject: [PATCH 072/142] 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 [abartlet@samba.org Backported due to conflict with DEBUG statements and IPA branding changes in comments] --- 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 | 2 ++ source3/include/smb_macros.h | 2 +- source3/lib/netapi/joindomain.c | 1 + source3/param/loadparm.c | 4 ++- source3/passdb/lookup_sid.c | 1 - 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, 65 insertions(+), 19 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 f9d3b55adf2..aed205d1944 100644 --- a/lib/param/param_table.c +++ b/lib/param/param_table.c @@ -100,6 +100,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 58a331d70ad..838bdf84c87 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 0a96d591808..c5bfe9ac626 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -529,6 +529,7 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx, break; case ROLE_DOMAIN_BDC: case ROLE_DOMAIN_PDC: + case ROLE_IPA_DC: DEBUG(5,("Making default auth method list for DC\n")); methods = "anonymous sam winbind sam_ignoredomain"; break; @@ -557,6 +558,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; @@ -578,6 +580,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 f9764d87e3c..d0b29083d46 100644 --- a/source3/auth/auth_sam.c +++ b/source3/auth/auth_sam.c @@ -139,6 +139,7 @@ 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 ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", effective_domain)); @@ -209,6 +210,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"); diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 06d24744960..346401510c2 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -213,7 +213,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 8d0752f4531..0344c0e0416 100644 --- a/source3/lib/netapi/joindomain.c +++ b/source3/lib/netapi/joindomain.c @@ -369,6 +369,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 57d1d909099..98e05d13d59 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -4321,6 +4321,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: @@ -4346,7 +4347,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 186ba17fda6..839da5cfbf4 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -117,7 +117,6 @@ bool lookup_name(TALLOC_CTX *mem_ctx, if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) && strequal(domain, get_global_sam_name())) { - /* It's our own domain, lookup the name in passdb */ if (lookup_global_sam_name(name, flags, &rid, &type)) { sid_compose(&sid, get_global_sam_sid(), rid); diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c index dfc21f295a1..b60cf56c490 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 7e3efa8504e..aa896e15ac4 100644 --- a/source3/rpc_server/dssetup/srv_dssetup_nt.c +++ b/source3/rpc_server/dssetup/srv_dssetup_nt.c @@ -62,6 +62,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 7d96a5762ec..d263507b22f 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -1969,7 +1969,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 cc0701e597a..f09b029fd13 100644 --- a/source3/winbindd/winbindd_misc.c +++ b/source3/winbindd/winbindd_misc.c @@ -75,7 +75,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 315eb366a52..04e79e70f6b 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -1225,15 +1225,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 f754bd5cd44..7dab02b5c4d 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -773,6 +773,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 b5de5a790d4..49aa560470c 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 51fed4da62b..1f09b721408 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -568,6 +568,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: @@ -675,6 +676,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.39.0 From 3a8b4d3b410508dfb0538376046a5b38c53f9568 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Oct 2021 18:11:57 +0200 Subject: [PATCH 073/142] 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 --- 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.39.0 From 15cca0f7ee6f4b8d96b6b650b2d009b030a2bc5f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Oct 2021 23:17:19 +0200 Subject: [PATCH 074/142] 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 [abartlet@samba.org Backported from master/4.15 as check_password is sync in 4.14] --- 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 51895c9259f..f16d0649de2 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -73,14 +73,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 7dab02b5c4d..2765fd1b13c 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) @@ -663,8 +621,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 fb88cb87f66..a8c7d8b4b85 100644 --- a/source4/auth/ntlm/auth_sam.c +++ b/source4/auth/ntlm/auth_sam.c @@ -854,28 +854,16 @@ 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 = authsam_check_password_internals, - .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, - .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, }; _PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *); -- 2.39.0 From ec14a33f17e638870c997b56d4b5ce9096cbb27a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 21 Sep 2021 12:27:28 +0200 Subject: [PATCH 075/142] 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 --- 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 3f70732a837..fefdd32bf11 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -827,23 +827,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; } } @@ -851,7 +855,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 { @@ -881,7 +886,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.39.0 From 9e036a77eca721c4ea23c3f629d9e504d5780f79 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 21 Sep 2021 12:44:01 +0200 Subject: [PATCH 076/142] 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 --- 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 fefdd32bf11..ff2fd30a9ae 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -799,10 +799,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) { @@ -819,79 +817,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.39.0 From 4c01fd62e30b8e1137e7de01ecb41c94550dac24 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Oct 2021 19:42:20 +0200 Subject: [PATCH 077/142] 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 [abartlet@samba.org Backported due to change in structure initialization with { 0 } to zero ] [abartlet@samba.org backported to 4.12 due to conflict with code not present to reload shared on krb5 login] --- source3/auth/auth_generic.c | 139 ++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 29 deletions(-) diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c index 26a38f92b30..3099e8f9057 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 - struct wbcAuthUserParams params = {}; + 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.39.0 From 2d7cd152d95e091447731b3699be9654ca13cffc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Oct 2021 17:14:01 +0200 Subject: [PATCH 078/142] 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 [scabrero@samba.org Backported to 4.11 Run winbindd in offline mode but keep the user name mapping to avoid having to backport fixes for bso#14539] --- selftest/target/Samba3.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index bbbefea44b7..7034127ef0b 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1176,7 +1176,7 @@ $ret->{USERNAME} = KTEST/Administrator # access the share for tests. chmod 0777, "$prefix/share"; - if (not $self->check_or_start($ret, "yes", "no", "yes")) { + if (not $self->check_or_start($ret, "yes", "offline", "yes")) { return undef; } return $ret; -- 2.39.0 From 6b4c3693d4ae3c54fd4c890b71829ac582436dee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Oct 2021 18:12:49 +0200 Subject: [PATCH 079/142] 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 [abartlet@samba.org Backported to Samba 4.12 has conflcits as the share reload code is in a different spot] --- 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 3099e8f9057..23f746c078e 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.39.0 From 6f6a1fedb97d119a7f15831f7295b1774e806ba8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 17:59:59 +0200 Subject: [PATCH 080/142] 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 --- 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 23f746c078e..a11aae713f5 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 fcfd1f36ca2..1ed3f4a2f77 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -416,7 +416,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.39.0 From 8fd8d952c4396484f822c51f71667baaf49402b4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Oct 2021 18:03:04 +0200 Subject: [PATCH 081/142] 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 --- 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 a11aae713f5..4dd1af784bf 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 1ed3f4a2f77..c00ac70fd3f 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -427,9 +427,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.39.0 From bf0696ec4f3080ebd0b61cac5a05a9284ccabda8 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:39:19 +1200 Subject: [PATCH 082/142] 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 f27e7243ee4..711b7f94b6c 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.39.0 From 7a9f618fdbf32872594f47dd4bc83ce087af4bbc Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 1 Sep 2021 15:40:59 +1200 Subject: [PATCH 083/142] 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 5930f448955..e6065a35691 100644 --- a/librpc/idl/security.idl +++ b/librpc/idl/security.idl @@ -292,6 +292,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.39.0 From 7713b56a8a8b26e05aa9a517348e3f95da1144a7 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 29 Sep 2021 16:15:26 +1300 Subject: [PATCH 084/142] 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 711b7f94b6c..141894ec5f1 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.39.0 From a85bf1d86d6e081c781cc93a8e7aaa049c3818d0 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 26 Oct 2021 20:33:38 +1300 Subject: [PATCH 085/142] 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 141894ec5f1..4bfec2de5e6 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.39.0 From 57e4c415ecae66ee984a30eb66d5d248e0e8587d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 26 Oct 2021 20:33:49 +1300 Subject: [PATCH 086/142] 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 4bfec2de5e6..f750359a069 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.39.0 From 7782a97868ead29b6e87fa98dcef8dbc2706b67d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 27 Sep 2021 11:20:19 +1300 Subject: [PATCH 087/142] 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 f750359a069..94b9160d6eb 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.39.0 From 44e8dd1a9a3c02dee31497fe20411758fce1acf9 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 12 Nov 2021 19:06:01 +0200 Subject: [PATCH 088/142] 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 71e9afdf48e..f23c1effb23 100644 --- a/auth/gensec/schannel.c +++ b/auth/gensec/schannel.c @@ -740,6 +740,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 57bfc596005..3f77856457e 100644 --- a/source3/rpc_server/lsa/srv_lsa_nt.c +++ b/source3/rpc_server/lsa/srv_lsa_nt.c @@ -672,6 +672,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.39.0 From c64bcd68614871cdddc9fe37c860729f490b4da1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 12 Nov 2021 15:27:58 +0100 Subject: [PATCH 089/142] CVE-2020-25717: idmap_nss: verify that the name of the sid belongs to the configured domain We already check the sid belongs to the domain, but checking the name too feels better and make it easier to understand. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme [abartlet@samba.org backorted from commit bfd093648b4af51d104096c0cb3535e8706671e5 as header libcli/security/dom_sid.h was not present for struct dom_sid_buf] [abartlet@samba.org fix CVE marker] --- source3/winbindd/idmap_nss.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c index 3fe98cbc729..243b67ccafd 100644 --- a/source3/winbindd/idmap_nss.c +++ b/source3/winbindd/idmap_nss.c @@ -25,6 +25,7 @@ #include "nsswitch/winbind_client.h" #include "idmap.h" #include "lib/winbind_util.h" +#include "libcli/security/dom_sid.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP @@ -135,18 +136,21 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma for (i = 0; ids[i]; i++) { struct group *gr; enum lsa_SidType type; - const char *p = NULL; + const char *_domain = NULL; + const char *_name = NULL; + char *domain = NULL; char *name = NULL; bool ret; /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ (void)winbind_on(); - ret = winbind_lookup_sid(talloc_tos(), ids[i]->sid, NULL, - &p, &type); + ret = winbind_lookup_sid(talloc_tos(), + ids[i]->sid, + &_domain, + &_name, + &type); (void)winbind_off(); - name = discard_const_p(char, p); - if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ @@ -154,6 +158,18 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma continue; } + domain = discard_const_p(char, _domain); + name = discard_const_p(char, _name); + + if (!strequal(domain, dom->name)) { + struct dom_sid_buf buf; + DBG_ERR("DOMAIN[%s] ignoring SID[%s] belongs to %s [%s\\%s]\n", + dom->name, dom_sid_str_buf(ids[i]->sid, &buf), + sid_type_lookup(type), domain, name); + ids[i]->status = ID_UNMAPPED; + continue; + } + switch (type) { case SID_NAME_USER: { struct passwd *pw; @@ -186,6 +202,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma ids[i]->status = ID_UNKNOWN; break; } + TALLOC_FREE(domain); TALLOC_FREE(name); } return NT_STATUS_OK; -- 2.39.0 From c7d277ef2c902482eca00fc981bf340a088fbfe1 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 12 Nov 2021 20:53:30 +1300 Subject: [PATCH 090/142] CVE-2020-25717: nsswitch/nsstest.c: Lower 'non existent uid' to make room for new accounts BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit fdbee5e074ebd76d659613b8b7114d70f938c38a) --- nsswitch/nsstest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsswitch/nsstest.c b/nsswitch/nsstest.c index 46f96795f39..8ce7493d1b6 100644 --- a/nsswitch/nsstest.c +++ b/nsswitch/nsstest.c @@ -460,7 +460,7 @@ static void nss_test_errors(void) printf("ERROR Non existent user gave error %d\n", last_error); } - pwd = getpwuid(0xFFF0); + pwd = getpwuid(0xFF00); if (pwd || last_error != NSS_STATUS_NOTFOUND) { total_errors++; printf("ERROR Non existent uid gave error %d\n", last_error); -- 2.39.0 From 0ff9bba35a043267a2781c294f5832378cd6da54 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 12 Nov 2021 16:10:31 +1300 Subject: [PATCH 091/142] CVE-2020-25717: s3:auth: Fallback to a SID/UID based mapping if the named based lookup fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the CVE-2020-25717 fixes we had a fallback from getpwnam('DOMAIN\user') to getpwnam('user') which was very dangerous and unpredictable. Now we do the fallback based on sid_to_uid() followed by getpwuid() on the returned uid. This obsoletes 'username map [script]' based workaround adviced for CVE-2020-25717, when nss_winbindd is not used or idmap_nss is actually used. In future we may decide to prefer or only do the SID/UID based lookup, but for now we want to keep this unchanged as much as possible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Andrew Bartlett Signed-off-by: Stefan Metzmacher [metze@samba.org moved the new logic into the fallback codepath only in order to avoid behavior changes as much as possible] Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Nov 15 19:01:56 UTC 2021 on sn-devel-184 [abartlet@samba.org backported from commit 0a546be05295a7e4a552f9f4f0c74aeb2e9a0d6e as usage.py is not present in Samba 4.10] --- source3/auth/auth_util.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index c0e5cfd7fa8..b463059f259 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1837,7 +1837,9 @@ const struct auth_session_info *get_session_info_system(void) ***************************************************************************/ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, - const char *username, char **found_username, + const char *username, + const struct dom_sid *sid, + char **found_username, struct passwd **pwd, bool *username_was_mapped) { @@ -1872,6 +1874,31 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, } passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false); + if (!passwd && !*username_was_mapped) { + struct dom_sid_buf buf; + uid_t uid; + bool ok; + + DBG_DEBUG("Failed to find authenticated user %s via " + "getpwnam(), fallback to sid_to_uid(%s).\n", + dom_user, dom_sid_str_buf(sid, &buf)); + + ok = sid_to_uid(sid, &uid); + if (!ok) { + DBG_ERR("Failed to convert SID %s to a UID (dom_user[%s])\n", + dom_sid_str_buf(sid, &buf), dom_user); + return NT_STATUS_NO_SUCH_USER; + } + passwd = getpwuid_alloc(mem_ctx, uid); + if (!passwd) { + DBG_ERR("Failed to find local account with UID %lld for SID %s (dom_user[%s])\n", + (long long)uid, + dom_sid_str_buf(sid, &buf), + dom_user); + return NT_STATUS_NO_SUCH_USER; + } + real_username = talloc_strdup(mem_ctx, passwd->pw_name); + } if (!passwd) { DEBUG(3, ("Failed to find authenticated user %s via " "getpwnam(), denying access.\n", dom_user)); @@ -2017,6 +2044,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, bool username_was_mapped; struct passwd *pwd; struct auth_serversupplied_info *result; + struct dom_sid sid; TALLOC_CTX *tmp_ctx = talloc_stackframe(); /* @@ -2063,9 +2091,13 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, /* this call will try to create the user if necessary */ + sid_copy(&sid, info3->base.domain_sid); + sid_append_rid(&sid, info3->base.rid); + nt_status = check_account(tmp_ctx, nt_domain, nt_username, + &sid, &found_username, &pwd, &username_was_mapped); -- 2.39.0 From f035c041e42594bacfe7c3f4e5ea5d05399e1c5a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 26 Nov 2021 10:57:17 +0100 Subject: [PATCH 092/142] CVE-2020-25717: s3-auth: fix MIT Realm regression This looks like a regression introduced by the recent security fixes. This commit should hopefully fixes it. As a quick solution it might be possible to use the username map script based on the example in https://bugzilla.samba.org/show_bug.cgi?id=14901#c0. We're not sure this behaves identical, but it might work in the standalone server case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14922 Reported-at: https://lists.samba.org/archive/samba/2021-November/238720.html Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Ralph Boehme Signed-off-by: Stefan Metzmacher (cherry picked from commit 1e61de8306604a0d3858342df8a1d2412d8d418b) --- source3/auth/user_krb5.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c index b8f37cbeee0..169bf563368 100644 --- a/source3/auth/user_krb5.c +++ b/source3/auth/user_krb5.c @@ -46,6 +46,7 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, char *fuser = NULL; char *unixuser = NULL; struct passwd *pw = NULL; + bool may_retry = false; DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); @@ -71,6 +72,7 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, domain = realm; } else { domain = lp_workgroup(); + may_retry = true; } fuser = talloc_asprintf(mem_ctx, @@ -89,6 +91,13 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, *mapped_to_guest = false; pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); + if (may_retry && pw == NULL && !*is_mapped) { + fuser = talloc_strdup(mem_ctx, user); + if (!fuser) { + return NT_STATUS_NO_MEMORY; + } + pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); + } if (pw) { if (!unixuser) { return NT_STATUS_NO_MEMORY; -- 2.39.0 From 8b8d1b20b16381c305c23ce03a559b8c7de67f5d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 13 Jan 2022 16:48:01 +0100 Subject: [PATCH 093/142] CVE-2021-44142: libadouble: add defines for icon lengths From https://www.ietf.org/rfc/rfc1740.txt BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914 Signed-off-by: Ralph Boehme --- source3/modules/vfs_fruit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index afad70ce180..3a35620bfe4 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -283,6 +283,8 @@ typedef enum {ADOUBLE_META, ADOUBLE_RSRC} adouble_type_t; #define ADEDLEN_MACFILEI 4 #define ADEDLEN_PRODOSFILEI 8 #define ADEDLEN_MSDOSFILEI 2 +#define ADEDLEN_ICONBW 128 +#define ADEDLEN_ICONCOL 1024 #define ADEDLEN_DID 4 #define ADEDLEN_PRIVDEV 8 #define ADEDLEN_PRIVINO 8 -- 2.39.0 From 3f2e9a6de36c086cff0bb3296f00c85a37a2653c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sat, 20 Nov 2021 16:36:42 +0100 Subject: [PATCH 094/142] CVE-2021-44142: smbd: add Netatalk xattr used by vfs_fruit to the list of private Samba xattrs This is an internal xattr that should not be user visible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914 Signed-off-by: Ralph Boehme [slow@samba.org: conflict due to changed includes in source3/smbd/trans2.c] --- source3/smbd/trans2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f8d987bbe63..406087c0419 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -176,6 +176,16 @@ void aapl_force_zero_file_id(struct smbd_server_connection *sconn) Refuse to allow clients to overwrite our private xattrs. ****************************************************************************/ +/* + * Taken from vfs_fruit.c + */ +#define NETATALK_META_XATTR "org.netatalk.Metadata" +#if defined(HAVE_ATTROPEN) +#define AFPINFO_EA_NETATALK NETATALK_META_XATTR +#else +#define AFPINFO_EA_NETATALK "user." NETATALK_META_XATTR +#endif + bool samba_private_attr_name(const char *unix_ea_name) { static const char * const prohibited_ea_names[] = { @@ -183,6 +193,7 @@ bool samba_private_attr_name(const char *unix_ea_name) SAMBA_XATTR_DOS_ATTRIB, SAMBA_XATTR_MARKER, XATTR_NTACL_NAME, + AFPINFO_EA_NETATALK, NULL }; -- 2.39.0 From 00287584703e9e91e804e0f182bd844b7c436716 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 26 Nov 2021 07:19:32 +0100 Subject: [PATCH 095/142] CVE-2021-44142: libadouble: harden ad_unpack_xattrs() This ensures ad_unpack_xattrs() is only called for an ad_type of ADOUBLE_RSRC, which is used for parsing ._ AppleDouble sidecar files, and the buffer ad->ad_data is AD_XATTR_MAX_HDR_SIZE bytes large which is a prerequisite for all buffer out-of-bounds access checks in ad_unpack_xattrs(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914 Signed-off-by: Ralph Boehme --- source3/modules/vfs_fruit.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 3a35620bfe4..76139e51047 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -728,14 +728,27 @@ static bool ad_pack(struct adouble *ad) static bool ad_unpack_xattrs(struct adouble *ad) { struct ad_xattr_header *h = &ad->adx_header; + size_t bufsize = talloc_get_size(ad->ad_data); const char *p = ad->ad_data; uint32_t hoff; uint32_t i; + if (ad->ad_type != ADOUBLE_RSRC) { + return false; + } + if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) { return true; } + /* + * Ensure the buffer ad->ad_data was allocated by ad_alloc() for an + * ADOUBLE_RSRC type (._ AppleDouble file on-disk). + */ + if (bufsize != AD_XATTR_MAX_HDR_SIZE) { + return false; + } + /* 2 bytes padding */ hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2; @@ -985,11 +998,12 @@ static bool ad_unpack(struct adouble *ad, const size_t nentries, ad->ad_eid[eid].ade_len = len; } - ok = ad_unpack_xattrs(ad); - if (!ok) { - return false; + if (ad->ad_type == ADOUBLE_RSRC) { + ok = ad_unpack_xattrs(ad); + if (!ok) { + return false; + } } - return true; } -- 2.39.0 From 94141fa38e082e4ab50be6c2f79c8506e72bc274 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 25 Nov 2021 15:04:03 +0100 Subject: [PATCH 096/142] CVE-2021-44142: libadouble: add basic cmocka tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914 Signed-off-by: Ralph Boehme [slow@samba.org: conflict due to missing test in selftest/tests.py] --- selftest/knownfail.d/samba.unittests.adouble | 3 + selftest/tests.py | 2 + source3/lib/test_adouble.c | 393 +++++++++++++++++++ source3/wscript_build | 5 + 4 files changed, 403 insertions(+) create mode 100644 selftest/knownfail.d/samba.unittests.adouble create mode 100644 source3/lib/test_adouble.c diff --git a/selftest/knownfail.d/samba.unittests.adouble b/selftest/knownfail.d/samba.unittests.adouble new file mode 100644 index 00000000000..8b0314f2fae --- /dev/null +++ b/selftest/knownfail.d/samba.unittests.adouble @@ -0,0 +1,3 @@ +^samba.unittests.adouble.parse_abouble_finderinfo2\(none\) +^samba.unittests.adouble.parse_abouble_finderinfo3\(none\) +^samba.unittests.adouble.parse_abouble_date2\(none\) diff --git a/selftest/tests.py b/selftest/tests.py index e3f7d9acb4a..4bc4d301c4c 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -260,3 +260,5 @@ plantestsuite("samba.unittests.ntlm_check", "none", [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")]) plantestsuite("samba.unittests.test_registry_regfio", "none", [os.path.join(bindir(), "default/source3/test_registry_regfio")]) +plantestsuite("samba.unittests.adouble", "none", + [os.path.join(bindir(), "test_adouble")]) diff --git a/source3/lib/test_adouble.c b/source3/lib/test_adouble.c new file mode 100644 index 00000000000..667d2a7542e --- /dev/null +++ b/source3/lib/test_adouble.c @@ -0,0 +1,393 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) 2021 Ralph Boehme + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General 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 "includes.h" +extern NTSTATUS vfs_fruit_init(TALLOC_CTX *mem_ctx); + +#include "vfs_fruit.c" +#include + + +static int setup_talloc_context(void **state) +{ + TALLOC_CTX *frame = talloc_stackframe(); + + *state = frame; + return 0; +} + +static int teardown_talloc_context(void **state) +{ + TALLOC_CTX *frame = *state; + + TALLOC_FREE(frame); + return 0; +} + +/* + * Basic and sane buffer. + */ +static uint8_t ad_basic[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x32, /* offset */ + 0x00, 0x00, 0x00, 0x20, /* length */ + /* adentry 2: Resourcefork */ + 0x00, 0x00, 0x00, 0x02, /* eid: Resourcefork */ + 0x00, 0x00, 0x00, 0x52, /* offset */ + 0xff, 0xff, 0xff, 0x00, /* length */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * An empty FinderInfo entry. + */ +static uint8_t ad_finderinfo1[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x52, /* off: points at end of buffer */ + 0x00, 0x00, 0x00, 0x00, /* len: 0, so off+len don't exceed bufferlen */ + /* adentry 2: Resourcefork */ + 0x00, 0x00, 0x00, 0x02, /* eid: Resourcefork */ + 0x00, 0x00, 0x00, 0x52, /* offset */ + 0xff, 0xff, 0xff, 0x00, /* length */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * A dangerous FinderInfo with correct length exceeding buffer by one byte. + */ +static uint8_t ad_finderinfo2[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x33, /* off: points at beginng of data + 1 */ + 0x00, 0x00, 0x00, 0x20, /* len: 32, so off+len exceeds bufferlen by 1 */ + /* adentry 2: Resourcefork */ + 0x00, 0x00, 0x00, 0x02, /* eid: Resourcefork */ + 0x00, 0x00, 0x00, 0x52, /* offset */ + 0xff, 0xff, 0xff, 0x00, /* length */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static uint8_t ad_finderinfo3[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x33, /* off: points at beginng of data + 1 */ + 0x00, 0x00, 0x00, 0x1f, /* len: 31, so off+len don't exceed buf */ + /* adentry 2: Resourcefork */ + 0x00, 0x00, 0x00, 0x02, /* eid: Resourcefork */ + 0x00, 0x00, 0x00, 0x52, /* offset */ + 0xff, 0xff, 0xff, 0x00, /* length */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * A dangerous name entry. + */ +static uint8_t ad_name[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x32, /* offset */ + 0x00, 0x00, 0x00, 0x20, /* length */ + /* adentry 2: Name */ + 0x00, 0x00, 0x00, 0x03, /* eid: Name */ + 0x00, 0x00, 0x00, 0x52, /* off: points at end of buffer */ + 0x00, 0x00, 0x00, 0x01, /* len: 1, so off+len exceeds bufferlen */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * A empty ADEID_FILEDATESI entry. + */ +static uint8_t ad_date1[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x32, /* offset */ + 0x00, 0x00, 0x00, 0x20, /* length */ + /* adentry 2: Dates */ + 0x00, 0x00, 0x00, 0x08, /* eid: dates */ + 0x00, 0x00, 0x00, 0x52, /* off: end of buffer */ + 0x00, 0x00, 0x00, 0x00, /* len: 0, empty entry, valid */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +/* + * A dangerous ADEID_FILEDATESI entry, invalid length. + */ +static uint8_t ad_date2[] = { + 0x00, 0x05, 0x16, 0x07, /* Magic */ + 0x00, 0x02, 0x00, 0x00, /* Version */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x00, 0x00, 0x00, /* Filler */ + 0x00, 0x02, /* Count */ + /* adentry 1: FinderInfo */ + 0x00, 0x00, 0x00, 0x09, /* eid: FinderInfo */ + 0x00, 0x00, 0x00, 0x32, /* offset */ + 0x00, 0x00, 0x00, 0x20, /* length */ + /* adentry 2: Dates */ + 0x00, 0x00, 0x00, 0x08, /* eid: dates */ + 0x00, 0x00, 0x00, 0x43, /* off: FinderInfo buf but one byte short */ + 0x00, 0x00, 0x00, 0x0f, /* len: 15, so off+len don't exceed bufferlen */ + /* FinderInfo data: 32 bytes */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static struct adouble *parse_adouble(TALLOC_CTX *mem_ctx, + uint8_t *adbuf, + size_t adsize, + off_t filesize) +{ + struct adouble *ad = NULL; + bool ok; + + ad = talloc_zero(mem_ctx, struct adouble); + ad->ad_data = talloc_zero_size(ad, adsize); + assert_non_null(ad); + + memcpy(ad->ad_data, adbuf, adsize); + + ok = ad_unpack(ad, 2, filesize); + if (!ok) { + return NULL; + } + + return ad; +} + +static void parse_abouble_basic(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + char *p = NULL; + + ad = parse_adouble(frame, ad_basic, sizeof(ad_basic), 0xffffff52); + assert_non_null(ad); + + p = ad_get_entry(ad, ADEID_FINDERI); + assert_non_null(p); + + return; +} + +static void parse_abouble_finderinfo1(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + char *p = NULL; + + ad = parse_adouble(frame, + ad_finderinfo1, + sizeof(ad_finderinfo1), + 0xffffff52); + assert_non_null(ad); + + p = ad_get_entry(ad, ADEID_FINDERI); + assert_null(p); + + return; +} + +static void parse_abouble_finderinfo2(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + + ad = parse_adouble(frame, + ad_finderinfo2, + sizeof(ad_finderinfo2), + 0xffffff52); + assert_null(ad); + + return; +} + +static void parse_abouble_finderinfo3(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + + ad = parse_adouble(frame, + ad_finderinfo3, + sizeof(ad_finderinfo3), + 0xffffff52); + assert_null(ad); + + return; +} + +static void parse_abouble_name(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + + ad = parse_adouble(frame, ad_name, sizeof(ad_name), 0x52); + assert_null(ad); + + return; +} + +static void parse_abouble_date1(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + char *p = NULL; + + ad = parse_adouble(frame, ad_date1, sizeof(ad_date1), 0x52); + assert_non_null(ad); + + p = ad_get_entry(ad, ADEID_FILEDATESI); + assert_null(p); + + return; +} + +static void parse_abouble_date2(void **state) +{ + TALLOC_CTX *frame = *state; + struct adouble *ad = NULL; + + ad = parse_adouble(frame, ad_date2, sizeof(ad_date2), 0x52); + assert_null(ad); + + return; +} + +int main(int argc, char *argv[]) +{ + int rc; + const struct CMUnitTest tests[] = { + cmocka_unit_test(parse_abouble_basic), + cmocka_unit_test(parse_abouble_finderinfo1), + cmocka_unit_test(parse_abouble_finderinfo2), + cmocka_unit_test(parse_abouble_finderinfo3), + cmocka_unit_test(parse_abouble_name), + cmocka_unit_test(parse_abouble_date1), + cmocka_unit_test(parse_abouble_date2), + }; + + if (argc == 2) { + cmocka_set_test_filter(argv[1]); + } + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + rc = cmocka_run_group_tests(tests, + setup_talloc_context, + teardown_talloc_context); + + return rc; +} diff --git a/source3/wscript_build b/source3/wscript_build index 26e251f442a..5230ae32934 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1080,6 +1080,11 @@ bld.SAMBA3_SUBSYSTEM('SPOOLSSD', ########################## BINARIES ################################# +bld.SAMBA3_BINARY('test_adouble', + source='lib/test_adouble.c', + deps='smbd_base STRING_REPLACE cmocka OFFLOAD_TOKEN', + install=False) + bld.SAMBA3_BINARY('smbd/smbd', source='smbd/server.c smbd/smbd_cleanupd.c', deps=''' -- 2.39.0 From 5c1c2ea3dbe554f621014bb2b3133c0859dce2da Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 13 Jan 2022 17:03:02 +0100 Subject: [PATCH 097/142] CVE-2021-44142: libadouble: harden parsing code BUG: https://bugzilla.samba.org/show_bug.cgi?id=14914 Signed-off-by: Ralph Boehme --- selftest/knownfail.d/samba.unittests.adouble | 3 - source3/modules/vfs_fruit.c | 114 ++++++++++++++++--- 2 files changed, 100 insertions(+), 17 deletions(-) delete mode 100644 selftest/knownfail.d/samba.unittests.adouble diff --git a/selftest/knownfail.d/samba.unittests.adouble b/selftest/knownfail.d/samba.unittests.adouble deleted file mode 100644 index 8b0314f2fae..00000000000 --- a/selftest/knownfail.d/samba.unittests.adouble +++ /dev/null @@ -1,3 +0,0 @@ -^samba.unittests.adouble.parse_abouble_finderinfo2\(none\) -^samba.unittests.adouble.parse_abouble_finderinfo3\(none\) -^samba.unittests.adouble.parse_abouble_date2\(none\) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 76139e51047..17e97d15bdb 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -540,6 +540,94 @@ static AfpInfo *afpinfo_new(TALLOC_CTX *ctx); static ssize_t afpinfo_pack(const AfpInfo *ai, char *buf); static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data); +/* + * All entries besides FinderInfo and resource fork must fit into the + * buffer. FinderInfo is special as it may be larger then the default 32 bytes + * if it contains marshalled xattrs, which we will fixup that in + * ad_convert(). The first 32 bytes however must also be part of the buffer. + * + * The resource fork is never accessed directly by the ad_data buf. + */ +static bool ad_entry_check_size(uint32_t eid, + size_t bufsize, + uint32_t off, + uint32_t got_len) +{ + struct { + off_t expected_len; + bool fixed_size; + bool minimum_size; + } ad_checks[] = { + [ADEID_DFORK] = {-1, false, false}, /* not applicable */ + [ADEID_RFORK] = {-1, false, false}, /* no limit */ + [ADEID_NAME] = {ADEDLEN_NAME, false, false}, + [ADEID_COMMENT] = {ADEDLEN_COMMENT, false, false}, + [ADEID_ICONBW] = {ADEDLEN_ICONBW, true, false}, + [ADEID_ICONCOL] = {ADEDLEN_ICONCOL, false, false}, + [ADEID_FILEI] = {ADEDLEN_FILEI, true, false}, + [ADEID_FILEDATESI] = {ADEDLEN_FILEDATESI, true, false}, + [ADEID_FINDERI] = {ADEDLEN_FINDERI, false, true}, + [ADEID_MACFILEI] = {ADEDLEN_MACFILEI, true, false}, + [ADEID_PRODOSFILEI] = {ADEDLEN_PRODOSFILEI, true, false}, + [ADEID_MSDOSFILEI] = {ADEDLEN_MSDOSFILEI, true, false}, + [ADEID_SHORTNAME] = {ADEDLEN_SHORTNAME, false, false}, + [ADEID_AFPFILEI] = {ADEDLEN_AFPFILEI, true, false}, + [ADEID_DID] = {ADEDLEN_DID, true, false}, + [ADEID_PRIVDEV] = {ADEDLEN_PRIVDEV, true, false}, + [ADEID_PRIVINO] = {ADEDLEN_PRIVINO, true, false}, + [ADEID_PRIVSYN] = {ADEDLEN_PRIVSYN, true, false}, + [ADEID_PRIVID] = {ADEDLEN_PRIVID, true, false}, + }; + + if (eid >= ADEID_MAX) { + return false; + } + if (got_len == 0) { + /* Entry present, but empty, allow */ + return true; + } + if (ad_checks[eid].expected_len == 0) { + /* + * Shouldn't happen: implicitly initialized to zero because + * explicit initializer missing. + */ + return false; + } + if (ad_checks[eid].expected_len == -1) { + /* Unused or no limit */ + return true; + } + if (ad_checks[eid].fixed_size) { + if (ad_checks[eid].expected_len != got_len) { + /* Wrong size fo fixed size entry. */ + return false; + } + } else { + if (ad_checks[eid].minimum_size) { + if (got_len < ad_checks[eid].expected_len) { + /* + * Too small for variable sized entry with + * minimum size. + */ + return false; + } + } else { + if (got_len > ad_checks[eid].expected_len) { + /* Too big for variable sized entry. */ + return false; + } + } + } + if (off + got_len < off) { + /* wrap around */ + return false; + } + if (off + got_len > bufsize) { + /* overflow */ + return false; + } + return true; +} /** * Return a pointer to an AppleDouble entry @@ -548,8 +636,15 @@ static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data); **/ static char *ad_get_entry(const struct adouble *ad, int eid) { + size_t bufsize = talloc_get_size(ad->ad_data); off_t off = ad_getentryoff(ad, eid); size_t len = ad_getentrylen(ad, eid); + bool valid; + + valid = ad_entry_check_size(eid, bufsize, off, len); + if (!valid) { + return NULL; + } if (off == 0 || len == 0) { return NULL; @@ -935,20 +1030,11 @@ static bool ad_unpack(struct adouble *ad, const size_t nentries, return false; } - /* - * All entries besides FinderInfo and resource fork - * must fit into the buffer. FinderInfo is special as - * it may be larger then the default 32 bytes (if it - * contains marshalled xattrs), but we will fixup that - * in ad_convert(). And the resource fork is never - * accessed directly by the ad_data buf (also see - * comment above) anyway. - */ - if ((eid != ADEID_RFORK) && - (eid != ADEID_FINDERI) && - ((off + len) > bufsize)) { - DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n", - eid, off, len)); + ok = ad_entry_check_size(eid, bufsize, off, len); + if (!ok) { + DBG_ERR("bogus eid [%"PRIu32"] bufsize [%zu] " + "off [%"PRIu32"] len [%"PRIu32"]\n", + eid, bufsize, off, len); return false; } -- 2.39.0 From 2c1f15a39367493733e4d275c3709a6497225917 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 5 Mar 2021 15:48:29 -0700 Subject: [PATCH 098/142] winbind: Only use unixid2sid mapping when module reports ID_MAPPED Only consider a mapping to be valid when the idmap module reports ID_MAPPED. Otherwise return the null SID. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14663 Signed-off-by: Christof Schmitt Reviewed-by: Volker Lendecke (cherry picked from commit db2afa57e4aa926b478db1be4d693edbdf4d2a23) (cherry picked from commit 3aa06edf38bc4002f031476baa50712fd1a67f4d) --- source3/winbindd/winbindd_dual_srv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 0842241e02e..94331163006 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -275,8 +275,10 @@ NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p, } for (i=0; iin.num_ids; i++) { - r->out.xids[i] = maps[i]->xid; - sid_copy(&r->out.sids[i], maps[i]->sid); + if (maps[i]->status == ID_MAPPED) { + r->out.xids[i] = maps[i]->xid; + sid_copy(&r->out.sids[i], maps[i]->sid); + } } TALLOC_FREE(maps); -- 2.39.0 From 754ece447c2dea8cccbe8740df5aff75dca7b646 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 5 Mar 2021 16:01:13 -0700 Subject: [PATCH 099/142] idmap_rfc2307: Do not return SID from unixids_to_sids on type mismatch The call to winbind_lookup_name already wrote the result in the id_map array. The later check for the type detected a mismatch, but that did not remove the SID from the result struct. Change this by first assigning the SID to a temporary variable and only write it to the id_map array after the type checks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14663 Signed-off-by: Christof Schmitt (cherry picked from commit 79dd4b133c37451c98fe7f7c45da881e89e91ffc) (cherry picked from commit af37d5abae924d095e7b35620d850cf1f19021c4) --- source3/winbindd/idmap_rfc2307.c | 4 +++- source3/winbindd/winbindd_dual_srv.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/source3/winbindd/idmap_rfc2307.c b/source3/winbindd/idmap_rfc2307.c index e3bf58d8165..2fffaec6cca 100644 --- a/source3/winbindd/idmap_rfc2307.c +++ b/source3/winbindd/idmap_rfc2307.c @@ -228,6 +228,7 @@ static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx, for (i = 0; i < count; i++) { char *name; + struct dom_sid sid; enum lsa_SidType lsa_type; struct id_map *map; uint32_t id; @@ -276,7 +277,7 @@ static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx, the following call will not recurse so this is safe */ (void)winbind_on(); /* Lookup name from PDC using lsa_lookup_names() */ - b = winbind_lookup_name(dom_name, name, map->sid, &lsa_type); + b = winbind_lookup_name(dom_name, name, &sid, &lsa_type); (void)winbind_off(); if (!b) { @@ -300,6 +301,7 @@ static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx, } map->status = ID_MAPPED; + sid_copy(map->sid, &sid); } } diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 94331163006..34375b3858f 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -278,6 +278,8 @@ NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p, if (maps[i]->status == ID_MAPPED) { r->out.xids[i] = maps[i]->xid; sid_copy(&r->out.sids[i], maps[i]->sid); + } else { + r->out.sids[i] = (struct dom_sid) { 0 }; } } -- 2.39.0 From f831d80dde35ba0e29014a9e4f34cb3ce6eb6161 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 5 Mar 2021 16:07:54 -0700 Subject: [PATCH 100/142] idmap_nss: Do not return SID from unixids_to_sids on type mismatch The call to winbind_lookup_name already wrote the result in the id_map array. The later check for the type detected a mismatch, but that did not remove the SID from the result struct. Change this by first assigning the SID to a temporary variable and only write it to the id_map array after the type checks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14663 Signed-off-by: Christof Schmitt Reviewed-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Thu Mar 11 08:38:41 UTC 2021 on sn-devel-184 (cherry picked from commit 0e789ba1802ca22e5a01abd6e93ef66cd45566a7) (cherry picked from commit 3f366878d33cf977230137021f6376936b2a1862) --- source3/winbindd/idmap_nss.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c index 243b67ccafd..e4bf1923786 100644 --- a/source3/winbindd/idmap_nss.c +++ b/source3/winbindd/idmap_nss.c @@ -56,6 +56,7 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma struct passwd *pw; struct group *gr; const char *name; + struct dom_sid sid; enum lsa_SidType type; bool ret; @@ -87,7 +88,7 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma the following call will not recurse so this is safe */ (void)winbind_on(); /* Lookup name from PDC using lsa_lookup_names() */ - ret = winbind_lookup_name(dom->name, name, ids[i]->sid, &type); + ret = winbind_lookup_name(dom->name, name, &sid, &type); (void)winbind_off(); if (!ret) { @@ -100,6 +101,7 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma switch (type) { case SID_NAME_USER: if (ids[i]->xid.type == ID_TYPE_UID) { + sid_copy(ids[i]->sid, &sid); ids[i]->status = ID_MAPPED; } break; @@ -108,6 +110,7 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: if (ids[i]->xid.type == ID_TYPE_GID) { + sid_copy(ids[i]->sid, &sid); ids[i]->status = ID_MAPPED; } break; -- 2.39.0 From 4ef3d95fb680cf278e68b6794459ff7bce1489aa Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 23 Nov 2021 15:48:57 +0100 Subject: [PATCH 101/142] s3:winbind: Fix possible NULL pointer dereference BUG: https://bugzilla.redhat.com/show_bug.cgi?id=2019888 Signed-off-by: Andreas Schneider Rewiewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon Nov 29 19:40:50 UTC 2021 on sn-devel-184 (cherry picked from commit cbf312f02bc86f9325fb89f6f5441bc61fd3974f) --- source3/winbindd/winbindd_util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 04e79e70f6b..d1bd81b2372 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -1691,6 +1691,9 @@ char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx, } tmp_user = talloc_strdup(mem_ctx, user); + if (tmp_user == NULL) { + return NULL; + } if (!strlower_m(tmp_user)) { TALLOC_FREE(tmp_user); return NULL; -- 2.39.0 From 95c9485bb600e965f24712534850d1a7fd325c44 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2022 16:00:36 +0100 Subject: [PATCH 102/142] CVE-2022-38023 docs-xml: improve wording for several options: "takes precedence" -> "overrides" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 8ec62694a94c346e6ba8f3144a417c9984a1c8b9) --- docs-xml/smbdotconf/logon/rejectmd5clients.xml | 2 +- docs-xml/smbdotconf/security/serverschannel.xml | 2 +- docs-xml/smbdotconf/winbind/rejectmd5servers.xml | 2 +- docs-xml/smbdotconf/winbind/requirestrongkey.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index 41684ef1080..0bb9f6f6c8e 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -10,7 +10,7 @@ You can set this to yes if all domain members support aes. This will prevent downgrade attacks. - This option takes precedence to the 'allow nt4 crypto' option. + This option overrides the 'allow nt4 crypto' option. no diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index b682d086f76..79e4e73a95c 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -59,7 +59,7 @@ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 - This option takes precedence to the option. + This option overrides the option. server require schannel:LEGACYCOMPUTER1$ = no diff --git a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml index 37656293aa4..151b4676c57 100644 --- a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml +++ b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml @@ -15,7 +15,7 @@ The behavior can be controlled per netbios domain by using 'reject md5 servers:NETBIOSDOMAIN = yes' as option. - This option takes precedence to the option. + This option overrides the option. no diff --git a/docs-xml/smbdotconf/winbind/requirestrongkey.xml b/docs-xml/smbdotconf/winbind/requirestrongkey.xml index 4db62bfb02d..b17620ec8f1 100644 --- a/docs-xml/smbdotconf/winbind/requirestrongkey.xml +++ b/docs-xml/smbdotconf/winbind/requirestrongkey.xml @@ -19,7 +19,7 @@ This option yields precedence to the option. - This option takes precedence to the option. + This option overrides the option. yes -- 2.39.0 From d6ab8377e55e4bda76c86de9bba1ddee30361481 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2022 16:05:26 +0100 Subject: [PATCH 103/142] CVE-2022-38023 docs-xml: improve wording for several options: "yields precedence" -> "is over-riden" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 830e865ba5648f6520bc552ffd71b61f754b8251) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 2 +- docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml | 2 +- docs-xml/smbdotconf/security/clientschannel.xml | 2 +- docs-xml/smbdotconf/security/serverschannel.xml | 2 +- docs-xml/smbdotconf/winbind/requirestrongkey.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index 03dc8fa93f7..06afcef73b1 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -18,7 +18,7 @@ "allow nt4 crypto = yes" allows weak crypto to be negotiated, maybe via downgrade attacks. - This option yields precedence to the 'reject md5 clients' option. + This option is over-ridden by the 'reject md5 clients' option. no diff --git a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml index 03531adbfb3..8bccab391cc 100644 --- a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml +++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml @@ -15,7 +15,7 @@ The behavior can be overwritten per interface name (e.g. lsarpc, netlogon, samr, srvsvc, winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = yes' as option. - This option yields precedence to the implementation specific restrictions. + This option is over-ridden by the implementation specific restrictions. E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY. The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY. diff --git a/docs-xml/smbdotconf/security/clientschannel.xml b/docs-xml/smbdotconf/security/clientschannel.xml index 5b07da95050..d124ad48181 100644 --- a/docs-xml/smbdotconf/security/clientschannel.xml +++ b/docs-xml/smbdotconf/security/clientschannel.xml @@ -23,7 +23,7 @@ Note that for active directory domains this is hardcoded to yes. - This option yields precedence to the option. + This option is over-ridden by the option. yes auto diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index 79e4e73a95c..3e66df1c203 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -23,7 +23,7 @@ If you still have legacy domain members use the option. - This option yields precedence to the option. + This option is over-ridden by the option. diff --git a/docs-xml/smbdotconf/winbind/requirestrongkey.xml b/docs-xml/smbdotconf/winbind/requirestrongkey.xml index b17620ec8f1..9c1c1d7af14 100644 --- a/docs-xml/smbdotconf/winbind/requirestrongkey.xml +++ b/docs-xml/smbdotconf/winbind/requirestrongkey.xml @@ -17,7 +17,7 @@ Note for active directory domain this option is hardcoded to 'yes' - This option yields precedence to the option. + This option is over-ridden by the option. This option overrides the option. -- 2.39.0 From 976080e72039b68ab66b757f1c3cb258eaca23df Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:46:59 +0100 Subject: [PATCH 104/142] CVE-2022-38023 libcli/auth: pass lp_ctx to netlogon_creds_cli_set_global_db() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 992f39a2c8a58301ceeb965f401e29cd64c5a209) --- libcli/auth/netlogon_creds_cli.c | 3 ++- libcli/auth/netlogon_creds_cli.h | 2 +- source3/rpc_client/cli_netlogon.c | 2 +- source3/utils/destroy_netlogon_creds_cli.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 0f6ca11ff96..c9873a5748e 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -201,7 +201,8 @@ static NTSTATUS netlogon_creds_cli_context_common( static struct db_context *netlogon_creds_cli_global_db; -NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db) +NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, + struct db_context **db) { if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_INVALID_PARAMETER_MIX; diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 56a2dd9bc77..2ce5de9d305 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -31,7 +31,7 @@ struct messaging_context; struct dcerpc_binding_handle; struct db_context; -NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db); +NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db); NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx); void netlogon_creds_cli_close_global_db(void); diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index f073f0d925e..b784064f17e 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -76,7 +76,7 @@ NTSTATUS rpccli_pre_open_netlogon_creds(void) return NT_STATUS_NO_MEMORY; } - status = netlogon_creds_cli_set_global_db(&global_db); + status = netlogon_creds_cli_set_global_db(lp_ctx, &global_db); TALLOC_FREE(frame); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source3/utils/destroy_netlogon_creds_cli.c b/source3/utils/destroy_netlogon_creds_cli.c index 137ac8393e7..95a650f4654 100644 --- a/source3/utils/destroy_netlogon_creds_cli.c +++ b/source3/utils/destroy_netlogon_creds_cli.c @@ -83,7 +83,7 @@ int main(int argc, const char *argv[]) goto done; } - status = netlogon_creds_cli_set_global_db(&global_db); + status = netlogon_creds_cli_set_global_db(lp_ctx, &global_db); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, "netlogon_creds_cli_set_global_db failed: %s\n", -- 2.39.0 From dfe17c3453980d53445a2cc6221cb8728fc9e3cf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:47:33 +0100 Subject: [PATCH 105/142] CVE-2022-38023 libcli/auth: add/use netlogon_creds_cli_warn_options() This warns the admin about insecure options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (similar to commit 7e7adf86e59e8a673fbe87de46cef0d62221e800) [jsutton@samba.org Replaced call to tevent_cached_getpid() with one to getpid()] --- libcli/auth/netlogon_creds_cli.c | 66 ++++++++++++++++++++++++++++++++ libcli/auth/netlogon_creds_cli.h | 2 + 2 files changed, 68 insertions(+) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index c9873a5748e..20a3da5060f 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -204,6 +204,8 @@ static struct db_context *netlogon_creds_cli_global_db; NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db) { + netlogon_creds_cli_warn_options(lp_ctx); + if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_INVALID_PARAMETER_MIX; } @@ -218,6 +220,8 @@ NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx) struct db_context *global_db; int hash_size, tdb_flags; + netlogon_creds_cli_warn_options(lp_ctx); + if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_OK; } @@ -258,6 +262,68 @@ void netlogon_creds_cli_close_global_db(void) TALLOC_FREE(netlogon_creds_cli_global_db); } +void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx) +{ + bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx); + bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx); + int global_client_schannel = lpcfg_client_schannel(lp_ctx); + bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx); + static bool warned_global_reject_md5_servers = false; + static bool warned_global_require_strong_key = false; + static bool warned_global_client_schannel = false; + static bool warned_global_seal_secure_channel = false; + static int warned_global_pid = 0; + int current_pid = getpid(); + + if (warned_global_pid != current_pid) { + warned_global_reject_md5_servers = false; + warned_global_require_strong_key = false; + warned_global_client_schannel = false; + warned_global_seal_secure_channel = false; + warned_global_pid = current_pid; + } + + if (!global_reject_md5_servers && !warned_global_reject_md5_servers) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'reject md5 servers = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_reject_md5_servers = true; + } + + if (!global_require_strong_key && !warned_global_require_strong_key) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'require strong key = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_require_strong_key = true; + } + + if (global_client_schannel != true && !warned_global_client_schannel) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'client schannel = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_client_schannel = true; + } + + if (!global_seal_secure_channel && !warned_global_seal_secure_channel) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'winbind sealed pipes = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_secure_channel = true; + } +} + NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, struct messaging_context *msg_ctx, const char *client_account, diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 2ce5de9d305..e4e0232e92f 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -35,6 +35,8 @@ NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struc NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx); void netlogon_creds_cli_close_global_db(void); +void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx); + NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, struct messaging_context *msg_ctx, const char *client_account, -- 2.39.0 From 75c44fdccf18bfa34530f05937e8e3305b2c927e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 16:16:05 +0100 Subject: [PATCH 106/142] CVE-2022-38023 s3:net: add and use net_warn_member_options() helper This makes sure domain member related 'net' commands print warnings about unsecure smb.conf options. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 1fdf1d55a5dd550bdb16d037b5dc995c33c1a67a) --- source3/utils/net.c | 6 ++++++ source3/utils/net_ads.c | 14 ++++++++++++++ source3/utils/net_dom.c | 2 ++ source3/utils/net_join.c | 2 ++ source3/utils/net_proto.h | 2 ++ source3/utils/net_rpc.c | 10 ++++++++++ source3/utils/net_util.c | 15 +++++++++++++++ 7 files changed, 51 insertions(+) diff --git a/source3/utils/net.c b/source3/utils/net.c index 8350e8c0967..c17dd972c3f 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -83,6 +83,8 @@ enum netr_SchannelType get_sec_channel_type(const char *param) static int net_changetrustpw(struct net_context *c, int argc, const char **argv) { + net_warn_member_options(); + if (net_ads_check_our_domain(c) == 0) return net_ads_changetrustpw(c, argc, argv); @@ -110,6 +112,8 @@ static int net_primarytrust_dumpinfo(struct net_context *c, int argc, return 1; } + net_warn_member_options(); + if (c->opt_stdin) { set_line_buffering(stdin); set_line_buffering(stdout); @@ -185,6 +189,8 @@ static int net_changesecretpw(struct net_context *c, int argc, return 1; } + net_warn_member_options(); + if(c->opt_force) { struct secrets_domain_info1 *info = NULL; struct secrets_domain_info1_change *prev = NULL; diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 3cf8fbbf7c8..32a7b2d7f7f 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -1290,6 +1290,8 @@ static int net_ads_status(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; } @@ -1431,6 +1433,8 @@ static NTSTATUS net_ads_join_ok(struct net_context *c) return NT_STATUS_ACCESS_DENIED; } + net_warn_member_options(); + net_use_krb_machine_account(c); get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip); @@ -1461,6 +1465,8 @@ int net_ads_testjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + /* Display success or failure */ status = net_ads_join_ok(c); if (!NT_STATUS_IS_OK(status)) { @@ -1846,6 +1852,8 @@ int net_ads_join(struct net_context *c, int argc, const char **argv) if (c->display_usage) return net_ads_join_usage(c, argc, argv); + net_warn_member_options(); + if (!modify_config) { werr = check_ads_config(); @@ -2732,6 +2740,8 @@ int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv) return -1; } + net_warn_member_options(); + net_use_krb_machine_account(c); use_in_memory_ccache(); @@ -3001,6 +3011,8 @@ static int net_ads_keytab_add(struct net_context *c, return 0; } + net_warn_member_options(); + d_printf(_("Processing principals to add...\n")); if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; @@ -3040,6 +3052,8 @@ static int net_ads_keytab_create(struct net_context *c, int argc, const char **a return 0; } + net_warn_member_options(); + if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; } diff --git a/source3/utils/net_dom.c b/source3/utils/net_dom.c index 1e45c59220c..db6e34e52de 100644 --- a/source3/utils/net_dom.c +++ b/source3/utils/net_dom.c @@ -154,6 +154,8 @@ static int net_dom_join(struct net_context *c, int argc, const char **argv) return net_dom_usage(c, argc, argv); } + net_warn_member_options(); + if (c->opt_host) { server_name = c->opt_host; } diff --git a/source3/utils/net_join.c b/source3/utils/net_join.c index 1493dff74d7..f67f08f79a8 100644 --- a/source3/utils/net_join.c +++ b/source3/utils/net_join.c @@ -39,6 +39,8 @@ int net_join(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + if (net_ads_check_our_domain(c) == 0) { if (net_ads_join(c, argc, argv) == 0) return 0; diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h index 22fe39e0f1c..38581a796cb 100644 --- a/source3/utils/net_proto.h +++ b/source3/utils/net_proto.h @@ -423,6 +423,8 @@ int net_run_function(struct net_context *c, int argc, const char **argv, const char *whoami, struct functable *table); void net_display_usage_from_functable(struct functable *table); +void net_warn_member_options(void); + const char *net_share_type_str(int num_type); NTSTATUS net_scan_dc(struct net_context *c, diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index f2d63d2af65..52c2ec37a89 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -370,6 +370,8 @@ static int net_rpc_oldjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_oldjoin"); if (!mem_ctx) { return -1; @@ -489,6 +491,8 @@ int net_rpc_testjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_testjoin"); if (!mem_ctx) { return -1; @@ -563,6 +567,8 @@ static int net_rpc_join_newstyle(struct net_context *c, int argc, const char **a return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_join_newstyle"); if (!mem_ctx) { return -1; @@ -684,6 +690,8 @@ int net_rpc_join(struct net_context *c, int argc, const char **argv) return -1; } + net_warn_member_options(); + if (strlen(lp_netbios_name()) > 15) { d_printf(_("Our netbios name can be at most 15 chars long, " "\"%s\" is %u chars long\n"), @@ -814,6 +822,8 @@ int net_rpc_info(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + return run_rpc_command(c, NULL, &ndr_table_samr, NET_FLAGS_PDC, rpc_info_internals, argc, argv); diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c index a84b4f5500e..94a8dc9defe 100644 --- a/source3/utils/net_util.c +++ b/source3/utils/net_util.c @@ -29,6 +29,8 @@ #include "secrets.h" #include "../libcli/security/security.h" #include "libsmb/libsmb.h" +#include "libcli/auth/netlogon_creds_cli.h" +#include "lib/param/param.h" NTSTATUS net_rpc_lookup_name(struct net_context *c, TALLOC_CTX *mem_ctx, struct cli_state *cli, @@ -534,6 +536,19 @@ void net_display_usage_from_functable(struct functable *table) } } +void net_warn_member_options(void) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct loadparm_context *lp_ctx = NULL; + + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); + if (lp_ctx != NULL) { + netlogon_creds_cli_warn_options(lp_ctx); + } + + TALLOC_FREE(frame); +} + const char *net_share_type_str(int num_type) { switch(num_type) { -- 2.39.0 From 9d7eba489e7f798dd3115439da1bc92a87059ce1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:59:36 +0100 Subject: [PATCH 107/142] CVE-2022-38023 s3:winbindd: also allow per domain "winbind sealed pipes:DOMAIN" and "require strong key:DOMAIN" This avoids advising insecure defaults for the global options. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit d60828f6391307a59abaa02b72b6a8acf66b2fef) --- source3/winbindd/winbindd_cm.c | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 502331f7260..1a8017cf4cc 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -2734,6 +2734,8 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; bool retry = false; /* allow one retry attempt for expired session */ + bool sealed_pipes = true; + bool strong_key = true; if (sid_check_is_our_sam(&domain->sid)) { if (domain->rodc == false || need_rw_dc == false) { @@ -2907,14 +2909,24 @@ retry: anonymous: + sealed_pipes = lp_winbind_sealed_pipes(); + sealed_pipes = lp_parm_bool(-1, "winbind sealed pipes", + domain->name, + sealed_pipes); + strong_key = lp_require_strong_key(); + strong_key = lp_parm_bool(-1, "require strong key", + domain->name, + strong_key); + /* Finally fall back to anonymous. */ - if (lp_winbind_sealed_pipes() || lp_require_strong_key()) { + if (sealed_pipes || strong_key) { status = NT_STATUS_DOWNGRADE_DETECTED; DEBUG(1, ("Unwilling to make SAMR connection to domain %s " "without connection level security, " - "must set 'winbind sealed pipes = false' and " - "'require strong key = false' to proceed: %s\n", - domain->name, nt_errstr(status))); + "must set 'winbind sealed pipes:%s = false' and " + "'require strong key:%s = false' to proceed: %s\n", + domain->name, domain->name, domain->name, + nt_errstr(status))); goto done; } status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr, @@ -3061,6 +3073,8 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; bool retry = false; /* allow one retry attempt for expired session */ + bool sealed_pipes = true; + bool strong_key = true; retry: result = init_dc_connection_rpc(domain, false); @@ -3216,13 +3230,24 @@ retry: goto done; } - if (lp_winbind_sealed_pipes() || lp_require_strong_key()) { + sealed_pipes = lp_winbind_sealed_pipes(); + sealed_pipes = lp_parm_bool(-1, "winbind sealed pipes", + domain->name, + sealed_pipes); + strong_key = lp_require_strong_key(); + strong_key = lp_parm_bool(-1, "require strong key", + domain->name, + strong_key); + + /* Finally fall back to anonymous. */ + if (sealed_pipes || strong_key) { result = NT_STATUS_DOWNGRADE_DETECTED; DEBUG(1, ("Unwilling to make LSA connection to domain %s " "without connection level security, " - "must set 'winbind sealed pipes = false' and " - "'require strong key = false' to proceed: %s\n", - domain->name, nt_errstr(result))); + "must set 'winbind sealed pipes:%s = false' and " + "'require strong key:%s = false' to proceed: %s\n", + domain->name, domain->name, domain->name, + nt_errstr(result))); goto done; } -- 2.39.0 From b310b2672f80a717188675b6c762d184436a190c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Nov 2022 18:22:23 +0100 Subject: [PATCH 108/142] CVE-2022-38023 docs-xml/smbdotconf: change 'reject md5 servers' default to yes AES is supported by Windows >= 2008R2 and Samba >= 4.0 so there's no reason to allow md5 servers by default. Note the change in netlogon_creds_cli_context_global() is only cosmetic, but avoids confusion while reading the code. Check with: git show -U35 libcli/auth/netlogon_creds_cli.c BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 1c6c1129905d0c7a60018e7bf0f17a0fd198a584) --- docs-xml/smbdotconf/winbind/rejectmd5servers.xml | 7 +++++-- lib/param/loadparm.c | 1 + libcli/auth/netlogon_creds_cli.c | 4 ++-- source3/param/loadparm.c | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml index 151b4676c57..3bc4eaf7b02 100644 --- a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml +++ b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml @@ -13,10 +13,13 @@ This will prevent downgrade attacks. The behavior can be controlled per netbios domain - by using 'reject md5 servers:NETBIOSDOMAIN = yes' as option. + by using 'reject md5 servers:NETBIOSDOMAIN = no' as option. + + The default changed from 'no' to 'yes, with the patches for CVE-2022-38023, + see https://bugzilla.samba.org/show_bug.cgi?id=15240 This option overrides the option. -no +yes diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 4aa91f4d404..dc659a449ea 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2733,6 +2733,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind sealed pipes", "True"); lpcfg_do_global_parameter(lp_ctx, "winbind scan trusted domains", "True"); lpcfg_do_global_parameter(lp_ctx, "require strong key", "True"); + lpcfg_do_global_parameter(lp_ctx, "reject md5 servers", "True"); lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR); lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR); lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/samba-gpupdate", dyn_SCRIPTSBINDIR); diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 20a3da5060f..0558cb237a4 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -340,8 +340,8 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, const char *client_computer; uint32_t proposed_flags; uint32_t required_flags = 0; - bool reject_md5_servers = false; - bool require_strong_key = false; + bool reject_md5_servers = true; + bool require_strong_key = true; int require_sign_or_seal = true; bool seal_secure_channel = true; enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 98e05d13d59..fbc987e119a 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -657,6 +657,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.client_schannel = true; Globals.winbind_sealed_pipes = true; Globals.require_strong_key = true; + Globals.reject_md5_servers = true; Globals.server_schannel = true; Globals.read_raw = true; Globals.write_raw = true; -- 2.39.0 From b62fb90dd434c99131086f27cb74cf2c109fb9d2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Dec 2022 10:56:29 +0100 Subject: [PATCH 109/142] CVE-2022-38023 s4:rpc_server/netlogon: 'server schannel != yes' warning to dcesrv_interface_netlogon_bind This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit e060ea5b3edbe3cba492062c9605f88fae212ee0) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 7668a9eb923..e7f8cd5c075 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -60,6 +60,21 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface) { + struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; + int schannel = lpcfg_server_schannel(lp_ctx); + bool schannel_global_required = (schannel == true); + static bool warned_global_schannel_once = false; + + if (!schannel_global_required && !warned_global_schannel_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2020-1472(ZeroLogon): " + "Please configure 'server schannel = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); + warned_global_schannel_once = true; + } + return dcesrv_interface_bind_reject_connect(context, iface); } @@ -629,7 +644,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; - static bool warned_global_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -681,16 +695,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc return NT_STATUS_ACCESS_DENIED; } - if (!schannel_global_required && !warned_global_once) { - /* - * We want admins to notice their misconfiguration! - */ - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Please configure 'server schannel = yes', " - "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); - warned_global_once = true; - } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) WITH schannel from " -- 2.39.0 From dbddee016499bddab42870226eda0b19facca936 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Dec 2022 14:03:50 +0100 Subject: [PATCH 110/142] CVE-2022-38023 s4:rpc_server/netlogon: add a lp_ctx variable to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 7baabbe9819cd5a2714e7ea4e57a0c23062c0150) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index e7f8cd5c075..bd3a36e60cc 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -635,8 +635,9 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; NTSTATUS nt_status; - int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); + int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; @@ -652,7 +653,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc dcesrv_call_auth_info(dce_call, &auth_type, NULL); nt_status = schannel_check_creds_state(mem_ctx, - dce_call->conn->dce_ctx->lp_ctx, + lp_ctx, computer_name, received_authenticator, return_authenticator, @@ -667,7 +668,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc * need the explicit_opt pointer in order to * adjust the debug messages. */ - explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx, + explicit_opt = lpcfg_get_parametric(lp_ctx, NULL, "server require schannel", creds->account_name); -- 2.39.0 From da1c4d9055c0b7fcb5e6952e3e63c7089b2b0432 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Dec 2022 14:03:50 +0100 Subject: [PATCH 111/142] CVE-2022-38023 s4:rpc_server/netlogon: add talloc_stackframe() to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 0e6a2ba83ef1be3c6a0f5514c21395121621a145) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index bd3a36e60cc..b842fa6a556 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -636,6 +636,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc struct netlogon_creds_CredentialState **creds_out) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS nt_status; int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); @@ -679,6 +680,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -686,13 +688,15 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' is needed! \n", - log_escape(mem_ctx, creds->account_name)); + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } @@ -701,13 +705,14 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%s request (opnum[%u]) WITH schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -717,24 +722,25 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_INFO("CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' still needed!\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); } else { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " "'server require schannel:%s = no' might be needed!\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); } *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } -- 2.39.0 From 01d4d64eaca505da9c542f2149c0bd362ad180d1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:37:03 +0100 Subject: [PATCH 112/142] CVE-2022-38023 s4:rpc_server/netlogon: re-order checking in dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit ec62151a2fb49ecbeaa3bf924f49a956832b735e) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b842fa6a556..9b3a933abca 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -677,13 +677,27 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc schannel_required = lp_bool(explicit_opt); } - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (!schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) WITH schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } + if (explicit_opt != NULL && !schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(frame, creds->account_name)); } + *creds_out = creds; + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (schannel_required) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", @@ -700,23 +714,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc return NT_STATUS_ACCESS_DENIED; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) WITH schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); - - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; - } - - if (explicit_opt != NULL) { DBG_INFO("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " -- 2.39.0 From 90531a4cb89b0d390261de1920f17a8ea7a9cbcb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:37:03 +0100 Subject: [PATCH 113/142] CVE-2022-38023 s4:rpc_server/netlogon: improve CVE-2020-1472(ZeroLogon) debug messages In order to avoid generating useless debug messages during make test, we will use 'CVE_2020_1472:warn_about_unused_debug_level = 3' and 'CVE_2020_1472:error_debug_level = 2' in order to avoid schannel warnings. Review with: git show -w BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 16ee03efc194d9c1c2c746f63236b977a419918d) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 147 +++++++++++++----- 1 file changed, 106 insertions(+), 41 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 9b3a933abca..8084061aabc 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -643,15 +643,34 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; struct netlogon_creds_CredentialState *creds = NULL; + int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + unsigned int dbg_lvl = DBGLVL_DEBUG; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; + const char *reason = ""; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; } - dcesrv_call_auth_info(dce_call, &auth_type, NULL); + dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + reason = "WITH SEALED"; + } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + reason = "WITH SIGNED"; + } else { + smb_panic("Schannel without SIGN/SEAL"); + } + } else { + reason = "WITHOUT"; + } nt_status = schannel_check_creds_state(mem_ctx, lp_ctx, @@ -678,62 +697,108 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc } if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (!schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) WITH schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); + nt_status = NT_STATUS_OK; + + if (explicit_opt != NULL && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + if (explicit_opt != NULL && !schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; TALLOC_FREE(frame); - return NT_STATUS_OK; + return nt_status; } if (schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' " - "might be needed for a legacy client.\n", - log_escape(frame, creds->account_name)); + nt_status = NT_STATUS_ACCESS_DENIED; + + if (explicit_opt != NULL) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + if (explicit_opt != NULL) { + D_NOTICE("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); - return NT_STATUS_ACCESS_DENIED; + return nt_status; } + nt_status = NT_STATUS_OK; + if (explicit_opt != NULL) { - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' still needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' might be needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + + if (explicit_opt != NULL) { + D_INFO("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server require schannel:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): " + "Please use 'server require schannel:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; -- 2.39.0 From 2ea49737a5cac8ead895da30d40f18019103b285 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:26:01 +0100 Subject: [PATCH 114/142] CVE-2022-38023 selftest:Samba4: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 63c96ea6c02981795e67336401143f2a8836992c) --- selftest/target/Samba4.pm | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 0f644661176..8dad74cae43 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1708,7 +1708,24 @@ sub provision_ad_dc_ntvfs($$) dsdb event notification = true dsdb password event notification = true dsdb group change notification = true - server schannel = auto + + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + + # needed for 'samba.tests.auth_log' tests + server require schannel:LOCALDC\$ = no "; my $extra_provision_options = ["--use-ntvfs"]; my $ret = $self->provision($prefix, @@ -2085,8 +2102,22 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes - server schannel = auto - auth event notification = true + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + + auth event notification = true dsdb event notification = true dsdb password event notification = true dsdb group change notification = true -- 2.39.0 From a9ad04a6a886c4f17120fcf585bba7b979752d3c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 28 Nov 2022 15:02:13 +0100 Subject: [PATCH 115/142] CVE-2022-38023 s4:torture: use NETLOGON_NEG_SUPPORTS_AES by default For generic tests we should use the best available features. And AES will be required by default soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit cfd55a22cda113fbb2bfa373b54091dde1ea6e66) --- source4/torture/ntp/ntp_signd.c | 2 +- source4/torture/rpc/lsa.c | 4 ++-- source4/torture/rpc/netlogon.c | 18 +++++++++--------- source4/torture/rpc/samba3rpc.c | 15 ++++++++++++--- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/source4/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c index d2a41819fcf..66f2b8956a2 100644 --- a/source4/torture/ntp/ntp_signd.c +++ b/source4/torture/ntp/ntp_signd.c @@ -68,7 +68,7 @@ static bool test_ntp_signd(struct torture_context *tctx, uint32_t rid; const char *machine_name; const struct samr_Password *pwhash = cli_credentials_get_nt_hash(credentials, mem_ctx); - uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; struct sign_request sign_req; struct signed_reply signed_reply; diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index 7bdc0cf679a..52e220ce225 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -4260,7 +4260,7 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p, torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b"); ok = check_pw_with_ServerAuthenticate3(p1, tctx, - NETLOGON_NEG_AUTH2_ADS_FLAGS, + NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, server_name, incoming_creds, &creds); torture_assert_int_equal(tctx, ok, expected_result, @@ -4357,7 +4357,7 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p, torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b"); ok = check_pw_with_ServerAuthenticate3(p2, tctx, - NETLOGON_NEG_AUTH2_ADS_FLAGS, + NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, server_name, incoming_creds, &creds); torture_assert(tctx, ok, "check_pw_with_ServerAuthenticate3 with changed password"); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index 97c16688bc9..1fceeae88cc 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -189,7 +189,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, /* This allows the tests to continue against the more fussy windows 2008 */ if (NT_STATUS_EQUAL(a.out.result, NT_STATUS_DOWNGRADE_DETECTED)) { - return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, credentials, cli_credentials_get_secure_channel_type(credentials), creds_out); @@ -423,7 +423,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, "ServerAuthenticate3 failed"); torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_DOWNGRADE_DETECTED, "ServerAuthenticate3 should have failed"); - negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; creds = netlogon_creds_client_init(tctx, a.in.account_name, a.in.computer_name, a.in.secure_channel_type, @@ -490,7 +490,7 @@ static bool test_ServerReqChallenge( const char *machine_name; struct dcerpc_binding_handle *b = p->binding_handle; struct netr_ServerAuthenticate2 a; - uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -562,7 +562,7 @@ static bool test_ServerReqChallenge_zero_challenge( const char *machine_name; struct dcerpc_binding_handle *b = p->binding_handle; struct netr_ServerAuthenticate2 a; - uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -639,7 +639,7 @@ static bool test_ServerReqChallenge_5_repeats( const char *machine_name; struct dcerpc_binding_handle *b = p->binding_handle; struct netr_ServerAuthenticate2 a; - uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -723,7 +723,7 @@ static bool test_ServerReqChallenge_4_repeats( const char *machine_name; struct dcerpc_binding_handle *b = p->binding_handle; struct netr_ServerAuthenticate2 a; - uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -3459,7 +3459,7 @@ static bool test_netr_GetForestTrustInformation(struct torture_context *tctx, struct dcerpc_pipe *p = NULL; struct dcerpc_binding_handle *b = NULL; - if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } @@ -4398,7 +4398,7 @@ static bool test_GetDomainInfo(struct torture_context *tctx, torture_comment(tctx, "Testing netr_LogonGetDomainInfo\n"); - if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } @@ -4973,7 +4973,7 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx, torture_comment(tctx, "Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT); - if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index 9cd479c9baf..6fc4ed326d2 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -1074,7 +1074,7 @@ static bool auth2(struct torture_context *tctx, goto done; } - negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; E_md4hash(cli_credentials_get_password(wks_cred), mach_pw.hash); a.in.server_name = talloc_asprintf( @@ -1264,10 +1264,19 @@ static bool schan(struct torture_context *tctx, E_md4hash(cli_credentials_get_password(user_creds), pinfo.ntpassword.hash); - netlogon_creds_arcfour_crypt(creds_state, pinfo.ntpassword.hash, 16); - logon.password = &pinfo; + /* + * We don't use this here: + * + * netlogon_creds_encrypt_samlogon_logon(creds_state, + * NetlogonInteractiveInformation, + * &logon); + * + * in order to detect bugs + */ + netlogon_creds_aes_encrypt(creds_state, pinfo.ntpassword.hash, 16); + r.in.logon_level = NetlogonInteractiveInformation; r.in.logon = &logon; r.out.return_authenticator = &return_authenticator; -- 2.39.0 From 6088b76def86b8f56511707c69b6cdd016722715 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 09:54:17 +0100 Subject: [PATCH 116/142] CVE-2022-38023 s4:rpc_server/netlogon: split out dcesrv_netr_ServerAuthenticate3_check_downgrade() We'll soon make it possible to use 'reject md5 servers:CLIENTACCOUNT$ = no', which means we'll need the downgrade detection in more places. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b6339fd1dcbe903e73efeea074ab0bd04ef83561) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 114 ++++++++++-------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 8084061aabc..6a00fe4efcf 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -128,6 +128,67 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal return NT_STATUS_OK; } +static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( + struct dcesrv_call_state *dce_call, + struct netr_ServerAuthenticate3 *r, + struct netlogon_server_pipe_state *pipe_state, + uint32_t negotiate_flags, + NTSTATUS orig_status) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool reject_des_client = !allow_nt4_crypto; + bool reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + + if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { + reject_des_client = false; + } + + if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + reject_des_client = false; + reject_md5_client = false; + } + + if (reject_des_client || reject_md5_client) { + /* + * Here we match Windows 2012 and return no flags. + */ + *r->out.negotiate_flags = 0; + return NT_STATUS_DOWNGRADE_DETECTED; + } + + /* + * This talloc_free is important to prevent re-use of the + * challenge. We have to delay it this far due to NETApp + * servers per: + * https://bugzilla.samba.org/show_bug.cgi?id=11291 + */ + TALLOC_FREE(pipe_state); + + /* + * At this point we must also cleanup the TDB cache + * entry, if we fail the client needs to call + * netr_ServerReqChallenge again. + * + * Note: this handles a non existing record just fine, + * the r->in.computer_name might not be the one used + * in netr_ServerReqChallenge(), but we are trying to + * just tidy up the normal case to prevent re-use. + */ + schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx, + r->in.computer_name); + + /* + * According to Microsoft (see bugid #6099) + * Windows 7 looks at the negotiate_flags + * returned in this structure *even if the + * call fails with access denied! + */ + *r->out.negotiate_flags = negotiate_flags; + + return orig_status; +} + /* * Do the actual processing of a netr_ServerAuthenticate3 message. * called from dcesrv_netr_ServerAuthenticate3, which handles the logging. @@ -155,11 +216,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( "objectSid", "samAccountName", NULL}; uint32_t server_flags = 0; uint32_t negotiate_flags = 0; - bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx); - bool reject_des_client = !allow_nt4_crypto; - bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx); ZERO_STRUCTP(r->out.return_credentials); + *r->out.negotiate_flags = 0; *r->out.rid = 0; pipe_state = dcesrv_iface_state_find_conn(dce_call, @@ -238,52 +297,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( negotiate_flags = *r->in.negotiate_flags & server_flags; - if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { - reject_des_client = false; - } - - if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - reject_des_client = false; - reject_md5_client = false; - } - - if (reject_des_client || reject_md5_client) { - /* - * Here we match Windows 2012 and return no flags. - */ - *r->out.negotiate_flags = 0; - return NT_STATUS_DOWNGRADE_DETECTED; + nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_OK); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; } - /* - * This talloc_free is important to prevent re-use of the - * challenge. We have to delay it this far due to NETApp - * servers per: - * https://bugzilla.samba.org/show_bug.cgi?id=11291 - */ - TALLOC_FREE(pipe_state); - - /* - * At this point we must also cleanup the TDB cache - * entry, if we fail the client needs to call - * netr_ServerReqChallenge again. - * - * Note: this handles a non existing record just fine, - * the r->in.computer_name might not be the one used - * in netr_ServerReqChallenge(), but we are trying to - * just tidy up the normal case to prevent re-use. - */ - schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx, - r->in.computer_name); - - /* - * According to Microsoft (see bugid #6099) - * Windows 7 looks at the negotiate_flags - * returned in this structure *even if the - * call fails with access denied! - */ - *r->out.negotiate_flags = negotiate_flags; - switch (r->in.secure_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_DNS_DOMAIN: -- 2.39.0 From 3e43111a1417414b545fcc46a72e701cf6e71c59 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Nov 2022 18:26:18 +0100 Subject: [PATCH 117/142] CVE-2022-38023 docs-xml/smbdotconf: change 'reject md5 clients' default to yes AES is supported by Windows Server >= 2008R2, Windows (Client) >= 7 and Samba >= 4.0, so there's no reason to allow md5 clients by default. However some third party domain members may need it. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit c8e53394b98b128ed460a6111faf05dfbad980d1) --- docs-xml/smbdotconf/logon/rejectmd5clients.xml | 11 ++++++++--- lib/param/loadparm.c | 1 + selftest/target/Samba4.pm | 4 ++++ source3/param/loadparm.c | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index 0bb9f6f6c8e..edcbe02e99a 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -7,11 +7,16 @@ only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_SUPPORTS_AES. - You can set this to yes if all domain members support aes. - This will prevent downgrade attacks. + Support for NETLOGON_NEG_SUPPORTS_AES was added in Windows + starting with Server 2008R2 and Windows 7, it's available in Samba + starting with 4.0, however third party domain members like NetApp ONTAP + still uses RC4 (HMAC-MD5), see https://www.samba.org/samba/security/CVE-2022-38023.html for more details. + + The default changed from 'no' to 'yes', with the patches for CVE-2022-38023, + see https://bugzilla.samba.org/show_bug.cgi?id=15240 This option overrides the 'allow nt4 crypto' option. -no +yes diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index dc659a449ea..77a80176f7d 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2790,6 +2790,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind nss info", "template"); lpcfg_do_global_parameter(lp_ctx, "server schannel", "True"); + lpcfg_do_global_parameter(lp_ctx, "reject md5 clients", "True"); lpcfg_do_global_parameter(lp_ctx, "short preserve case", "True"); diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 8dad74cae43..7e3d7c9de8e 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1709,6 +1709,8 @@ sub provision_ad_dc_ntvfs($$) dsdb password event notification = true dsdb group change notification = true + reject md5 clients = no + CVE_2020_1472:warn_about_unused_debug_level = 3 server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no @@ -2102,6 +2104,8 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes + reject md5 clients = no + CVE_2020_1472:warn_about_unused_debug_level = 3 server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index fbc987e119a..1cf468b1009 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -659,6 +659,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.require_strong_key = true; Globals.reject_md5_servers = true; Globals.server_schannel = true; + Globals.reject_md5_clients = true; Globals.read_raw = true; Globals.write_raw = true; Globals.null_passwords = false; -- 2.39.0 From 886878d18d22eb4a2f3b63663e0ffe284ed9788b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 10:31:08 +0100 Subject: [PATCH 118/142] CVE-2022-38023 s4:rpc_server/netlogon: defer downgrade check until we found the account in our SAM We'll soon make it possible to use 'reject md5 servers:CLIENTACCOUNT$ = no', which means we'll need use the account name from our SAM. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b09f51eefc311bbb1525efd1dc7b9a837f7ec3c2) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 6a00fe4efcf..1c180343252 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -297,13 +297,6 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( negotiate_flags = *r->in.negotiate_flags & server_flags; - nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( - dce_call, r, pipe_state, negotiate_flags, - NT_STATUS_OK); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - switch (r->in.secure_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_DNS_DOMAIN: @@ -312,11 +305,15 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( case SEC_CHAN_RODC: break; case SEC_CHAN_NULL: - return NT_STATUS_INVALID_PARAMETER; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_PARAMETER); default: DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", r->in.secure_channel_type)); - return NT_STATUS_INVALID_PARAMETER; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_PARAMETER); } sam_ctx = samdb_connect(mem_ctx, @@ -326,7 +323,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( dce_call->conn->remote_address, 0); if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_SYSTEM_SERVICE); } if (r->in.secure_channel_type == SEC_CHAN_DOMAIN || @@ -355,16 +354,22 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( encoded_name = ldb_binary_encode_string(mem_ctx, r->in.account_name); if (encoded_name == NULL) { - return NT_STATUS_NO_MEMORY; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_MEMORY); } len = strlen(encoded_name); if (len < 2) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (require_trailer && encoded_name[len - 1] != trailer) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } encoded_name[len - 1] = '\0'; @@ -382,30 +387,42 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( "but there's no tdo for [%s] => [%s] \n", log_escape(mem_ctx, r->in.account_name), encoded_name)); - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + nt_status); } nt_status = dsdb_trust_get_incoming_passwords(tdo_msg, mem_ctx, &curNtHash, &prevNtHash); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + nt_status); } flatname = ldb_msg_find_attr_as_string(tdo_msg, "flatName", NULL); if (flatname == NULL) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } *trust_account_for_search = talloc_asprintf(mem_ctx, "%s$", flatname); if (*trust_account_for_search == NULL) { - return NT_STATUS_NO_MEMORY; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_MEMORY); } } else { *trust_account_for_search = r->in.account_name; @@ -420,14 +437,18 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (num_records == 0) { DEBUG(3,("Couldn't find user [%s] in samdb.\n", log_escape(mem_ctx, r->in.account_name))); - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (num_records > 1) { DEBUG(0,("Found %d records matching user [%s]\n", num_records, log_escape(mem_ctx, r->in.account_name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INTERNAL_DB_CORRUPTION); } *trust_account_in_db = ldb_msg_find_attr_as_string(msgs[0], @@ -436,9 +457,18 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (*trust_account_in_db == NULL) { DEBUG(0,("No samAccountName returned in record matching user [%s]\n", r->in.account_name)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INTERNAL_DB_CORRUPTION); } - + + nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_OK); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0); if (user_account_control & UF_ACCOUNTDISABLE) { -- 2.39.0 From ed628f5bf355801023c1bb2ac4aabd06c5c878a6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:13:36 +0100 Subject: [PATCH 119/142] CVE-2022-38023 s4:rpc_server/netlogon: add 'server reject md5 schannel:COMPUTERACCOUNT = no' and 'allow nt4 crypto:COMPUTERACCOUNT = yes' This makes it more flexible when we change the global default to 'reject md5 servers = yes'. 'allow nt4 crypto = no' is already the default. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 69b36541606d7064de9648cd54b35adfdf8f0e8f) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 1c180343252..b605daea794 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -133,12 +133,48 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( struct netr_ServerAuthenticate3 *r, struct netlogon_server_pipe_state *pipe_state, uint32_t negotiate_flags, + const char *trust_account_in_db, NTSTATUS orig_status) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); - bool reject_des_client = !allow_nt4_crypto; - bool reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool account_allow_nt4_crypto = global_allow_nt4_crypto; + const char *explicit_nt4_opt = NULL; + bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + bool account_reject_md5_client = global_reject_md5_client; + const char *explicit_md5_opt = NULL; + bool reject_des_client; + bool allow_nt4_crypto; + bool reject_md5_client; + + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + + if (trust_account_in_db != NULL) { + explicit_nt4_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "allow nt4 crypto", + trust_account_in_db); + } + if (explicit_nt4_opt != NULL) { + account_allow_nt4_crypto = lp_bool(explicit_nt4_opt); + } + allow_nt4_crypto = account_allow_nt4_crypto; + if (trust_account_in_db != NULL) { + explicit_md5_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "server reject md5 schannel", + trust_account_in_db); + } + if (explicit_md5_opt != NULL) { + account_reject_md5_client = lp_bool(explicit_md5_opt); + } + reject_md5_client = account_reject_md5_client; + + reject_des_client = !allow_nt4_crypto; if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { reject_des_client = false; @@ -307,12 +343,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( case SEC_CHAN_NULL: return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_PARAMETER); default: DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", r->in.secure_channel_type)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_PARAMETER); } @@ -325,6 +363,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (sam_ctx == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_SYSTEM_SERVICE); } @@ -356,6 +395,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (encoded_name == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_MEMORY); } @@ -363,12 +403,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (len < 2) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (require_trailer && encoded_name[len - 1] != trailer) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } encoded_name[len - 1] = '\0'; @@ -389,11 +431,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( encoded_name)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ nt_status); } @@ -403,11 +447,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ nt_status); } @@ -415,6 +461,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (flatname == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } @@ -422,6 +469,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (*trust_account_for_search == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_MEMORY); } } else { @@ -439,6 +487,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( log_escape(mem_ctx, r->in.account_name))); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } @@ -448,6 +497,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( log_escape(mem_ctx, r->in.account_name))); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INTERNAL_DB_CORRUPTION); } @@ -459,11 +509,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( r->in.account_name)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INTERNAL_DB_CORRUPTION); } nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + *trust_account_in_db, NT_STATUS_OK); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; -- 2.39.0 From b15c69701d065504588671187a5cec9eea9dcf57 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:31:14 +0100 Subject: [PATCH 120/142] CVE-2022-38023 docs-xml/smbdotconf: document "allow nt4 crypto:COMPUTERACCOUNT = no" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit bd429d025981b445bf63935063e8e302bfab3f9b) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 76 +++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index 06afcef73b1..bbd03a42db7 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -1,11 +1,18 @@ + + This option is deprecated and will be removed in future, + as it is a security problem if not set to "no" (which will be + the hardcoded behavior in future). + + This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will - reject clients which does not support NETLOGON_NEG_STRONG_KEYS + reject clients which do not support NETLOGON_NEG_STRONG_KEYS nor NETLOGON_NEG_SUPPORTS_AES. This option was added with Samba 4.2.0. It may lock out clients @@ -18,8 +25,73 @@ "allow nt4 crypto = yes" allows weak crypto to be negotiated, maybe via downgrade attacks. - This option is over-ridden by the 'reject md5 clients' option. + Avoid using this option! Use explicit 'yes' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240 + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'yes' option + for the client. The message will indicate + the explicit 'yes' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + This allows admins to use "yes" only for a short grace period, + in order to collect the explicit + 'yes' options. + + This option is over-ridden by the 'yes' option. no + + + + + If you still have legacy domain members which required 'allow nt4 crypto = yes', + it is possible to specify an explicit exception per computer account + by using 'allow nt4 crypto:COMPUTERACCOUNT = yes' as option. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "yes", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will log a warning in the log files at log level 5, + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + This option overrides the option. + + This option is over-ridden by the 'yes' option. + + + allow nt4 crypto:LEGACYCOMPUTER1$ = yes + allow nt4 crypto:NASBOX$ = yes + allow nt4 crypto:LEGACYCOMPUTER2$ = yes + + + + -- 2.39.0 From bbc9f54fdc1ebbfc0c27b61aff43a63a16aed9d9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 14:02:11 +0100 Subject: [PATCH 121/142] CVE-2022-38023 docs-xml/smbdotconf: document "server reject md5 schannel:COMPUTERACCOUNT" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 2ad302b42254e3c2800aaf11669fe2e6d55fa8a1) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 13 ++- .../smbdotconf/logon/rejectmd5clients.xml | 96 ++++++++++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index bbd03a42db7..ee63e6cc245 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -45,7 +45,9 @@ in order to collect the explicit 'yes' options. - This option is over-ridden by the 'yes' option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. no @@ -85,12 +87,19 @@ This option overrides the option. - This option is over-ridden by the 'yes' option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + Which means 'yes' + is only useful in combination with 'no' allow nt4 crypto:LEGACYCOMPUTER1$ = yes + server reject md5 schannel:LEGACYCOMPUTER1$ = no allow nt4 crypto:NASBOX$ = yes + server reject md5 schannel:NASBOX$ = no allow nt4 crypto:LEGACYCOMPUTER2$ = yes + server reject md5 schannel:LEGACYCOMPUTER2$ = no diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index edcbe02e99a..fe7701d9277 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -1,8 +1,15 @@ + + This option is deprecated and will be removed in a future release, + as it is a security problem if not set to "yes" (which will be + the hardcoded behavior in the future). + + This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_SUPPORTS_AES. @@ -10,13 +17,94 @@ Support for NETLOGON_NEG_SUPPORTS_AES was added in Windows starting with Server 2008R2 and Windows 7, it's available in Samba starting with 4.0, however third party domain members like NetApp ONTAP - still uses RC4 (HMAC-MD5), see https://www.samba.org/samba/security/CVE-2022-38023.html for more details. + still uses RC4 (HMAC-MD5), see + https://www.samba.org/samba/security/CVE-2022-38023.html + for more details. + + + The default changed from 'no' to 'yes', with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + Avoid using this option! Use an explicit per machine account + '' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + - The default changed from 'no' to 'yes', with the patches for CVE-2022-38023, - see https://bugzilla.samba.org/show_bug.cgi?id=15240 + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + - This option overrides the 'allow nt4 crypto' option. + This allows admins to use "no" only for a short grace period, + in order to collect the explicit + 'no' options. + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'no'. + yes + + + + + If you still have legacy domain members or trusted domains, + which required "reject md5 clients = no" before, + it is possible to specify an explicit exception per computer account + by setting 'server reject md5 schannel:COMPUTERACCOUNT = no'. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "no", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will log a warning in the log files at log level 5 + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + This option overrides the option. + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'no'. + + + + server reject md5 schannel:LEGACYCOMPUTER1$ = no + server reject md5 schannel:NASBOX$ = no + server reject md5 schannel:LEGACYCOMPUTER2$ = no + + + + -- 2.39.0 From 88311bae73bfdd2863ee94f421ef89266bff97f0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:13:36 +0100 Subject: [PATCH 122/142] CVE-2022-38023 s4:rpc_server/netlogon: debug 'reject md5 servers' and 'allow nt4 crypto' misconfigurations This allows the admin to notice what's wrong in order to adjust the configuration if required. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 43df4be35950f491864ae8ada05d51b42a556381) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b605daea794..b93ff08abcd 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -61,10 +61,34 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context const struct dcesrv_interface *iface) { struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; + bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); + static bool warned_global_nt4_once = false; + static bool warned_global_md5_once = false; static bool warned_global_schannel_once = false; + if (global_allow_nt4_crypto && !warned_global_nt4_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023 (and others): " + "Please configure 'allow nt4 crypto = no' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_nt4_once = true; + } + + if (!global_reject_md5_client && !warned_global_md5_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023: " + "Please configure 'reject md5 clients = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_md5_once = true; + } + if (!schannel_global_required && !warned_global_schannel_once) { /* * We want admins to notice their misconfiguration! @@ -146,6 +170,12 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( bool reject_des_client; bool allow_nt4_crypto; bool reject_md5_client; + bool need_des = true; + bool need_md5 = true; + int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); /* * We don't use lpcfg_parm_bool(), as we @@ -177,19 +207,62 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( reject_des_client = !allow_nt4_crypto; if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { + need_des = false; reject_des_client = false; } if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + need_des = false; + need_md5 = false; reject_des_client = false; reject_md5_client = false; } if (reject_des_client || reject_md5_client) { + TALLOC_CTX *frame = talloc_stackframe(); + + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "client_account[%s] computer_name[%s] " + "schannel_type[%u] " + "client_negotiate_flags[0x%x] " + "%s%s%s " + "NT_STATUS_DOWNGRADE_DETECTED " + "reject_des[%u] reject_md5[%u]\n", + log_escape(frame, r->in.account_name), + log_escape(frame, r->in.computer_name), + r->in.secure_channel_type, + (unsigned)*r->in.negotiate_flags, + trust_account_in_db ? "real_account[" : "", + trust_account_in_db ? trust_account_in_db : "", + trust_account_in_db ? "]" : "", + reject_des_client, + reject_md5_client)); + if (trust_account_in_db == NULL) { + goto return_downgrade; + } + + if (reject_md5_client && explicit_md5_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } + if (reject_des_client && explicit_nt4_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } + +return_downgrade: /* * Here we match Windows 2012 and return no flags. */ *r->out.negotiate_flags = 0; + TALLOC_FREE(frame); return NT_STATUS_DOWNGRADE_DETECTED; } @@ -222,6 +295,54 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( */ *r->out.negotiate_flags = negotiate_flags; + if (!NT_STATUS_IS_OK(orig_status) || trust_account_in_db == NULL) { + return orig_status; + } + + if (global_reject_md5_client && account_reject_md5_client && explicit_md5_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = yes' not needed!?\n", + trust_account_in_db); + } else if (need_md5 && !account_reject_md5_client && explicit_md5_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "still needed for a legacy client.\n", + trust_account_in_db); + } else if (need_md5 && explicit_md5_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } else if (!account_reject_md5_client && explicit_md5_opt) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' not needed!?\n", + trust_account_in_db)); + } + + if (!global_allow_nt4_crypto && !account_allow_nt4_crypto && explicit_nt4_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = no' not needed!?\n", + trust_account_in_db); + } else if (need_des && account_allow_nt4_crypto && explicit_nt4_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "still needed for a legacy client.\n", + trust_account_in_db); + } else if (need_des && explicit_nt4_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } else if (account_allow_nt4_crypto && explicit_nt4_opt) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' not needed!?\n", + trust_account_in_db)); + } + return orig_status; } -- 2.39.0 From 73230d08dd1ec2390e52b24f0398d328a55e5866 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:57:20 +0100 Subject: [PATCH 123/142] CVE-2022-38023 selftest:Samba4: avoid global 'allow nt4 crypto = yes' and 'reject md5 clients = no' Instead of using the generic deprecated option use the specific allow nt4 crypto:COMPUTERACCOUNT = yes and server reject md5 schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (backported from commit 7ae3735810c2db32fa50f309f8af3c76ffa29768) --- selftest/target/Samba4.pm | 60 ++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 7e3d7c9de8e..aafb9ee14ca 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1700,7 +1700,6 @@ sub provision_ad_dc_ntvfs($$) my $extra_conf_options = "netbios aliases = localDC1-a server services = +winbind -winbindd ldap server require strong auth = allow_sasl_over_tls - allow nt4 crypto = yes raw NTLMv2 auth = yes lsa over netlogon = yes rpc server port = 1027 @@ -1709,9 +1708,19 @@ sub provision_ad_dc_ntvfs($$) dsdb password event notification = true dsdb group change notification = true - reject md5 clients = no - CVE_2020_1472:warn_about_unused_debug_level = 3 + CVE_2022_38023:warn_about_unused_debug_level = 3 + allow nt4 crypto:torturetest\$ = yes + server reject md5 schannel:schannel2\$ = no + server reject md5 schannel:schannel3\$ = no + server reject md5 schannel:schannel8\$ = no + server reject md5 schannel:schannel9\$ = no + server reject md5 schannel:torturetest\$ = no + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no server require schannel:schannel2\$ = no @@ -1770,6 +1779,13 @@ sub provision_fl2000dc($$) my $extra_conf_options = " spnego:simulate_w2k=yes ntlmssp_server:force_old_spnego=yes + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no "; my $extra_provision_options = ["--use-ntvfs"]; # This environment uses plain text secrets @@ -1818,7 +1834,16 @@ sub provision_fl2003dc($$$) my $extra_conf_options = "allow dns updates = nonsecure and secure dcesrv:header signing = no dcesrv:max auth states = 0 - dns forwarder = 127.0.0.$swiface1 127.0.0.$swiface2"; + dns forwarder = 127.0.0.$swiface1 127.0.0.$swiface2 + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no +"; + my $extra_provision_options = ["--use-ntvfs"]; my $ret = $self->provision($prefix, "domain controller", @@ -1874,8 +1899,18 @@ sub provision_fl2008r2dc($$$) my ($self, $prefix, $dcvars) = @_; print "PROVISIONING DC WITH FOREST LEVEL 2008r2...\n"; - my $extra_conf_options = "ldap server require strong auth = no"; + my $extra_conf_options = " + ldap server require strong auth = no + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no +"; my $extra_provision_options = ["--use-ntvfs"]; + my $ret = $self->provision($prefix, "domain controller", "dc7", @@ -2104,9 +2139,20 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes - reject md5 clients = no - CVE_2020_1472:warn_about_unused_debug_level = 3 + CVE_2022_38023:warn_about_unused_debug_level = 3 + CVE_2022_38023:error_debug_level = 2 + server reject md5 schannel:schannel2\$ = no + server reject md5 schannel:schannel3\$ = no + server reject md5 schannel:schannel8\$ = no + server reject md5 schannel:schannel9\$ = no + server reject md5 schannel:torturetest\$ = no + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:samlogontest\$ = no server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no server require schannel:schannel2\$ = no -- 2.39.0 From 2efdacb36c42985595284db6db90953feecc6e1a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 16:57:24 +0100 Subject: [PATCH 124/142] CVE-2022-38023 s4:rpc_server/netlogon: split out dcesrv_netr_check_schannel() function This will allow us to reuse the function in other places. As it will also get some additional checks soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit f43dc4f0bd60d4e127b714565147f82435aa4f07) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b93ff08abcd..94adb74165f 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -845,18 +845,11 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3); } -/* - * NOTE: The following functions are nearly identical to the ones available in - * source3/rpc_server/srv_nelog_nt.c - * The reason we keep 2 copies is that they use different structures to - * represent the auth_info and the decrpc pipes. - */ -static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) +static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; TALLOC_CTX *frame = talloc_stackframe(); @@ -865,15 +858,11 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; - struct netlogon_creds_CredentialState *creds = NULL; int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; - uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; const char *reason = ""; @@ -881,8 +870,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc opname = ndr_table_netlogon.calls[opnum].name; } - dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; @@ -895,17 +882,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc reason = "WITHOUT"; } - nt_status = schannel_check_creds_state(mem_ctx, - lp_ctx, - computer_name, - received_authenticator, - return_authenticator, - &creds); - if (!NT_STATUS_IS_OK(nt_status)) { - ZERO_STRUCTP(return_authenticator); - return nt_status; - } - /* * We don't use lpcfg_parm_bool(), as we * need the explicit_opt pointer in order to @@ -945,7 +921,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return nt_status; } @@ -979,8 +954,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); return nt_status; } @@ -1024,11 +997,56 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return NT_STATUS_OK; } +/* + * NOTE: The following functions are nearly identical to the ones available in + * source3/rpc_server/srv_nelog_nt.c + * The reason we keep 2 copies is that they use different structures to + * represent the auth_info and the decrpc pipes. + */ +static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + NTSTATUS nt_status; + struct netlogon_creds_CredentialState *creds = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + + dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); + + nt_status = schannel_check_creds_state(mem_ctx, + dce_call->conn->dce_ctx->lp_ctx, + computer_name, + received_authenticator, + return_authenticator, + &creds); + if (!NT_STATUS_IS_OK(nt_status)) { + ZERO_STRUCTP(return_authenticator); + return nt_status; + } + + nt_status = dcesrv_netr_check_schannel(dce_call, + creds, + auth_type, + auth_level, + dce_call->pkt.u.request.opnum); + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return nt_status; + } + + *creds_out = creds; + return NT_STATUS_OK; +} + /* Change the machine account password for the currently connected client. Supplies only the NT#. -- 2.39.0 From b95d07ebad63544c585a43590bdeaf5247cbaf46 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 17:15:36 +0100 Subject: [PATCH 125/142] CVE-2022-38023 s4:rpc_server/netlogon: make sure all dcesrv_netr_LogonSamLogon*() calls go through dcesrv_netr_check_schannel() We'll soon add some additional contraints in dcesrv_netr_check_schannel(), which are also required for dcesrv_netr_LogonSamLogonEx(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 689507457f5e6666488732f91a355a2183fb1662) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 94adb74165f..f4413d7a03b 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -1408,6 +1408,35 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL struct auth_usersupplied_info *user_info = NULL; NTSTATUS nt_status; struct tevent_req *subreq = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + + dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); + + switch (dce_call->pkt.u.request.opnum) { + case NDR_NETR_LOGONSAMLOGON: + case NDR_NETR_LOGONSAMLOGONWITHFLAGS: + /* + * These already called dcesrv_netr_check_schannel() + * via dcesrv_netr_creds_server_step_check() + */ + break; + case NDR_NETR_LOGONSAMLOGONEX: + default: + if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_ACCESS_DENIED; + } + + nt_status = dcesrv_netr_check_schannel(dce_call, + creds, + auth_type, + auth_level, + dce_call->pkt.u.request.opnum); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + break; + } *r->out.authoritative = 1; @@ -1739,7 +1768,6 @@ static void dcesrv_netr_LogonSamLogon_base_reply( static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_LogonSamLogonEx *r) { - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; struct dcesrv_netr_LogonSamLogon_base_state *state; NTSTATUS nt_status; @@ -1777,12 +1805,6 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, return nt_status; } - dcesrv_call_auth_info(dce_call, &auth_type, NULL); - - if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - return NT_STATUS_ACCESS_DENIED; - } - nt_status = dcesrv_netr_LogonSamLogon_base_call(state); if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { -- 2.39.0 From 5e5019dbdf9b49e07bd5f88bafa7275d5d076166 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 16:53:35 +0100 Subject: [PATCH 126/142] CVE-2022-38023 docs-xml/smbdotconf: add "server schannel require seal[:COMPUTERACCOUNT]" options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 7732a4b0bde1d9f98a0371f17d22648495329470) --- .../smbdotconf/security/serverschannel.xml | 43 ++++++- .../security/serverschannelrequireseal.xml | 118 ++++++++++++++++++ lib/param/loadparm.c | 1 + source3/param/loadparm.c | 1 + 4 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 docs-xml/smbdotconf/security/serverschannelrequireseal.xml diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index 3e66df1c203..42a657912ca 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -12,19 +12,37 @@ the hardcoded behavior in future). - - Samba will complain in the log files at log level 0, - about the security problem if the option is not set to "yes". + Avoid using this option! Use explicit 'no' instead! + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + - See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + This allows admins to use "auto" only for a short grace period, + in order to collect the explicit + 'no' options. - If you still have legacy domain members use the option. + + See CVE-2020-1472(ZeroLogon), + https://bugzilla.samba.org/show_bug.cgi?id=14497. This option is over-ridden by the option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + yes @@ -48,6 +66,9 @@ about the security problem if the option is not set to "no", but the related computer is actually using the netlogon secure channel (schannel) feature. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). @@ -56,15 +77,25 @@ - See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + See CVE-2020-1472(ZeroLogon), + https://bugzilla.samba.org/show_bug.cgi?id=14497. This option overrides the option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + Which means 'no' + is only useful in combination with 'no' + server require schannel:LEGACYCOMPUTER1$ = no + server require schannel seal:LEGACYCOMPUTER1$ = no server require schannel:NASBOX$ = no + server require schannel seal:NASBOX$ = no server require schannel:LEGACYCOMPUTER2$ = no + server require schannel seal:LEGACYCOMPUTER2$ = no diff --git a/docs-xml/smbdotconf/security/serverschannelrequireseal.xml b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml new file mode 100644 index 00000000000..d4620d1252d --- /dev/null +++ b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml @@ -0,0 +1,118 @@ + + + + + This option is deprecated and will be removed in future, + as it is a security problem if not set to "yes" (which will be + the hardcoded behavior in future). + + + + This option controls whether the netlogon server (currently + only in 'active directory domain controller' mode), will + reject the usage of netlogon secure channel without privacy/enryption. + + + + The option is modelled after the registry key available on Windows. + + + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\RequireSeal=2 + + + + Avoid using this option! Use the per computer account specific option + '' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + This allows admins to use "no" only for a short grace period, + in order to collect the explicit + 'no' options. + + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'yes'. + + + + This option is over-ridden by the option. + + + + +yes + + + + + + + If you still have legacy domain members, which required "server schannel require seal = no" before, + it is possible to specify explicit exception per computer account + by using 'server schannel require seal:COMPUTERACCOUNT = no' as option. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "no", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will warn in the log files at log level 5, + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + + This option overrides the '' option. + + + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'yes'. + + + + server require schannel seal:LEGACYCOMPUTER1$ = no + server require schannel seal:NASBOX$ = no + server require schannel seal:LEGACYCOMPUTER2$ = no + + + + diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 77a80176f7d..4b3976ebdb6 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2790,6 +2790,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind nss info", "template"); lpcfg_do_global_parameter(lp_ctx, "server schannel", "True"); + lpcfg_do_global_parameter(lp_ctx, "server schannel require seal", "True"); lpcfg_do_global_parameter(lp_ctx, "reject md5 clients", "True"); lpcfg_do_global_parameter(lp_ctx, "short preserve case", "True"); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 1cf468b1009..8dab202fc17 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -659,6 +659,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.require_strong_key = true; Globals.reject_md5_servers = true; Globals.server_schannel = true; + Globals.server_schannel_require_seal = true; Globals.reject_md5_clients = true; Globals.read_raw = true; Globals.write_raw = true; -- 2.39.0 From 83be39efadc4c4fad4a873e23016e1c5a8d65380 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 2 Dec 2022 14:31:26 +0100 Subject: [PATCH 127/142] CVE-2022-38023 s4:rpc_server/netlogon: add a per connection cache to dcesrv_netr_check_schannel() It's enough to warn the admin once per connection. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 3c57608e1109c1d6e8bb8fbad2ef0b5d79d00e1a) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 193 ++++++++++++++---- 1 file changed, 153 insertions(+), 40 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index f4413d7a03b..474d0806e6b 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -845,23 +845,105 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3); } -static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, - const struct netlogon_creds_CredentialState *creds, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, - uint16_t opnum) +struct dcesrv_netr_check_schannel_state { + struct dom_sid account_sid; + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + + bool schannel_global_required; + bool schannel_required; + bool schannel_explicitly_set; + + NTSTATUS result; +}; + +static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + struct dcesrv_netr_check_schannel_state **_s) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS nt_status; int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; +#define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1) + struct dcesrv_netr_check_schannel_state *s = NULL; + NTSTATUS status; + + *_s = NULL; + + s = dcesrv_iface_state_find_conn(dce_call, + DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, + struct dcesrv_netr_check_schannel_state); + if (s != NULL) { + if (!dom_sid_equal(&s->account_sid, creds->sid)) { + goto new_state; + } + if (s->auth_type != auth_type) { + goto new_state; + } + if (s->auth_level != auth_level) { + goto new_state; + } + + *_s = s; + return NT_STATUS_OK; + } + +new_state: + TALLOC_FREE(s); + s = talloc_zero(dce_call, + struct dcesrv_netr_check_schannel_state); + if (s == NULL) { + return NT_STATUS_NO_MEMORY; + } + + s->account_sid = *creds->sid; + s->auth_type = auth_type; + s->auth_level = auth_level; + s->result = NT_STATUS_MORE_PROCESSING_REQUIRED; + + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + explicit_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "server require schannel", + creds->account_name); + if (explicit_opt != NULL) { + schannel_required = lp_bool(explicit_opt); + } + + s->schannel_global_required = schannel_global_required; + s->schannel_required = schannel_required; + s->schannel_explicitly_set = explicit_opt != NULL; + + status = dcesrv_iface_state_store_conn(dce_call, + DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, + s); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *_s = s; + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_call, + struct dcesrv_netr_check_schannel_state *s, + const struct netlogon_creds_CredentialState *creds, + uint16_t opnum) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + TALLOC_CTX *frame = talloc_stackframe(); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; @@ -870,37 +952,43 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname = ndr_table_netlogon.calls[opnum].name; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; - } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + } else if (s->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { reason = "WITH SIGNED"; } else { - smb_panic("Schannel without SIGN/SEAL"); + reason = "WITH INVALID"; + dbg_lvl = DBGLVL_ERR; + s->result = NT_STATUS_INTERNAL_ERROR; } } else { reason = "WITHOUT"; } - /* - * We don't use lpcfg_parm_bool(), as we - * need the explicit_opt pointer in order to - * adjust the debug messages. - */ - explicit_opt = lpcfg_get_parametric(lp_ctx, - NULL, - "server require schannel", - creds->account_name); - if (explicit_opt != NULL) { - schannel_required = lp_bool(explicit_opt); + if (!NT_STATUS_EQUAL(s->result, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (!NT_STATUS_IS_OK(s->result)) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + TALLOC_FREE(frame); + return s->result; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - nt_status = NT_STATUS_OK; + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + s->result = NT_STATUS_OK; - if (explicit_opt != NULL && !schannel_required) { + if (s->schannel_explicitly_set && !s->schannel_required) { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); - } else if (!schannel_required) { + } else if (!s->schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } @@ -911,9 +999,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); - - if (explicit_opt != NULL && !schannel_required) { + nt_errstr(s->result))); + if (s->schannel_explicitly_set && !s->schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed for '%s'!\n", @@ -922,13 +1009,13 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, } TALLOC_FREE(frame); - return nt_status; + return s->result; } - if (schannel_required) { - nt_status = NT_STATUS_ACCESS_DENIED; + if (s->schannel_required) { + s->result = NT_STATUS_ACCESS_DENIED; - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -941,8 +1028,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); - if (explicit_opt != NULL) { + nt_errstr(s->result))); + if (s->schannel_explicitly_set) { D_NOTICE("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = yes' " "rejects access for client.\n", @@ -955,12 +1042,12 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, log_escape(frame, creds->account_name))); } TALLOC_FREE(frame); - return nt_status; + return s->result; } - nt_status = NT_STATUS_OK; + s->result = NT_STATUS_OK; - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -973,9 +1060,9 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); + nt_errstr(s->result))); - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " "still needed for '%s'!\n", @@ -998,6 +1085,32 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, } TALLOC_FREE(frame); + return s->result; +} + +static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) +{ + struct dcesrv_netr_check_schannel_state *s = NULL; + NTSTATUS status; + + status = dcesrv_netr_check_schannel_get_state(dce_call, + creds, + auth_type, + auth_level, + &s); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcesrv_netr_check_schannel_once(dce_call, s, creds, opnum); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return NT_STATUS_OK; } -- 2.39.0 From ef51add9def64d75f17b394924c238fffc81168f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 14:05:30 +0100 Subject: [PATCH 128/142] CVE-2022-38023 s4:rpc_server/netlogon: implement "server schannel require seal[:COMPUTERACCOUNT]" By default we'll now require schannel connections with privacy/sealing/encryption. But we allow exceptions for specific computer/trust accounts. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b3ed90a0541a271a7c6d4bee1201fa47adc3c0c1) --- selftest/target/Samba4.pm | 27 ++ source4/rpc_server/netlogon/dcerpc_netlogon.c | 244 +++++++++++++++++- 2 files changed, 270 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index aafb9ee14ca..c267b81d865 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1734,9 +1734,23 @@ sub provision_ad_dc_ntvfs($$) server require schannel:schannel10\$ = no server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no # needed for 'samba.tests.auth_log' tests server require schannel:LOCALDC\$ = no + server schannel require seal:LOCALDC\$ = no "; my $extra_provision_options = ["--use-ntvfs"]; my $ret = $self->provision($prefix, @@ -2166,6 +2180,19 @@ sub provision_ad_dc($$$$$$) server require schannel:schannel10\$ = no server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no auth event notification = true dsdb event notification = true diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 474d0806e6b..343cd53473c 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -65,9 +65,11 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); + bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx); static bool warned_global_nt4_once = false; static bool warned_global_md5_once = false; static bool warned_global_schannel_once = false; + static bool warned_global_seal_once = false; if (global_allow_nt4_crypto && !warned_global_nt4_once) { /* @@ -99,6 +101,16 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context warned_global_schannel_once = true; } + if (!global_require_seal && !warned_global_seal_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023 (and others): " + "Please configure 'server schannel require seal = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_once = true; + } + return dcesrv_interface_bind_reject_connect(context, iface); } @@ -854,6 +866,10 @@ struct dcesrv_netr_check_schannel_state { bool schannel_required; bool schannel_explicitly_set; + bool seal_global_required; + bool seal_required; + bool seal_explicitly_set; + NTSTATUS result; }; @@ -868,6 +884,9 @@ static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *d bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; + bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx); + bool require_seal = global_require_seal; + const char *explicit_seal_opt = NULL; #define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1) struct dcesrv_netr_check_schannel_state *s = NULL; NTSTATUS status; @@ -905,6 +924,19 @@ new_state: s->auth_level = auth_level; s->result = NT_STATUS_MORE_PROCESSING_REQUIRED; + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + explicit_seal_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "server schannel require seal", + creds->account_name); + if (explicit_seal_opt != NULL) { + require_seal = lp_bool(explicit_seal_opt); + } + /* * We don't use lpcfg_parm_bool(), as we * need the explicit_opt pointer in order to @@ -922,6 +954,10 @@ new_state: s->schannel_required = schannel_required; s->schannel_explicitly_set = explicit_opt != NULL; + s->seal_global_required = global_require_seal; + s->seal_required = require_seal; + s->seal_explicitly_set = explicit_seal_opt != NULL; + status = dcesrv_iface_state_store_conn(dce_call, DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, s); @@ -943,6 +979,10 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); TALLOC_CTX *frame = talloc_stackframe(); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; @@ -972,18 +1012,107 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } DEBUG(dbg_lvl, ( - "CVE-2020-1472(ZeroLogon): " + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + TALLOC_FREE(frame); + return s->result; + } + + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL && + s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) + { + s->result = NT_STATUS_OK; + + if (s->schannel_explicitly_set && !s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + if (s->seal_explicitly_set && !s->seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } else if (!s->seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " "%s request (opnum[%u]) %s schannel from " "client_account[%s] client_computer_name[%s] %s\n", opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(s->result))); + + if (s->schannel_explicitly_set && !s->schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + if (s->seal_explicitly_set && !s->seal_required) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); return s->result; } if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (s->seal_required) { + s->result = NT_STATUS_ACCESS_DENIED; + + if (s->seal_explicitly_set) { + dbg_lvl = DBGLVL_NOTICE; + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (s->schannel_explicitly_set && !s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (s->schannel_explicitly_set && !s->schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); + return s->result; + } + s->result = NT_STATUS_OK; if (s->schannel_explicitly_set && !s->schannel_required) { @@ -991,6 +1120,11 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } else if (!s->schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + if (s->seal_explicitly_set && !s->seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else if (!s->seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon): " @@ -1007,11 +1141,81 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name))); } + if (s->seal_explicitly_set && !s->seal_required) { + D_INFO("CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else if (!s->seal_required) { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "Please use 'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } TALLOC_FREE(frame); return s->result; } + if (s->seal_required) { + s->result = NT_STATUS_ACCESS_DENIED; + + if (s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (!s->schannel_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } else if (s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (!s->schannel_explicitly_set) { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } else if (s->schannel_required) { + D_NOTICE("CVE-2022-38023: Option " + "'server require schannel:%s = yes' " + "also rejects access for client.\n", + log_escape(frame, creds->account_name)); + } + TALLOC_FREE(frame); + return s->result; + } + if (s->schannel_required) { s->result = NT_STATUS_ACCESS_DENIED; @@ -1020,6 +1224,9 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); } + if (!s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " @@ -1041,12 +1248,25 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } + if (!s->seal_explicitly_set) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(frame); return s->result; } s->result = NT_STATUS_OK; + if (s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { @@ -1062,6 +1282,28 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca log_escape(frame, creds->computer_name), nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_INFO("CVE-2022-38023: Option " + "'server schannel require seal:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Please use " + "'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + if (s->schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " -- 2.39.0 From fe38dc0186d3505db4c105f78dc46c2270c43240 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 15:13:47 +0100 Subject: [PATCH 129/142] CVE-2022-38023 testparm: warn about server/client schannel != yes BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit f964c0c357214637f80d0089723b9b11d1b38f7e) --- source3/utils/testparm.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index c673ef71a92..aa990b729d7 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -522,6 +522,27 @@ static int do_global_checks(void) ret = 1; } + if (lp_server_schannel() != true) { /* can be 'auto' */ + fprintf(stderr, + "WARNING: You have not configured " + "'server schannel = yes' (the default). " + "Your server is vulernable to \"ZeroLogon\" " + "(CVE-2020-1472)\n" + "If required use individual " + "'server require schannel:COMPUTERACCOUNT$ = no' " + "options\n\n"); + } + if (lp_client_schannel() != true) { /* can be 'auto' */ + fprintf(stderr, + "WARNING: You have not configured " + "'client schannel = yes' (the default). " + "Your server is vulernable to \"ZeroLogon\" " + "(CVE-2020-1472)\n" + "If required use individual " + "'client schannel:NETBIOSDOMAIN = no' " + "options\n\n"); + } + return ret; } -- 2.39.0 From c870a61377d0245a3fd25f5d5c8663d965fe469a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Dec 2022 13:36:17 +0100 Subject: [PATCH 130/142] CVE-2022-38023 testparm: warn about unsecure schannel related options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 4d540473c3d43d048a30dd63efaeae9ff87b2aeb) --- source3/utils/testparm.c | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index aa990b729d7..f9253d323aa 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -532,6 +532,37 @@ static int do_global_checks(void) "'server require schannel:COMPUTERACCOUNT$ = no' " "options\n\n"); } + if (lp_allow_nt4_crypto()) { + fprintf(stderr, + "WARNING: You have not configured " + "'allow nt4 crypto = no' (the default). " + "Your server is vulernable to " + "CVE-2022-38023 and others!\n" + "If required use individual " + "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' " + "options\n\n"); + } + if (!lp_reject_md5_clients()) { + fprintf(stderr, + "WARNING: You have not configured " + "'reject md5 clients = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023!\n" + "If required use individual " + "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' " + "options\n\n"); + } + if (!lp_server_schannel_require_seal()) { + fprintf(stderr, + "WARNING: You have not configured " + "'server schannel require seal = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023!\n" + "If required use individual " + "'server schannel require seal:COMPUTERACCOUNT$ = no' " + "options\n\n"); + } + if (lp_client_schannel() != true) { /* can be 'auto' */ fprintf(stderr, "WARNING: You have not configured " @@ -542,6 +573,36 @@ static int do_global_checks(void) "'client schannel:NETBIOSDOMAIN = no' " "options\n\n"); } + if (!lp_reject_md5_servers()) { + fprintf(stderr, + "WARNING: You have not configured " + "'reject md5 servers = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'reject md5 servers:NETBIOSDOMAIN = no' " + "options\n\n"); + } + if (!lp_require_strong_key()) { + fprintf(stderr, + "WARNING: You have not configured " + "'require strong key = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'require strong key:NETBIOSDOMAIN = no' " + "options\n\n"); + } + if (!lp_winbind_sealed_pipes()) { + fprintf(stderr, + "WARNING: You have not configured " + "'winbind sealed pipes = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'winbind sealed pipes:NETBIOSDOMAIN = no' " + "options\n\n"); + } return ret; } -- 2.39.0 From 938168a5f7c3225562ed772bf8a9bbecc0badb62 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 12 Sep 2022 16:31:05 +0200 Subject: [PATCH 131/142] s3:auth: Flush the GETPWSID in memory cache for NTLM auth Example valgrind output: ==22502== 22,747,002 bytes in 21,049 blocks are possibly lost in loss record 1,075 of 1,075 ==22502== at 0x4C29F73: malloc (vg_replace_malloc.c:309) ==22502== by 0x11D7089C: _talloc_pooled_object (in /usr/lib64/libtalloc.so.2.1.16) ==22502== by 0x9027834: tcopy_passwd (in /usr/lib64/libsmbconf.so.0) ==22502== by 0x6A1E1A3: pdb_copy_sam_account (in /usr/lib64/libsamba-passdb.so.0.27.2) ==22502== by 0x6A28AB7: pdb_getsampwnam (in /usr/lib64/libsamba-passdb.so.0.27.2) ==22502== by 0x65D0BC4: check_sam_security (in /usr/lib64/samba/libauth-samba4.so) ==22502== by 0x65C70F0: ??? (in /usr/lib64/samba/libauth-samba4.so) ==22502== by 0x65C781A: auth_check_ntlm_password (in /usr/lib64/samba/libauth-samba4.so) ==22502== by 0x14E464: ??? (in /usr/sbin/winbindd) ==22502== by 0x151CED: winbind_dual_SamLogon (in /usr/sbin/winbindd) ==22502== by 0x152072: winbindd_dual_pam_auth_crap (in /usr/sbin/winbindd) ==22502== by 0x167DE0: ??? (in /usr/sbin/winbindd) ==22502== by 0x12F29B12: tevent_common_invoke_fd_handler (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F30086: ??? (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F2E056: ??? (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F2925C: _tevent_loop_once (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x16A243: ??? (in /usr/sbin/winbindd) ==22502== by 0x16AA04: ??? (in /usr/sbin/winbindd) ==22502== by 0x12F29F68: tevent_common_invoke_immediate_handler (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F29F8F: tevent_common_loop_immediate (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F2FE3C: ??? (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F2E056: ??? (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F2925C: _tevent_loop_once (in /usr/lib64/libtevent.so.0.9.39) ==22502== by 0x12F4C7: main (in /usr/sbin/winbindd) You can find one for each string in pdb_copy_sam_account(), in total this already has 67 MB in total for this valgrind run. pdb_getsampwnam() -> memcache_add_talloc(NULL, PDB_GETPWSID_CACHE, ...) BUG: https://bugzilla.samba.org/show_bug.cgi?id=15169 Signed-off-by: Andreas Schneider Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Sep 16 20:30:31 UTC 2022 on sn-devel-184 (cherry picked from commit 9ef2f7345f0d387567fca598cc7008af95598903) --- source3/auth/check_samsec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source3/auth/check_samsec.c b/source3/auth/check_samsec.c index 53b6da53dc1..4276c3060ed 100644 --- a/source3/auth/check_samsec.c +++ b/source3/auth/check_samsec.c @@ -24,6 +24,7 @@ #include "auth.h" #include "../libcli/auth/libcli_auth.h" #include "passdb.h" +#include "lib/util/memcache.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH @@ -487,8 +488,6 @@ NTSTATUS check_sam_security(const DATA_BLOB *challenge, nt_status = make_server_info_sam(mem_ctx, sampass, server_info); unbecome_root(); - TALLOC_FREE(sampass); - if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status))); goto done; @@ -507,6 +506,11 @@ NTSTATUS check_sam_security(const DATA_BLOB *challenge, (*server_info)->nss_token |= user_info->was_mapped; done: + /* + * Always flush the getpwsid cache or this will grow indefinetly for + * each NTLM auththentication. + */ + memcache_flush(NULL, PDB_GETPWSID_CACHE); TALLOC_FREE(sampass); data_blob_free(&user_sess_key); data_blob_free(&lm_sess_key); -- 2.39.0 From 296612a8c1dda253e1f2c0618f1f8330e2e23b34 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 16:46:15 +0100 Subject: [PATCH 132/142] CVE-2022-38023 selftest:Samba3: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 3cd18690f83d2f85e847fc703ac127b4b04189fc) --- selftest/target/Samba3.pm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 7034127ef0b..0c14f02be11 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -199,7 +199,6 @@ sub setup_nt4_dc lanman auth = yes ntlm auth = yes raw NTLMv2 auth = yes - server schannel = auto rpc_server:epmapper = external rpc_server:spoolss = external @@ -213,6 +212,22 @@ sub setup_nt4_dc rpc_daemon:spoolssd = fork rpc_daemon:lsasd = fork rpc_daemon:fssd = fork + + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + fss: sequence timeout = 1 check parent directory delete on close = yes "; -- 2.39.0 From 1a90fc7cbc4054f9815ffaca710b5bdba0dffd6f Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:33:12 +0100 Subject: [PATCH 133/142] CVE-2022-38023 s3:rpc_server/netlogon: add talloc_stackframe() to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 38 ++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 7f6704adbda..f9b674d0052 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1071,6 +1071,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { + TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; @@ -1092,19 +1093,19 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, auth_type = p->auth.auth_type; - lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); + TALLOC_FREE(frame); return NT_STATUS_INTERNAL_ERROR; } status = schannel_check_creds_state(mem_ctx, lp_ctx, computer_name, received_authenticator, return_authenticator, &creds); - talloc_unlink(mem_ctx, lp_ctx); - if (!NT_STATUS_IS_OK(status)) { ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return status; } @@ -1125,6 +1126,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -1132,13 +1134,15 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' is needed! \n", - log_escape(mem_ctx, creds->account_name)); + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } @@ -1157,13 +1161,14 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%s request (opnum[%u]) WITH schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -1172,24 +1177,25 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_INFO("CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' still needed!\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); } else { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " "'server require schannel:%s = no' might be needed!\n", - log_escape(mem_ctx, creds->account_name)); + log_escape(frame, creds->account_name)); } *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } -- 2.39.0 From d3e503e670501186fcce9702b72cda3b03afc0cf Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 21 Dec 2022 18:17:57 +0100 Subject: [PATCH 134/142] CVE-2022-38023 s3:rpc_server/netlogon: re-order checking in netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index f9b674d0052..b42794eea8d 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1123,13 +1123,27 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, schannel_required = lp_bool(explicit_opt); } - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (!schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) WITH schannel from " + "client_account[%s] client_computer_name[%s]\n", + opname, opnum, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } + if (explicit_opt != NULL && !schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(frame, creds->account_name)); } + *creds_out = creds; + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (schannel_required) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", @@ -1156,22 +1170,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, warned_global_once = true; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) WITH schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); - - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; - } - if (explicit_opt != NULL) { DBG_INFO("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " -- 2.39.0 From 44de3ae0d4b6f1a728124429dfc748c538714a05 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:35:57 +0100 Subject: [PATCH 135/142] CVE-2022-38023 s3:rpc_server/netlogon: improve CVE-2020-1472(ZeroLogon) debug messages In order to avoid generating useless debug messages during make test, we will use 'CVE_2020_1472:warn_about_unused_debug_level = 3' and 'CVE_2020_1472:error_debug_level = 2' in order to avoid schannel warnings. Review with: git show -w BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 149 ++++++++++++++------ 1 file changed, 109 insertions(+), 40 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index b42794eea8d..1d261c9a639 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1078,9 +1078,14 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, const char *explicit_opt = NULL; struct loadparm_context *lp_ctx; struct netlogon_creds_CredentialState *creds = NULL; + int CVE_2020_1472_warn_level = DBGLVL_ERR; + int CVE_2020_1472_error_level = DBGLVL_ERR; + unsigned int dbg_lvl = DBGLVL_DEBUG; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; uint16_t opnum = p->opnum; const char *opname = ""; + const char *reason = ""; static bool warned_global_once = false; if (creds_out != NULL) { @@ -1092,6 +1097,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, } auth_type = p->auth.auth_type; + auth_level = p->auth.auth_level; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { @@ -1100,6 +1106,23 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, return NT_STATUS_INTERNAL_ERROR; } + CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + reason = "WITH SEALED"; + } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + reason = "WITH SIGNED"; + } else { + smb_panic("Schannel without SIGN/SEAL"); + } + } else { + reason = "WITHOUT"; + } + status = schannel_check_creds_state(mem_ctx, lp_ctx, computer_name, received_authenticator, return_authenticator, &creds); @@ -1124,40 +1147,69 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, } if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (!schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) WITH schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); + status = NT_STATUS_OK; + + if (explicit_opt != NULL && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (explicit_opt != NULL && !schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; TALLOC_FREE(frame); - return NT_STATUS_OK; + return status; } if (schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' " - "might be needed for a legacy client.\n", - log_escape(frame, creds->account_name)); + status = NT_STATUS_ACCESS_DENIED; + + if (explicit_opt != NULL) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (explicit_opt != NULL) { + D_NOTICE("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); - return NT_STATUS_ACCESS_DENIED; + return status; } if (!schannel_global_required && !warned_global_once) { @@ -1170,26 +1222,43 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, warned_global_once = true; } + status = NT_STATUS_OK; + if (explicit_opt != NULL) { - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' still needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' might be needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + + if (explicit_opt != NULL) { + D_INFO("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server require schannel:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): " + "Please use 'server require schannel:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; -- 2.39.0 From 7e0bfe3db2b4d274b3bf2e5f011ae8207ce6f4ab Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 21 Dec 2022 18:37:05 +0100 Subject: [PATCH 136/142] CVE-2022-38023 selftest:Samba3: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- selftest/target/Samba3.pm | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 0c14f02be11..e8a4c3bbbb6 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -140,7 +140,7 @@ sub getlog_env_app($$$) close(LOG); return "" if $out eq $title; - + return $out; } @@ -200,6 +200,21 @@ sub setup_nt4_dc ntlm auth = yes raw NTLMv2 auth = yes + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + rpc_server:epmapper = external rpc_server:spoolss = external rpc_server:lsarpc = external @@ -1588,7 +1603,7 @@ sub provision($$$$$$$$$) my $nmbdsockdir="$prefix_abs/nmbd"; unlink($nmbdsockdir); - ## + ## ## create the test directory layout ## die ("prefix_abs = ''") if $prefix_abs eq ""; @@ -2393,7 +2408,7 @@ sub provision($$$$$$$$$) unless (open(PASSWD, ">$nss_wrapper_passwd")) { warn("Unable to open $nss_wrapper_passwd"); return undef; - } + } print PASSWD "nobody:x:$uid_nobody:$gid_nobody:nobody gecos:$prefix_abs:/bin/false $unix_name:x:$unix_uid:$unix_gids[0]:$unix_name gecos:$prefix_abs:/bin/false pdbtest:x:$uid_pdbtest:$gid_nogroup:pdbtest gecos:$prefix_abs:/bin/false -- 2.39.0 From 340bdcc92d979eb67d67e2a2d8056f939a011f37 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:42:51 +0100 Subject: [PATCH 137/142] CVE-2022-38023 s3:rpc_server/netlogon: split out netr_check_schannel() function This will allow us to reuse the function in other places. As it will also get some additional checks soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 107 ++++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 1d261c9a639..eb364eaf29a 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1064,53 +1064,30 @@ NTSTATUS _netr_ServerAuthenticate2(struct pipes_struct *p, /************************************************************************* *************************************************************************/ -static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) +static NTSTATUS netr_check_schannel(struct pipes_struct *p, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) { TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; - struct loadparm_context *lp_ctx; - struct netlogon_creds_CredentialState *creds = NULL; - int CVE_2020_1472_warn_level = DBGLVL_ERR; - int CVE_2020_1472_error_level = DBGLVL_ERR; + int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; - uint16_t opnum = p->opnum; const char *opname = ""; const char *reason = ""; static bool warned_global_once = false; - if (creds_out != NULL) { - *creds_out = NULL; - } - if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; } - auth_type = p->auth.auth_type; - auth_level = p->auth.auth_level; - - lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - TALLOC_FREE(frame); - return NT_STATUS_INTERNAL_ERROR; - } - - CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, - "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); - CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, - "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; @@ -1123,15 +1100,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, reason = "WITHOUT"; } - status = schannel_check_creds_state(mem_ctx, lp_ctx, - computer_name, received_authenticator, - return_authenticator, &creds); - if (!NT_STATUS_IS_OK(status)) { - ZERO_STRUCTP(return_authenticator); - TALLOC_FREE(frame); - return status; - } - /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to @@ -1172,7 +1140,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return status; } @@ -1206,8 +1173,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); return status; } @@ -1261,11 +1226,63 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return NT_STATUS_OK; } +static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + struct loadparm_context *lp_ctx = NULL; + NTSTATUS status; + struct netlogon_creds_CredentialState *creds = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + uint16_t opnum = p->opnum; + + if (creds_out != NULL) { + *creds_out = NULL; + } + + auth_type = p->auth.auth_type; + auth_level = p->auth.auth_level; + + lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); + if (lp_ctx == NULL) { + DEBUG(0, ("loadparm_init_s3 failed\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + status = schannel_check_creds_state(mem_ctx, + lp_ctx, + computer_name, + received_authenticator, + return_authenticator, + &creds); + TALLOC_FREE(lp_ctx); + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCTP(return_authenticator); + return status; + } + + status = netr_check_schannel(p, + creds, + auth_type, + auth_level, + opnum); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return status; + } + + *creds_out = creds; + return NT_STATUS_OK; +} /************************************************************************* *************************************************************************/ -- 2.39.0 From 8b52bfc3bb274d7d1607b505c18b4ccafe25cad7 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 09:29:04 +0100 Subject: [PATCH 138/142] CVE-2022-38023 s3:rpc_server/netlogon: make sure all dcesrv_netr_LogonSamLogon*() calls go through netr_check_schannel() We'll soon add some additional contraints in dcesrv_netr_check_schannel(), which are also required for dcesrv_netr_LogonSamLogonEx(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 30 ++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index eb364eaf29a..ca343d3e28a 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1766,6 +1766,8 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, struct auth_serversupplied_info *server_info = NULL; struct auth_context *auth_context = NULL; const char *fn; + enum dcerpc_AuthType auth_type = p->auth.auth_type; + enum dcerpc_AuthLevel auth_level = p->auth.auth_level; #ifdef DEBUG_PASSWORD logon = netlogon_creds_shallow_copy_logon(p->mem_ctx, @@ -1779,11 +1781,32 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, switch (p->opnum) { case NDR_NETR_LOGONSAMLOGON: fn = "_netr_LogonSamLogon"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONWITHFLAGS: fn = "_netr_LogonSamLogonWithFlags"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONEX: + if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_ACCESS_DENIED; + } + + status = netr_check_schannel(p, + creds, + auth_type, + auth_level, + p->opnum); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + fn = "_netr_LogonSamLogonEx"; break; default: @@ -2123,13 +2146,6 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, return status; } - /* Only allow this if the pipe is protected. */ - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_netr_LogonSamLogonEx: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); -- 2.39.0 From 43dca97088ce82a5e346887b8078f346e8249929 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:23:41 +0100 Subject: [PATCH 139/142] CVE-2022-38023 s3:rpc_server/netlogon: Rename variable This will simplify the following changes. Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index ca343d3e28a..5500a421334 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1072,9 +1072,10 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, { TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; + const char *explicit_opt = NULL; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; - const char *explicit_opt = NULL; + bool schannel_explicitly_set = false; int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, @@ -1113,11 +1114,12 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, if (explicit_opt != NULL) { schannel_required = lp_bool(explicit_opt); } + schannel_explicitly_set = explicit_opt != NULL; if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { status = NT_STATUS_OK; - if (explicit_opt != NULL && !schannel_required) { + if (schannel_explicitly_set && !schannel_required) { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); } else if (!schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); @@ -1132,7 +1134,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL && !schannel_required) { + if (schannel_explicitly_set && !schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed for '%s'!\n", @@ -1147,7 +1149,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, if (schannel_required) { status = NT_STATUS_ACCESS_DENIED; - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -1161,7 +1163,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { D_NOTICE("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = yes' " "rejects access for client.\n", @@ -1189,7 +1191,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, status = NT_STATUS_OK; - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -1204,7 +1206,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " "still needed for '%s'!\n", -- 2.39.0 From 4ae0a15ed4ebde7b1725f9ada406c179de238267 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:39:20 +0100 Subject: [PATCH 140/142] CVE-2022-38023 s3:rpc_server/netlogon: Return error on invalid auth level Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 5500a421334..fb5a05b75c8 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1071,7 +1071,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, uint16_t opnum) { TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; + NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED; const char *explicit_opt = NULL; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; @@ -1095,12 +1095,31 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { reason = "WITH SIGNED"; } else { - smb_panic("Schannel without SIGN/SEAL"); + reason = "WITH INVALID"; + dbg_lvl = DBGLVL_ERR; + status = NT_STATUS_INTERNAL_ERROR; } } else { reason = "WITHOUT"; } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (!NT_STATUS_IS_OK(status)) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + TALLOC_FREE(frame); + return status; + } + /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to -- 2.39.0 From f59b49f3c23a9a7879a6975aa77e9cf2560a68be Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:42:37 +0100 Subject: [PATCH 141/142] CVE-2022-38023 s3:rpc_server/netlogon: Rename variable This will simplify the following changes. Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index fb5a05b75c8..fd128a70c8b 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1083,7 +1083,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; - static bool warned_global_once = false; + static bool warned_global_schannel_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -1198,14 +1198,14 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, return status; } - if (!schannel_global_required && !warned_global_once) { + if (!schannel_global_required && !warned_global_schannel_once) { /* * We want admins to notice their misconfiguration! */ DBG_ERR("CVE-2020-1472(ZeroLogon): " "Please configure 'server schannel = yes', " "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); - warned_global_once = true; + warned_global_schannel_once = true; } status = NT_STATUS_OK; -- 2.39.0 From 6b038af7f70f0331d85dac00647cfe8dedefec28 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:50:04 +0100 Subject: [PATCH 142/142] CVE-2022-38023 s3:rpc_server/netlogon: implement "server schannel require seal[:COMPUTERACCOUNT]" By default we'll now require schannel connections with privacy/sealing/encryption. But we allow exceptions for specific computer/trust accounts. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- selftest/target/Samba3.pm | 14 ++ source3/rpc_server/netlogon/srv_netlog_nt.c | 237 +++++++++++++++++++- 2 files changed, 249 insertions(+), 2 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index e8a4c3bbbb6..cf6c38562de 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -215,6 +215,20 @@ sub setup_nt4_dc server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no + rpc_server:epmapper = external rpc_server:spoolss = external rpc_server:lsarpc = external diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index fd128a70c8b..38772586d81 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1076,14 +1076,22 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; bool schannel_explicitly_set = false; + bool seal_global_required = (lp_server_schannel_require_seal() == true) ? true:false; + bool seal_required = seal_global_required; + bool seal_explicitly_set = false; int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + int CVE_2022_38023_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; static bool warned_global_schannel_once = false; + static bool warned_global_seal_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -1120,6 +1128,20 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, return status; } + /* + * We don't use lp_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM, + "server schannel require seal", + creds->account_name, + NULL); + if (explicit_opt != NULL) { + seal_required = lp_bool(explicit_opt); + } + seal_explicitly_set = explicit_opt != NULL; + /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to @@ -1135,7 +1157,96 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } schannel_explicitly_set = explicit_opt != NULL; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL && + auth_level == DCERPC_AUTH_LEVEL_PRIVACY) + { + status = NT_STATUS_OK; + + if (schannel_explicitly_set && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + if (seal_explicitly_set && !seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } else if (!seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + + if (schannel_explicitly_set && !schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + if (seal_explicitly_set && !seal_required) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + TALLOC_FREE(frame); + return status; + } + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (seal_required) { + status = NT_STATUS_ACCESS_DENIED; + + if (seal_explicitly_set) { + dbg_lvl = DBGLVL_NOTICE; + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (schannel_explicitly_set && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (schannel_explicitly_set && !schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); + return status; + } + status = NT_STATUS_OK; if (schannel_explicitly_set && !schannel_required) { @@ -1143,6 +1254,11 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else if (!schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + if (seal_explicitly_set && !seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else if (!seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon): " @@ -1152,7 +1268,6 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(status))); - if (schannel_explicitly_set && !schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " @@ -1160,7 +1275,77 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name))); } + if (seal_explicitly_set && !seal_required) { + D_INFO("CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else if (!seal_required) { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "Please use 'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + TALLOC_FREE(frame); + return status; + } + + if (seal_required) { + status = NT_STATUS_ACCESS_DENIED; + if (seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (!schannel_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } else if (schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (!schannel_explicitly_set) { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } else if (schannel_required) { + D_NOTICE("CVE-2022-38023: Option " + "'server require schannel:%s = yes' " + "also rejects access for client.\n", + log_escape(frame, creds->account_name)); + } TALLOC_FREE(frame); return status; } @@ -1173,6 +1358,9 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); } + if (!seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " @@ -1194,6 +1382,13 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } + if (!seal_explicitly_set) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(frame); return status; } @@ -1208,8 +1403,24 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, warned_global_schannel_once = true; } + if (!seal_global_required && !warned_global_seal_once) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'server schannel require seal = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_once = true; + } + status = NT_STATUS_OK; + if (seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { @@ -1225,6 +1436,28 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); + if (seal_explicitly_set) { + D_INFO("CVE-2022-38023: Option " + "'server schannel require seal:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Please use " + "'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + if (schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " @@ -1248,7 +1481,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } TALLOC_FREE(frame); - return NT_STATUS_OK; + return status; } static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, -- 2.39.0