/* * 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; }