ipa-kdb: refactor KDB driver to prepare for KDB version 9

MIT Kerberos 1.20 changes DAL interface around PAC record issuance:
sign_authdata callback is removed and replaced with issue_pac one.
The signatures are different and logic changed as well.

Prepare for KDB version 9 by moving PAC implementation into separate
source files. ipa_kdb_mspac.c is left with most of the common code.

FreeIPA supports sign_authdata callback since KDB version 6, move current
implementation to ipa_kdb_mspac_v6.c.

KDB version 8 actually changed sign_authdata interface and we accounted
to that in ipa_kdb.c with a stub that re-uses v6 version. Keep it as it
is right now.

Finally, add KDB version 9 stub files. Compiling against MIT Kerberos
1.20 does not work yet, thus explicit #error message in ipa_kdb.c. This
will be worked on later.

Related: https://pagure.io/freeipa/issue/9083

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Alexander Bokovoy 2022-01-13 14:34:55 +02:00 committed by Rob Crittenden
parent 2278de732b
commit 2dc752018c
8 changed files with 445 additions and 300 deletions

View File

@ -293,6 +293,9 @@ AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], [
AM_CONDITIONAL([BUILD_IPA_KDCPOLICY_PLUGIN],
[test x$have_kdcpolicy_plugin = xyes])
AM_CONDITIONAL([BUILD_IPA_ISSUE_PAC],
[test x$have_kdb_issue_pac = xyes])
dnl ---------------------------------------------------------------------------
dnl - Check for program paths
dnl ---------------------------------------------------------------------------

View File

@ -33,7 +33,7 @@ ipadb_la_SOURCES = \
ipa_kdb_passwords.c \
ipa_kdb_principals.c \
ipa_kdb_pwdpolicy.c \
ipa_kdb_mspac.c \
ipa_kdb_mspac.c \
ipa_kdb_mspac_private.h \
ipa_kdb_delegation.c \
ipa_kdb_audit_as.c \
@ -41,6 +41,12 @@ ipadb_la_SOURCES = \
dist_noinst_DATA = ipa_kdb.exports
if BUILD_IPA_ISSUE_PAC
ipadb_la_SOURCES += ipa_kdb_mspac_v9.c
else
ipadb_la_SOURCES += ipa_kdb_mspac_v6.c
endif
if BUILD_IPA_CERTAUTH_PLUGIN
ipadb_la_SOURCES += ipa_kdb_certauth.c
endif

View File

@ -792,8 +792,47 @@ kdb_vftabl kdb_function_table = {
};
#endif
#if (KRB5_KDB_DAL_MAJOR_VERSION == 9)
#error DAL version 9 is not supported yet
/* Version 9 removes sign_authdata and adds issue_pac method. It is a complete
* revamp of how PAC is issued, so we need to implement it differently to previous
* versions. */
kdb_vftabl kdb_function_table = {
.maj_ver = KRB5_KDB_DAL_MAJOR_VERSION,
.min_ver = 0,
.init_library = ipadb_init_library,
.fini_library = ipadb_fini_library,
.init_module = ipadb_init_module,
.fini_module = ipadb_fini_module,
.create = ipadb_create,
.get_age = ipadb_get_age,
.get_principal = ipadb_get_principal,
.put_principal = ipadb_put_principal,
.delete_principal = ipadb_delete_principal,
.iterate = ipadb_iterate,
.create_policy = ipadb_create_pwd_policy,
.get_policy = ipadb_get_pwd_policy,
.put_policy = ipadb_put_pwd_policy,
.iter_policy = ipadb_iterate_pwd_policy,
.delete_policy = ipadb_delete_pwd_policy,
.fetch_master_key = ipadb_fetch_master_key,
.store_master_key_list = ipadb_store_master_key_list,
.change_pwd = ipadb_change_pwd,
.check_transited_realms = ipadb_check_transited_realms,
.check_policy_as = ipadb_check_policy_as,
.audit_as_req = ipadb_audit_as_req,
.check_allowed_to_delegate = ipadb_check_allowed_to_delegate,
.free_principal_e_data = ipadb_free_principal_e_data,
.get_s4u_x509_principal = NULL,
.allowed_to_delegate_from = NULL,
.issue_pac = NULL,
};
#endif
#if (KRB5_KDB_DAL_MAJOR_VERSION != 6) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 7) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 8)
(KRB5_KDB_DAL_MAJOR_VERSION != 8) && \
(KRB5_KDB_DAL_MAJOR_VERSION != 9)
#error unsupported DAL major version
#endif

View File

@ -982,11 +982,11 @@ static krb5_error_code ipadb_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
#endif
static krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac)
krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac)
{
TALLOC_CTX *tmpctx;
struct ipadb_e_data *ied;
@ -1181,7 +1181,7 @@ done:
return kerr;
}
static bool is_cross_realm_krbtgt(krb5_const_principal princ)
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ)
{
if ((princ->length != 2) ||
(princ->data[0].length != 6) ||
@ -2224,17 +2224,17 @@ done:
return kerr;
}
static krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac)
krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac)
{
krb5_keyblock *srv_key = NULL;
krb5_keyblock *priv_key = NULL;
@ -2264,7 +2264,7 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
* But when a trusted realm passes us a PAC the kdc checksum is
* generated with that realm krbtgt key, so we need to use the cross
* realm krbtgt to check the 'server' checksum instead. */
if (is_cross_realm_krbtgt(krbtgt->princ)) {
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
/* krbtgt from a trusted realm */
is_cross_realm = true;
@ -2425,104 +2425,6 @@ done:
return kerr;
}
static krb5_error_code ipadb_sign_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_pac pac,
krb5_data *pac_data)
{
krb5_keyblock *right_krbtgt_signing_key = NULL;
krb5_key_data *right_krbtgt_key;
krb5_db_entry *right_krbtgt = NULL;
krb5_principal krbtgt_princ = NULL;
krb5_error_code kerr;
char *princ = NULL;
bool is_issuing_referral = false;
int ret;
/* for cross realm trusts cases we need to sign with the right key.
* we need to fetch the right key on our own until the DAL is fixed
* to pass us separate check tgt keys and sign tgt keys */
/* We can only ever create the kdc checksum with our realm tgt key.
* So, if we get a cross realm tgt we have to fetch our realm tgt
* instead. */
if (is_cross_realm_krbtgt(krbtgt->princ)) {
ret = asprintf(&princ, "krbtgt/%.*s@%.*s",
server->princ->realm.length,
server->princ->realm.data,
server->princ->realm.length,
server->princ->realm.data);
if (ret == -1) {
princ = NULL;
kerr = ENOMEM;
goto done;
}
kerr = krb5_parse_name(context, princ, &krbtgt_princ);
if (kerr) {
goto done;
}
kerr = ipadb_get_principal(context, krbtgt_princ, 0, &right_krbtgt);
if (kerr) {
goto done;
}
kerr = krb5_dbe_find_enctype(context, right_krbtgt,
-1, -1, 0, &right_krbtgt_key);
if (kerr) {
goto done;
}
if (!right_krbtgt_key) {
kerr = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto done;
}
right_krbtgt_signing_key = malloc(sizeof(krb5_keyblock));
if (!right_krbtgt_signing_key) {
kerr = ENOMEM;
goto done;
}
kerr = krb5_dbe_decrypt_key_data(context, NULL, right_krbtgt_key,
right_krbtgt_signing_key, NULL);
if (kerr) {
goto done;
}
} else {
right_krbtgt_signing_key = krbtgt_key;
}
#ifdef KRB5_KDB_FLAG_ISSUING_REFERRAL
is_issuing_referral = (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL) != 0;
#endif
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
* was requested */
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
right_krbtgt_signing_key,
(is_issuing_referral &&
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
pac_data);
done:
free(princ);
krb5_free_principal(context, krbtgt_princ);
ipadb_free_principal(context, right_krbtgt);
if (right_krbtgt_signing_key != krbtgt_key) {
krb5_free_keyblock(context, right_krbtgt_signing_key);
}
return kerr;
}
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
bool *_with_pac, bool *_with_pad)
{
@ -2652,187 +2554,6 @@ done:
}
krb5_error_code ipadb_sign_authdata(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *client_key,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
krb5_authdata ***signed_auth_data)
{
krb5_const_principal ks_client_princ;
krb5_authdata **pac_auth_data = NULL;
krb5_authdata *authdata[2] = { NULL, NULL };
krb5_authdata ad;
krb5_boolean is_as_req;
krb5_error_code kerr;
krb5_pac pac = NULL;
krb5_data pac_data;
struct ipadb_context *ipactx;
bool with_pac;
bool with_pad;
bool make_ad = false;
int result;
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
/* When using s4u2proxy client_princ actually refers to the proxied user
* while client->princ to the proxy service asking for the TGS on behalf
* of the proxied user. So always use client_princ in preference */
if (client_princ != NULL) {
ks_client_princ = client_princ;
if (!is_as_req) {
is_equal = false;
if ((client != NULL) && (client->princ != NULL)) {
is_equal = krb5_principal_compare(context, client_princ, client->princ);
}
if (!is_equal) {
kerr = ipadb_get_principal(context, client_princ, flags, &client_entry);
/* If we didn't find client_princ in our database, it might be:
* - a principal from another realm, handle it down in ipadb_get/verify_pac()
*/
if (kerr != 0) {
client_entry = NULL;
}
}
}
} else {
if (client == NULL) {
*signed_auth_data = NULL;
return 0;
}
ks_client_princ = client->princ;
}
if (client_entry == NULL) client_entry = client;
if (is_as_req) {
get_authz_data_types(context, client_entry, &with_pac, &with_pad);
} else {
get_authz_data_types(context, server, &with_pac, &with_pad);
}
if (with_pad) {
krb5_klog_syslog(LOG_ERR, "PAD authorization data is requested but " \
"currently not supported.");
}
/* we need to create a PAC if we are requested one and this is an AS REQ,
* or we are doing protocol transition (S4USelf) but not over cross-realm
*/
if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) ||
((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) && (client != NULL))) {
make_ad = true;
}
if (with_pac && make_ad) {
ipactx = ipadb_get_context(context);
if (!ipactx) {
kerr = ENOMEM;
goto done;
}
/* Be aggressive here: special case for discovering range type
* immediately after establishing the trust by IPA framework. For all
* other cases call ipadb_reinit_mspac() with force_reinit_mspac set
* to 'false' to make sure the information about trusted domains is
* updated on a regular basis for all worker processes. */
if ((krb5_princ_size(context, ks_client_princ) == 2) &&
(strncmp(krb5_princ_component(context, ks_client_princ, 0)->data, "HTTP",
krb5_princ_component(context, ks_client_princ, 0)->length) == 0) &&
(ulc_casecmp(krb5_princ_component(context, ks_client_princ, 1)->data,
krb5_princ_component(context, ks_client_princ, 1)->length,
ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
NULL, NULL, &result) == 0)) {
force_reinit_mspac = true;
}
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
kerr = ipadb_get_pac(context, client, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
} else if (with_pac && !is_as_req) {
/* find the existing PAC, if present */
kerr = krb5_find_authdata(context, tgt_auth_data, NULL,
KRB5_AUTHDATA_WIN2K_PAC, &pac_auth_data);
if (kerr != 0) {
goto done;
}
/* check or generate pac data */
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
kerr = ipadb_get_pac(context, client_entry, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
}
} else {
if (pac_auth_data[1] != NULL) {
kerr = KRB5KDC_ERR_BADOPTION; /* FIXME: right error ? */
goto done;
}
kerr = ipadb_verify_pac(context, flags, ks_client_princ, client,
server, krbtgt, server_key, krbtgt_key,
authtime, pac_auth_data, &pac);
if (kerr != 0) {
goto done;
}
}
}
if (pac == NULL) {
/* No PAC to deal with, proceed */
*signed_auth_data = NULL;
kerr = 0;
goto done;
}
kerr = ipadb_sign_pac(context, flags, ks_client_princ, server, krbtgt,
server_key, krbtgt_key, authtime, pac, &pac_data);
if (kerr != 0) {
goto done;
}
/* put in signed data */
ad.magic = KV5M_AUTHDATA;
ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
ad.contents = (krb5_octet *)pac_data.data;
ad.length = pac_data.length;
authdata[0] = &ad;
kerr = krb5_encode_authdata_container(context,
KRB5_AUTHDATA_IF_RELEVANT,
authdata,
signed_auth_data);
krb5_free_data_contents(context, &pac_data);
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
if (client_entry != NULL && client_entry != client) {
ipadb_free_principal(context, client_entry);
}
krb5_pac_free(context, pac);
return kerr;
}
static char *get_server_netbios_name(struct ipadb_context *ipactx)
{

View File

@ -55,4 +55,22 @@ char *dom_sid_string(TALLOC_CTX *memctx, const struct dom_sid *dom_sid);
krb5_error_code filter_logon_info(krb5_context context, TALLOC_CTX *memctx,
krb5_data realm, struct PAC_LOGON_INFO_CTR *info);
void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
bool *_with_pac, bool *_with_pad);
bool *_with_pac, bool *_with_pad);
bool ipadb_is_cross_realm_krbtgt(krb5_const_principal princ);
krb5_error_code ipadb_get_pac(krb5_context kcontext,
krb5_db_entry *client,
unsigned int flags,
krb5_timestamp authtime,
krb5_pac *pac);
krb5_error_code ipadb_verify_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *proxy,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_authdata **authdata,
krb5_pac *pac);

View File

@ -0,0 +1,315 @@
/*
* MIT Kerberos KDC database backend for FreeIPA
*
* Authors: Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2011 Simo Sorce, Red Hat
* see file 'COPYING' for use and warranty information
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "ipa_hostname.h"
#include "ipa_kdb.h"
#include <talloc.h>
#include <unicase.h>
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
#include "ipa_kdb_mspac_private.h"
static krb5_error_code ipadb_sign_pac(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_timestamp authtime,
krb5_pac pac,
krb5_data *pac_data)
{
krb5_keyblock *right_krbtgt_signing_key = NULL;
krb5_key_data *right_krbtgt_key;
krb5_db_entry *right_krbtgt = NULL;
krb5_principal krbtgt_princ = NULL;
krb5_error_code kerr;
char *princ = NULL;
bool is_issuing_referral = false;
int ret;
/* for cross realm trusts cases we need to sign with the right key.
* we need to fetch the right key on our own until the DAL is fixed
* to pass us separate check tgt keys and sign tgt keys */
/* We can only ever create the kdc checksum with our realm tgt key.
* So, if we get a cross realm tgt we have to fetch our realm tgt
* instead. */
if (ipadb_is_cross_realm_krbtgt(krbtgt->princ)) {
ret = asprintf(&princ, "krbtgt/%.*s@%.*s",
server->princ->realm.length,
server->princ->realm.data,
server->princ->realm.length,
server->princ->realm.data);
if (ret == -1) {
princ = NULL;
kerr = ENOMEM;
goto done;
}
kerr = krb5_parse_name(context, princ, &krbtgt_princ);
if (kerr) {
goto done;
}
kerr = ipadb_get_principal(context, krbtgt_princ, 0, &right_krbtgt);
if (kerr) {
goto done;
}
kerr = krb5_dbe_find_enctype(context, right_krbtgt,
-1, -1, 0, &right_krbtgt_key);
if (kerr) {
goto done;
}
if (!right_krbtgt_key) {
kerr = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto done;
}
right_krbtgt_signing_key = malloc(sizeof(krb5_keyblock));
if (!right_krbtgt_signing_key) {
kerr = ENOMEM;
goto done;
}
kerr = krb5_dbe_decrypt_key_data(context, NULL, right_krbtgt_key,
right_krbtgt_signing_key, NULL);
if (kerr) {
goto done;
}
} else {
right_krbtgt_signing_key = krbtgt_key;
}
#ifdef KRB5_KDB_FLAG_ISSUING_REFERRAL
is_issuing_referral = (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL) != 0;
#endif
/* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
* was requested */
kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
right_krbtgt_signing_key,
(is_issuing_referral &&
(flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)),
pac_data);
done:
free(princ);
krb5_free_principal(context, krbtgt_princ);
ipadb_free_principal(context, right_krbtgt);
if (right_krbtgt_signing_key != krbtgt_key) {
krb5_free_keyblock(context, right_krbtgt_signing_key);
}
return kerr;
}
krb5_error_code ipadb_sign_authdata(krb5_context context,
unsigned int flags,
krb5_const_principal client_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *client_key,
krb5_keyblock *server_key,
krb5_keyblock *krbtgt_key,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
krb5_authdata ***signed_auth_data)
{
krb5_const_principal ks_client_princ;
krb5_authdata **pac_auth_data = NULL;
krb5_authdata *authdata[2] = { NULL, NULL };
krb5_authdata ad;
krb5_boolean is_as_req;
krb5_error_code kerr;
krb5_pac pac = NULL;
krb5_data pac_data;
struct ipadb_context *ipactx;
bool with_pac;
bool with_pad;
bool make_ad = false;
int result;
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
/* When using s4u2proxy client_princ actually refers to the proxied user
* while client->princ to the proxy service asking for the TGS on behalf
* of the proxied user. So always use client_princ in preference */
if (client_princ != NULL) {
ks_client_princ = client_princ;
if (!is_as_req) {
is_equal = false;
if ((client != NULL) && (client->princ != NULL)) {
is_equal = krb5_principal_compare(context, client_princ, client->princ);
}
if (!is_equal) {
kerr = ipadb_get_principal(context, client_princ, flags, &client_entry);
/* If we didn't find client_princ in our database, it might be:
* - a principal from another realm, handle it down in ipadb_get/verify_pac()
*/
if (kerr != 0) {
client_entry = NULL;
}
}
}
} else {
if (client == NULL) {
*signed_auth_data = NULL;
return 0;
}
ks_client_princ = client->princ;
}
if (client_entry == NULL) client_entry = client;
if (is_as_req) {
get_authz_data_types(context, client_entry, &with_pac, &with_pad);
} else {
get_authz_data_types(context, server, &with_pac, &with_pad);
}
if (with_pad) {
krb5_klog_syslog(LOG_ERR, "PAD authorization data is requested but " \
"currently not supported.");
}
/* we need to create a PAC if we are requested one and this is an AS REQ,
* or we are doing protocol transition (S4USelf) but not over cross-realm
*/
if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) ||
((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) && (client != NULL))) {
make_ad = true;
}
if (with_pac && make_ad) {
ipactx = ipadb_get_context(context);
if (!ipactx) {
kerr = ENOMEM;
goto done;
}
/* Be aggressive here: special case for discovering range type
* immediately after establishing the trust by IPA framework. For all
* other cases call ipadb_reinit_mspac() with force_reinit_mspac set
* to 'false' to make sure the information about trusted domains is
* updated on a regular basis for all worker processes. */
if ((krb5_princ_size(context, ks_client_princ) == 2) &&
(strncmp(krb5_princ_component(context, ks_client_princ, 0)->data, "HTTP",
krb5_princ_component(context, ks_client_princ, 0)->length) == 0) &&
(ulc_casecmp(krb5_princ_component(context, ks_client_princ, 1)->data,
krb5_princ_component(context, ks_client_princ, 1)->length,
ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
NULL, NULL, &result) == 0)) {
force_reinit_mspac = true;
}
(void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
kerr = ipadb_get_pac(context, client, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
} else if (with_pac && !is_as_req) {
/* find the existing PAC, if present */
kerr = krb5_find_authdata(context, tgt_auth_data, NULL,
KRB5_AUTHDATA_WIN2K_PAC, &pac_auth_data);
if (kerr != 0) {
goto done;
}
/* check or generate pac data */
if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) {
if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
kerr = ipadb_get_pac(context, client_entry, flags, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
goto done;
}
}
} else {
if (pac_auth_data[1] != NULL) {
kerr = KRB5KDC_ERR_BADOPTION; /* FIXME: right error ? */
goto done;
}
kerr = ipadb_verify_pac(context, flags, ks_client_princ, client,
server, krbtgt, server_key, krbtgt_key,
authtime, pac_auth_data, &pac);
if (kerr != 0) {
goto done;
}
}
}
if (pac == NULL) {
/* No PAC to deal with, proceed */
*signed_auth_data = NULL;
kerr = 0;
goto done;
}
kerr = ipadb_sign_pac(context, flags, ks_client_princ, server, krbtgt,
server_key, krbtgt_key, authtime, pac, &pac_data);
if (kerr != 0) {
goto done;
}
/* put in signed data */
ad.magic = KV5M_AUTHDATA;
ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
ad.contents = (krb5_octet *)pac_data.data;
ad.length = pac_data.length;
authdata[0] = &ad;
kerr = krb5_encode_authdata_container(context,
KRB5_AUTHDATA_IF_RELEVANT,
authdata,
signed_auth_data);
krb5_free_data_contents(context, &pac_data);
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
if (client_entry != NULL && client_entry != client) {
ipadb_free_principal(context, client_entry);
}
krb5_pac_free(context, pac);
return kerr;
}

View File

@ -0,0 +1,34 @@
/*
* MIT Kerberos KDC database backend for FreeIPA
*
* Authors: Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2011 Simo Sorce, Red Hat
* see file 'COPYING' for use and warranty information
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "ipa_hostname.h"
#include "ipa_kdb.h"
#include <talloc.h>
#include <unicase.h>
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
#include "ipa_kdb_mspac_private.h"

View File

@ -74,6 +74,15 @@ krb5rundir="${runstatedir}/krb5kdc"
AC_SUBST(KRAD_LIBS)
AC_SUBST(krb5rundir)
dnl ---------------------------------------------------------------------------
dnl - Check for KRB5 KDB API issue_pac support
dnl ---------------------------------------------------------------------------
AC_CHECK_HEADER(kdb.h, [], [AC_MSG_ERROR([kdb.h not found])])
AC_CHECK_MEMBER([kdb_vftabl.issue_pac],
[have_kdb_issue_pac=yes],
[have_kdb_issue_pac=no])
dnl ---------------------------------------------------------------------------
dnl - Check for UUID library
dnl ---------------------------------------------------------------------------