ipa-kdb: Always allow services to get PAC if needed

Previously, FreeIPA only allowed to issue PAC record in a ticket
for the following principal types:
   - for IPA users
   - for a host principal of one of IPA masters
   - for a cifs/ or HTTP/ service on one of IPA masters

To allow S4U2Self operations over trust to AD, an impersonating service
must have PAC record in its TGT to be able to ask AD DCs for a S4U2Self
ticket. It means any IPA service performing S4U2Self would need to have
PAC record and the constraints above prevent it from doing so.

However, depending on whether the service or host principal belongs to
one of IPA masters, we need to set proper primary RID to 516 (domain
controllers) or 515 (domain computers).

Fixes: https://pagure.io/freeipa/issue/8319

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Isaac Boukris <iboukris@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
This commit is contained in:
Alexander Bokovoy 2020-05-12 18:19:06 +03:00
parent 015ae27598
commit 3e20a96c30

View File

@ -70,17 +70,6 @@ static char *memberof_pac_attrs[] = {
NULL NULL
}; };
static struct {
char *service;
int length;
} supported_services[] = {
{"cifs", sizeof("cifs")},
{"HTTP", sizeof("HTTP")},
{NULL, 0}
};
#define SID_ID_AUTHS 6 #define SID_ID_AUTHS 6
#define SID_SUB_AUTHS 15 #define SID_SUB_AUTHS 15
#define MAX(a,b) (((a)>(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b))
@ -435,7 +424,6 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
char *strres; char *strres;
int intres; int intres;
int ret; int ret;
int i;
char **objectclasses = NULL; char **objectclasses = NULL;
size_t c; size_t c;
bool is_host = false; bool is_host = false;
@ -444,7 +432,6 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
bool is_ipauser = false; bool is_ipauser = false;
bool is_idobject = false; bool is_idobject = false;
krb5_principal princ; krb5_principal princ;
krb5_data *data;
ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, "objectClass", ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, "objectClass",
&objectclasses); &objectclasses);
@ -488,17 +475,10 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
/* fqdn is mandatory for hosts */ /* fqdn is mandatory for hosts */
return ret; return ret;
} }
/* Currently we only add a PAC to TGTs for IPA servers to allow SSSD in
* ipa_server_mode to access the AD LDAP server */
if (!is_master_host(ipactx, strres)) {
free(strres);
return ENOENT;
}
} else if (is_service) { } else if (is_service) {
ret = ipadb_ldap_attr_to_str(lcontext, lentry, "krbPrincipalName", &strres); ret = ipadb_ldap_attr_to_str(lcontext, lentry, "krbCanonicalName", &strres);
if (ret) { if (ret) {
/* krbPrincipalName is mandatory for services */ /* krbCanonicalName is mandatory for services */
return ret; return ret;
} }
@ -509,39 +489,10 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
return ENOENT; return ENOENT;
} }
if (krb5_princ_size(ipactx->kcontext, princ) != 2) { ret = krb5_unparse_name_flags(ipactx->kcontext,
krb5_free_principal(ipactx->kcontext, princ); princ, KRB5_PRINCIPAL_UNPARSE_SHORT,
return ENOENT; &strres);
} if (ret) {
data = krb5_princ_component(ipactx->context, princ, 0);
for (i = 0; supported_services[i].service; i++) {
if (0 == memcmp(data->data, supported_services[i].service,
MIN(supported_services[i].length, data->length))) {
break;
}
}
if (supported_services[i].service == NULL) {
krb5_free_principal(ipactx->kcontext, princ);
return ENOENT;
}
data = krb5_princ_component(ipactx->context, princ, 1);
strres = malloc(data->length+1);
if (strres == NULL) {
krb5_free_principal(ipactx->kcontext, princ);
return ENOENT;
}
memcpy(strres, data->data, data->length);
strres[data->length] = '\0';
krb5_free_principal(ipactx->kcontext, princ);
/* Only add PAC to TGT to services on IPA masters to allow querying
* AD LDAP server */
if (!is_master_host(ipactx, strres)) {
free(strres);
return ENOENT; return ENOENT;
} }
} else { } else {
@ -678,9 +629,19 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
info3->base.logon_count = 0; /* we do not have this info yet */ info3->base.logon_count = 0; /* we do not have this info yet */
info3->base.bad_password_count = 0; /* we do not have this info yet */ info3->base.bad_password_count = 0; /* we do not have this info yet */
if (is_host || is_service) { if ((is_host || is_service)) {
/* Well know RID of domain controllers group */ /* it is either host or service, so get the hostname first */
info3->base.rid = 516; char *sep = strchr(info3->base.account_name.string, '/');
bool is_master = is_master_host(
ipactx,
sep ? sep + 1 : info3->base.account_name.string);
if (is_master) {
/* Well know RID of domain controllers group */
info3->base.rid = 516;
} else {
/* Well know RID of domain computers group */
info3->base.rid = 515;
}
} else { } else {
ret = ipadb_ldap_attr_to_str(lcontext, lentry, ret = ipadb_ldap_attr_to_str(lcontext, lentry,
"ipaNTSecurityIdentifier", &strres); "ipaNTSecurityIdentifier", &strres);