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>
Tue, 9 Nov 2021 19:45:33 +0000 (19:45 +0000)
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 d9301152d94c3e8e5cb6671ef77501e5a8300bff..9fac73ef113b3c1b13c7f29147a878bcabfe7d78 100644 (file)
@@ -109,6 +109,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 ce6bf6c56219d5c644803587bcc7a25b14fec9e1..fec19c76dbb0612c058d0a2ecbb81bbec2219539 100644 (file)
@@ -544,6 +544,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;
@@ -575,6 +576,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;
 
@@ -596,6 +598,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 39a7c0d6911f6b6a4cfe097538d5a82ba7de56f1..ba2c76764d15c9633f59c0f5e97403535260baf2 100644 (file)
@@ -203,7 +203,7 @@ copy an IP address from one buffer to another
  Check to see if we are a DC for this domain
 *****************************************************************************/
 
-#define IS_DC  (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
+#define IS_DC  (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_server_role() == ROLE_IPA_DC)
 #define IS_AD_DC  (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)
 
 /*
index da40a88717200e4c67deccb1cd70dc85a42408f5..4fe5a3b8eef84602a464aa9e7cbd24954495edc8 100644 (file)
@@ -378,6 +378,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 fd1f7b92610791649fd0b1b12f5ccdd6200d9fcc..62878c213d3a92b89a7199b51652191ead4c24d9 100644 (file)
@@ -4422,6 +4422,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:
@@ -4447,7 +4448,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 1964eb5a4489b073e5a3caba2e58425ad8b0d703..f98f0c986746919c4fb3f3c9006999c44672b5a1 100644 (file)
@@ -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;
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 b9fb7e855b83f19ad603a318271d5324fdd4b047..d7f5b4b73c0f85ac799511dfda1355d42dff585e 100644 (file)
@@ -1930,7 +1930,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 451ad6aee142b89565d262842803298ba51f28d1..db7e1c87dee1be1145900a6b9123bb43e2394c9c 100644 (file)
@@ -76,7 +76,7 @@ static char *get_trust_type_string(TALLOC_CTX *mem_ctx,
        case SEC_CHAN_BDC: {
                int role = lp_server_role();
 
-               if (role == ROLE_DOMAIN_PDC) {
+               if (role == ROLE_DOMAIN_PDC || role == ROLE_IPA_DC) {
                        s = talloc_strdup(mem_ctx, "PDC");
                        if (s == NULL) {
                                return NULL;
index 6e3739f68c153da418e38f7f6f4072324535a7bf..fe68adec534a2f42cb18d0938634fee36d14812d 100644 (file)
@@ -1322,15 +1322,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 4c66f2c23cb61c82ac422d25dd4068fc1133f581..ea9ff70ce802743278db86eb107cfd2242f36324 100644 (file)
@@ -737,6 +737,7 @@ const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *
        case ROLE_DOMAIN_BDC:
        case ROLE_DOMAIN_PDC:
        case ROLE_ACTIVE_DIRECTORY_DC:
+       case ROLE_IPA_DC:
                auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
                break;
        }
index c695004cafc86a9b26b6b06ac6b4d6f1fa335174..ce32d3cb1b362a66ca88bcad6911c0b460823d41 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 cda887d45eeef6dd84d013de4a462733fafed120..29c509522beb5f4866649a1ef34aeea61fb2826c 100644 (file)
@@ -575,6 +575,7 @@ static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state
                break;
        case ROLE_DOMAIN_PDC:
        case ROLE_DOMAIN_BDC:
+       case ROLE_IPA_DC:
        case ROLE_AUTO:
                return NT_STATUS_INTERNAL_ERROR;
        case ROLE_DOMAIN_MEMBER:
@@ -723,6 +724,7 @@ static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
                break;
        case ROLE_DOMAIN_PDC:
        case ROLE_DOMAIN_BDC:
+       case ROLE_IPA_DC:
        case ROLE_AUTO:
                return NT_STATUS_INTERNAL_ERROR;
        case ROLE_DOMAIN_MEMBER: