From 789b560a5786b02bd210f90c5b75b18b3ca609b3 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 10 Oct 2011 15:42:11 -0400 Subject: Add support for generating PAC for AS requests --- daemons/configure.ac | 10 ++ daemons/ipa-kdb/Makefile.am | 3 + daemons/ipa-kdb/ipa_kdb.c | 2 +- daemons/ipa-kdb/ipa_kdb.h | 16 +++ daemons/ipa-kdb/ipa_kdb_mspac.c | 230 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 daemons/ipa-kdb/ipa_kdb_mspac.c diff --git a/daemons/configure.ac b/daemons/configure.ac index e238d8b15..f89c50d62 100644 --- a/daemons/configure.ac +++ b/daemons/configure.ac @@ -226,6 +226,16 @@ if test "x$PYTHON" = "x" ; then AC_MSG_ERROR([Python not found]) fi +dnl --------------------------------------------------------------------------- +dnl Check for ndr_krb5pac +dnl --------------------------------------------------------------------------- + +PKG_PROG_PKG_CONFIG() +PKG_CHECK_MODULES([TALLOC], [talloc]) +PKG_CHECK_MODULES([TEVENT], [tevent]) +PKG_CHECK_MODULES([NDRPAC], [ndr_krb5pac]) + + dnl --------------------------------------------------------------------------- dnl - Set the data install directory since we don't use pkgdatadir dnl --------------------------------------------------------------------------- diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am index 036074f43..b29f60171 100644 --- a/daemons/ipa-kdb/Makefile.am +++ b/daemons/ipa-kdb/Makefile.am @@ -19,6 +19,7 @@ INCLUDES = \ $(KRB5_CFLAGS) \ $(SSL_CFLAGS) \ $(WARN_CFLAGS) \ + $(NDRPAC_CFLAGS) \ $(NULL) plugindir = $(libdir)/krb5/plugins/kdb @@ -33,6 +34,7 @@ ipadb_la_SOURCES = \ ipa_kdb_passwords.c \ ipa_kdb_principals.c \ ipa_kdb_pwdpolicy.c \ + ipa_kdb_mspac.c \ $(KRB5_UTIL_SRCS) \ $(NULL) @@ -45,6 +47,7 @@ ipadb_la_LIBADD = \ $(KRB5_LIBS) \ $(SSL_LIBS) \ $(LDAP_LIBS) \ + $(NDRPAC_LIBS) \ $(NULL) dist_noinst_DATA = ipa_kdb.exports diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c index 880a7890b..1594d8316 100644 --- a/daemons/ipa-kdb/ipa_kdb.c +++ b/daemons/ipa-kdb/ipa_kdb.c @@ -445,7 +445,7 @@ kdb_vftabl kdb_function_table = { NULL, /* promote_db */ NULL, /* decrypt_key_data */ NULL, /* encrypt_key_data */ - NULL, /* sign_authdata */ + ipadb_sign_authdata, /* sign_authdata */ NULL, /* check_transited_realms */ NULL, /* check_policy_as */ NULL, /* check_policy_tgs */ diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index cfcaca649..d026656ac 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -182,3 +182,19 @@ krb5_error_code ipadb_get_pwd_expiration(krb5_context context, krb5_db_entry *entry, struct ipadb_e_data *ied, time_t *expire_time); + +/* MS-PAC FUNCTIONS */ + +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); diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c new file mode 100644 index 000000000..410f4306e --- /dev/null +++ b/daemons/ipa-kdb/ipa_kdb_mspac.c @@ -0,0 +1,230 @@ +/* + * MIT Kerberos KDC database backend for FreeIPA + * + * Authors: Simo Sorce + * + * 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 . + */ + +#include "ipa_kdb.h" +#include "gen_ndr/ndr_krb5pac.h" +#include +#include + +#define KRB5INT_PAC_SIGN_AVAILABLE 1 + +#if KRB5INT_PAC_SIGN_AVAILABLE +krb5_error_code +krb5int_pac_sign(krb5_context context, + krb5_pac pac, + krb5_timestamp authtime, + krb5_const_principal principal, + const krb5_keyblock *server_key, + const krb5_keyblock *privsvr_key, + krb5_data *data); +#define krb5_pac_sign krb5int_pac_sign +#define KRB5_PAC_LOGON_INFO 1 +#endif + + +#define EMPTY_LSA_STRING { 0, 0, NULL } +const char simo[] = { 0x73, 0x00, 0x6a, 0x00, 0x6d, 0x00, 0x6f, 0x00 }; +const char ipa[] = { 0x6a, 0x00, 0x70, 0x00, 0x61, 0x00, 0x00, 0x00 }; + + +static krb5_error_code ipadb_get_pac(krb5_context context, + krb5_db_entry *client, + krb5_pac *pac) +{ + TALLOC_CTX *tmpctx; + DATA_BLOB pac_data; + krb5_data data; + struct netr_SamInfo3 info3; + struct dom_sid2 dom_sid; + union PAC_INFO pac_info; + krb5_error_code kerr; + enum ndr_err_code ndr_err; + + memset(&info3, 0, sizeof(info3)); + memset(&pac_info, 0, sizeof(pac_info)); + + tmpctx = talloc_new(NULL); + if (!tmpctx) { + return ENOMEM; + } + + pac_info.logon_info.info = talloc_zero(tmpctx, struct PAC_LOGON_INFO); + if (!tmpctx) { + kerr = ENOMEM; + goto done; + } + +/* info3.base.last_logon + info3.base.last_logoff + info3.base.acct_expiry + info3.base.last_password_change + info3.base.allow_password_change + info3.base.force_password_change */ + info3.base.account_name.length = sizeof(simo); + info3.base.account_name.size = sizeof(simo); + info3.base.account_name.string = simo; + info3.base.full_name.length = sizeof(simo); + info3.base.full_name.size = sizeof(simo); + info3.base.full_name.string = simo; +/* info3.base.logon_script + info3.base.profile_path + info3.base.home_directory + info3.base.home_drive + info3.base.logon_count + info3.base.bad_password_count */ + info3.base.rid = 1000; + info3.base.primary_gid = 1001; +/* info3.base.groups */ + info3.base.user_flags = 0; +/* info3.base.key */ + info3.base.logon_server.length = sizeof(ipa) - 2; + info3.base.logon_server.size = sizeof(ipa); + info3.base.logon_server.string = ipa; + info3.base.domain.length = sizeof(ipa) - 2; + info3.base.domain.size = sizeof(ipa); + info3.base.domain.string = ipa; + dom_sid.sid_rev_num = 1; + dom_sid.num_auths = 4; + dom_sid.id_auth[5] = 5; + dom_sid.sub_auths[0] = 15; + dom_sid.sub_auths[1] = 1; + dom_sid.sub_auths[2] = 2; + dom_sid.sub_auths[3] = 3; + info3.base.domain_sid = &dom_sid; +/* info3.base.LMSessKey */ + info3.base.acct_flags = 0; + + pac_info.logon_info.info->info3 = info3; + + ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_info, + PAC_TYPE_LOGON_INFO, + (ndr_push_flags_fn_t)ndr_push_PAC_INFO); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + kerr = KRB5_KDB_INTERNAL_ERROR; + goto done; + } + + kerr = krb5_pac_init(context, pac); + if (kerr) { + goto done; + } + + data.magic = KV5M_DATA; + data.data = (char *)pac_data.data; + data.length = pac_data.length; + + kerr = krb5_pac_add_buffer(context, *pac, KRB5_PAC_LOGON_INFO, &data); + +done: + talloc_free(tmpctx); + 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 *authdata[2] = { NULL, NULL }; + krb5_authdata ad; + krb5_boolean is_as_req; + krb5_error_code kerr; + krb5_pac pac = NULL; + krb5_data pac_data; + + /* Prefer canonicalised name from client entry */ + if (client != NULL) { + ks_client_princ = client->princ; + } else { + ks_client_princ = client_princ; + } + + is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); + + if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { + + kerr = ipadb_get_pac(context, client, &pac); + if (kerr != 0) { + goto done; + } + } +#if 0 + if (!is_as_req) { + code = ks_verify_pac(context, flags, ks_client_princ, client, + server_key, krbtgt_key, authtime, + tgt_auth_data, &pac); + if (code != 0) { + goto done; + } + } + + if (pac == NULL && client != NULL) { + + code = ks_get_pac(context, client, &pac); + if (code != 0) { + goto done; + } + } +#endif + if (pac == NULL) { + kerr = KRB5_KDB_DBTYPE_NOSUP; + goto done; + } + + kerr = krb5_pac_sign(context, pac, authtime, ks_client_princ, + server_key, krbtgt_key, &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); + if (kerr != 0) { + goto done; + } + + kerr = 0; + +done: + krb5_pac_free(context, pac); + return kerr; +} -- cgit