Skip to content

Commit

Permalink
CVE-2020-25717: Add FreeIPA domain controller role
Browse files Browse the repository at this point in the history
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 <[email protected]>

Signed-off-by: Alexander Bokovoy <[email protected]>
Signed-off-by: Stefan Metzmacher <[email protected]>
Reviewed-by: Andrew Bartlett <[email protected]>
  • Loading branch information
abbra authored and Jule Anger committed Nov 9, 2021
1 parent 57abb7f commit e2d5b4d
Show file tree
Hide file tree
Showing 21 changed files with 72 additions and 25 deletions.
7 changes: 7 additions & 0 deletions docs-xml/smbdotconf/security/serverrole.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@
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>
Expand Down
2 changes: 2 additions & 0 deletions lib/param/loadparm_server_role.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};

Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions lib/param/param_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}
};

Expand Down
1 change: 1 addition & 0 deletions lib/param/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libcli/netlogon/netlogon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libds/common/roles.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions source3/auth/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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:
Expand Down
14 changes: 8 additions & 6 deletions source3/auth/auth_sam.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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");
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion source3/include/smb_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

/*
Expand Down
1 change: 1 addition & 0 deletions source3/lib/netapi/joindomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion source3/param/loadparm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion source3/passdb/lookup_sid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
7 changes: 3 additions & 4 deletions source3/passdb/machine_account_secrets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions source3/registry/reg_backend_prod_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions source3/rpc_server/dssetup/srv_dssetup_nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion source3/smbd/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion source3/winbindd/winbindd_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
40 changes: 31 additions & 9 deletions source3/winbindd/winbindd_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
1 change: 1 addition & 0 deletions source4/auth/ntlm/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions source4/kdc/kdc-heimdal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions source4/rpc_server/samr/dcesrv_samr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit e2d5b4d

Please sign in to comment.