diff options
Diffstat (limited to 'source4/kdc/mit_kdc_irpc.c')
-rw-r--r-- | source4/kdc/mit_kdc_irpc.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/source4/kdc/mit_kdc_irpc.c b/source4/kdc/mit_kdc_irpc.c new file mode 100644 index 0000000..92fb78d --- /dev/null +++ b/source4/kdc/mit_kdc_irpc.c @@ -0,0 +1,204 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (c) 2015 Andreas Schneider <asn@samba.org> + * + * 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 "includes.h" +#include "system/kerberos.h" +#include "source4/auth/kerberos/kerberos.h" +#include "auth/kerberos/pac_utils.h" + +#include "librpc/gen_ndr/irpc.h" +#include "lib/messaging/irpc.h" +#include "source4/librpc/gen_ndr/ndr_irpc.h" +#include "source4/librpc/gen_ndr/irpc.h" + +#include "librpc/gen_ndr/ndr_krb5pac.h" + +#include "source4/samba/process_model.h" +#include "lib/param/param.h" + +#include "samba_kdc.h" +#include "db-glue.h" +#include "sdb.h" +#include "mit_kdc_irpc.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_KERBEROS + +struct mit_kdc_irpc_context { + struct task_server *task; + krb5_context krb5_context; + struct samba_kdc_db_context *db_ctx; +}; + +static NTSTATUS netr_samlogon_generic_logon(struct irpc_message *msg, + struct kdc_check_generic_kerberos *r) +{ + struct PAC_Validate pac_validate; + DATA_BLOB pac_chksum; + struct PAC_SIGNATURE_DATA pac_kdc_sig; + struct mit_kdc_irpc_context *mki_ctx = + talloc_get_type(msg->private_data, + struct mit_kdc_irpc_context); + enum ndr_err_code ndr_err; + int code; + krb5_principal principal; + struct sdb_entry sentry = {}; + struct sdb_keys skeys; + unsigned int i; + const uint8_t *d = NULL; + + /* There is no reply to this request */ + r->out.generic_reply = data_blob(NULL, 0); + + ndr_err = + ndr_pull_struct_blob(&r->in.generic_request, + msg, + &pac_validate, + (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) { + /* + * We don't implement any other message types - such as + * certificate validation - yet + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if ((pac_validate.ChecksumAndSignature.length != + (pac_validate.ChecksumLength + pac_validate.SignatureLength)) || + (pac_validate.ChecksumAndSignature.length < + pac_validate.ChecksumLength) || + (pac_validate.ChecksumAndSignature.length < + pac_validate.SignatureLength)) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* PAC Checksum */ + pac_chksum = data_blob_const(pac_validate.ChecksumAndSignature.data, + pac_validate.ChecksumLength); + + /* Create the krbtgt principal */ + code = smb_krb5_make_principal(mki_ctx->krb5_context, + &principal, + lpcfg_realm(mki_ctx->task->lp_ctx), + "krbtgt", + lpcfg_realm(mki_ctx->task->lp_ctx), + NULL); + if (code != 0) { + DBG_ERR("Failed to create krbtgt@%s principal!\n", + lpcfg_realm(mki_ctx->task->lp_ctx)); + return NT_STATUS_NO_MEMORY; + } + + /* Get the krbtgt from the DB */ + code = samba_kdc_fetch(mki_ctx->krb5_context, + mki_ctx->db_ctx, + principal, + SDB_F_GET_KRBTGT | SDB_F_DECRYPT, + 0, + &sentry); + krb5_free_principal(mki_ctx->krb5_context, principal); + if (code != 0) { + DBG_ERR("Failed to fetch krbtgt@%s principal entry!\n", + lpcfg_realm(mki_ctx->task->lp_ctx)); + return NT_STATUS_LOGON_FAILURE; + } + + /* PAC Signature */ + pac_kdc_sig.type = pac_validate.SignatureType; + + d = &pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength]; + pac_kdc_sig.signature = + data_blob_const(d, pac_validate.SignatureLength); + + /* + * Brute force variant because MIT KRB5 doesn't provide a function like + * krb5_checksum_to_enctype(). + */ + skeys = sentry.keys; + + code = EINVAL; + for (i = 0; i < skeys.len; i++) { + krb5_keyblock krbtgt_keyblock = skeys.val[i].key; + + code = check_pac_checksum(pac_chksum, + &pac_kdc_sig, + mki_ctx->krb5_context, + &krbtgt_keyblock); + if (code == 0) { + break; + } + } + + sdb_entry_free(&sentry); + + if (code != 0) { + return NT_STATUS_LOGON_FAILURE; + } + + return NT_STATUS_OK; +} + +NTSTATUS samba_setup_mit_kdc_irpc(struct task_server *task) +{ + struct samba_kdc_base_context base_ctx; + struct mit_kdc_irpc_context *mki_ctx; + NTSTATUS status; + int code; + + mki_ctx = talloc_zero(task, struct mit_kdc_irpc_context); + if (mki_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + mki_ctx->task = task; + + base_ctx.ev_ctx = task->event_ctx; + base_ctx.lp_ctx = task->lp_ctx; + + /* db-glue.h */ + status = samba_kdc_setup_db_ctx(mki_ctx, + &base_ctx, + &mki_ctx->db_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + code = smb_krb5_init_context_basic(mki_ctx, + task->lp_ctx, + &mki_ctx->krb5_context); + if (code != 0) { + return NT_STATUS_INTERNAL_ERROR; + } + + status = IRPC_REGISTER(task->msg_ctx, + irpc, + KDC_CHECK_GENERIC_KERBEROS, + netr_samlogon_generic_logon, + mki_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + irpc_add_name(task->msg_ctx, "kdc_server"); + + return status; +} |