]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2020-25717: Add FreeIPA domain controller role
authorAlexander Bokovoy <ab@samba.org>
Wed, 11 Nov 2020 16:50:45 +0000 (18:50 +0200)
committerJule Anger <janger@samba.org>
Mon, 8 Nov 2021 09:52:10 +0000 (10:52 +0100)
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 <metze@samba.org>

Signed-off-by: Alexander Bokovoy <ab@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
21 files changed:
docs-xml/smbdotconf/security/serverrole.xml
lib/param/loadparm_server_role.c
lib/param/param_table.c
lib/param/util.c
libcli/netlogon/netlogon.c
libds/common/roles.h
source3/auth/auth.c
source3/auth/auth_sam.c
source3/include/smb_macros.h
source3/lib/netapi/joindomain.c
source3/param/loadparm.c
source3/passdb/lookup_sid.c
source3/passdb/machine_account_secrets.c
source3/registry/reg_backend_prod_options.c
source3/rpc_server/dssetup/srv_dssetup_nt.c
source3/smbd/server.c
source3/winbindd/winbindd_misc.c
source3/winbindd/winbindd_util.c
source4/auth/ntlm/auth.c
source4/kdc/kdc-heimdal.c
source4/rpc_server/samr/dcesrv_samr.c

index 9511c61c96d61c4f116cd85ddd770ce1268d4633..b8b83a127b5df3995970e857660621c75c04ad01 100644 (file)
     url="http://wiki.samba.org/index.php/Samba4/HOWTO">Samba4
     HOWTO</ulink></para>
 
+    <para><anchor id="IPA-DC"/><emphasis>SERVER ROLE = IPA DOMAIN CONTROLLER</emphasis></para>
+
+    <para>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.
+    </para>
 </description>
 
 <related>security</related>
index 7a6bc7707235985e59276812fd7be02e4ca1ec93..a78d1ab9cf39346fe218bfbe4d3bb72aa4857bba 100644 (file)
@@ -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;
                }
index 47b85de1f876528f36a67684d320bad099e12bf9..780252017d2292c507fc8cc568e8f9dbe307319a 100644 (file)
@@ -111,6 +111,7 @@ static const struct enum_list enum_server_role[] = {
        {ROLE_ACTIVE_DIRECTORY_DC, "active directory domain controller"},
        {ROLE_ACTIVE_DIRECTORY_DC, "domain controller"},
        {ROLE_ACTIVE_DIRECTORY_DC, "dc"},
+       {ROLE_IPA_DC, "IPA primary domain controller"},
        {-1, NULL}
 };
 
index cd8e74b9d8f387fcb0354530a2f473ef3a75b3ad..9a0fc102de892c81df4e3e79c08eb70947471201 100644 (file)
@@ -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);
index 239503e85b64495192d8d964d0ebb58904da3286..59af460dc4e80c457a9ff64f2af4450c28a5856b 100644 (file)
@@ -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
index 4772c8d7d3f7a3beff4036b26f93e10091877d47..03ba1915b215b7c895210eaa35a3a8bee89a937e 100644 (file)
@@ -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
index 12f7917b38d71b306c4d79ce074090b4c5f26846..4944c0fee1a9ca9b1ec01953e25655a2fdd2a278 100644 (file)
@@ -542,6 +542,7 @@ NTSTATUS make_auth3_context_for_ntlm(TALLOC_CTX *mem_ctx,
                break;
        case ROLE_DOMAIN_BDC:
        case ROLE_DOMAIN_PDC:
+       case ROLE_IPA_DC:
                role = "'DC'";
                methods = "anonymous sam winbind sam_ignoredomain";
                break;
@@ -573,6 +574,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;
 
@@ -594,6 +596,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:
index e8e0d543f8c36903e7ff2420c71f551bddbaae1f..a2ce1013975014c8abbc518e18e86825b780c17d 100644 (file)
@@ -143,12 +143,13 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context,
                        break;
                case ROLE_DOMAIN_PDC:
                case ROLE_DOMAIN_BDC:
+               case ROLE_IPA_DC:
                        if (!is_local_name && !is_my_domain) {
                               /* If we are running on a DC that has PASSDB module with domain
                                * information, check if DNS forest name is matching the domain
-                               * name. This is the case of FreeIPA domain controller when
-                               * trusted AD DCs attempt to authenticate FreeIPA users using
-                               * the forest root domain (which is the only domain in FreeIPA).
+                               * name. This is the case of IPA domain controller when
+                               * trusted AD DCs attempt to authenticate IPA users using
+                               * the forest root domain (which is the only domain in IPA).
                                */
                                struct pdb_domain_info *dom_info = NULL;
 
@@ -234,6 +235,7 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context,
        switch (lp_server_role()) {
        case ROLE_DOMAIN_PDC:
        case ROLE_DOMAIN_BDC:
+       case ROLE_IPA_DC:
                break;
        default:
                DBG_ERR("Invalid server role\n");
@@ -252,9 +254,9 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context,
        if (!is_my_domain) {
               /* If we are running on a DC that has PASSDB module with domain
                * information, check if DNS forest name is matching the domain
-               * name. This is the case of FreeIPA domain controller when
-               * trusted AD DCs attempt to authenticate FreeIPA users using
-               * the forest root domain (which is the only domain in FreeIPA).
+               * name. This is the case of IPA domain controller when
+               * trusted AD DCs attempt to authenticate IPA users using
+               * the forest root domain (which is the only domain in IPA).
                */
                struct pdb_domain_info *dom_info = NULL;
                dom_info = pdb_get_domain_info(mem_ctx);
index 1513696f7660cd26f6d362f2bb46a694931a0d30..68abe83dcbcafb6a39336bc69d32f8537de5de3f 100644 (file)
@@ -199,7 +199,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)
 
 /*
index f2d36fc00dbe18c015729d64c78ca3a74c8940a9..d1710c4b938b6572a3ac0a618ec65260a3299291 100644 (file)
@@ -375,6 +375,7 @@ WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
                case ROLE_DOMAIN_MEMBER:
                case ROLE_DOMAIN_PDC:
                case ROLE_DOMAIN_BDC:
+               case ROLE_IPA_DC:
                        *r->out.name_type = NetSetupDomainName;
                        break;
                case ROLE_STANDALONE:
index 301e3622ed47402be3c89213fbaa8b49505d7575..56cf0abb33af28d7a652d9f2c4c4a6a022d81c0a 100644 (file)
@@ -4405,6 +4405,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:
@@ -4430,7 +4431,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;
 }
index 0e01467b3cb44d1dd0bcb9f7d51b7268f10ae97b..a551bcfd24a056ca3f13f8d0d353c45cba66c146 100644 (file)
@@ -121,7 +121,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx,
 
                /* If we are running on a DC that has PASSDB module with domain
                 * information, check if DNS forest name is matching the domain
-                * name. This is the case of FreeIPA domain controller when
+                * name. This is the case of IPA domain controller when
                 * trusted AD DC looks up users found in a Global Catalog of
                 * the forest root domain. */
                if (!check_global_sam && (IS_DC)) {
index 7c103d0a6e40ef99c3281b5a2bde6cc3a0af3272..0b18334446eb36b594a9cb4a161aab0c1ffc43f3 100644 (file)
@@ -197,7 +197,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;
@@ -313,9 +314,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;
index 655c587ac405dfa6b468211c66c0ce5ec6f56d16..7bd3f324c37308dabfb4bf66f1b3f74f9453fa99 100644 (file)
@@ -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:
index 64569382695a1c8c88d7203b02299cab52cfb574..932452bc13ba106b9af50d70a8be41e44f5b7006 100644 (file)
@@ -63,6 +63,7 @@ static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx,
                        basic->domain = get_global_sam_name();
                        break;
                case ROLE_DOMAIN_PDC:
+               case ROLE_IPA_DC:
                        basic->role = DS_ROLE_PRIMARY_DC;
                        basic->domain = get_global_sam_name();
                        break;
index 39f83c3daa680b5f249b91f3cd2aaa66707792a4..d574e7de1a5d9f9c5f5a47f50052e57fc9fc6a37 100644 (file)
@@ -1973,7 +1973,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);
index d27ed76e81e78ecf6bc071ed965c3b4aa315c0b0..0e31fc6b65c1a6f0dc8e1ae2ce016ab780c14d8f 100644 (file)
@@ -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;
index ef197310fa0ce71596881cf35443837c13dea299..1ae4a8d3ca3dc03b0c757b5aea479bdfb82da92b 100644 (file)
@@ -1251,15 +1251,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");
index e0c4436343cd3ea07b713b03b1ee86507bf8aa57..6302a60232dbb81582b1804ce72af9bfef5a40f1 100644 (file)
@@ -736,6 +736,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;
        }
index ee4e1387def322fe75cff277799d4f48ddecb225..28dadcb1fd584f79c88a64952536cac607561bda 100644 (file)
@@ -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;
index 70f914bf14c728b1e69eea73ad97d7ef4525edef..7345cac6bd679fbe1abab1747cf84657bdf03c90 100644 (file)
@@ -573,6 +573,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:
@@ -721,6 +722,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: