2 * Unix SMB/CIFS implementation.
4 * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/kerberos.h"
22 #include "source4/auth/kerberos/kerberos.h"
23 #include "auth/kerberos/pac_utils.h"
25 #include "librpc/gen_ndr/irpc.h"
26 #include "lib/messaging/irpc.h"
27 #include "source4/librpc/gen_ndr/ndr_irpc.h"
28 #include "source4/librpc/gen_ndr/irpc.h"
30 #include "librpc/gen_ndr/ndr_krb5pac.h"
32 #include "source4/smbd/process_model.h"
33 #include "lib/param/param.h"
35 #include "samba_kdc.h"
38 #include "mit_kdc_irpc.h"
40 struct mit_kdc_irpc_context
{
41 struct task_server
*task
;
42 krb5_context krb5_context
;
43 struct samba_kdc_db_context
*db_ctx
;
46 static NTSTATUS
netr_samlogon_generic_logon(struct irpc_message
*msg
,
47 struct kdc_check_generic_kerberos
*r
)
49 struct PAC_Validate pac_validate
;
51 struct PAC_SIGNATURE_DATA pac_kdc_sig
;
52 struct mit_kdc_irpc_context
*mki_ctx
=
53 talloc_get_type(msg
->private_data
,
54 struct mit_kdc_irpc_context
);
55 enum ndr_err_code ndr_err
;
57 krb5_principal principal
;
58 struct sdb_entry_ex sentry
= {};
59 struct sdb_keys skeys
;
61 const uint8_t *d
= NULL
;
63 /* There is no reply to this request */
64 r
->out
.generic_reply
= data_blob(NULL
, 0);
67 ndr_pull_struct_blob(&r
->in
.generic_request
,
70 (ndr_pull_flags_fn_t
)ndr_pull_PAC_Validate
);
71 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
72 return NT_STATUS_INVALID_PARAMETER
;
75 if (pac_validate
.MessageType
!= NETLOGON_GENERIC_KRB5_PAC_VALIDATE
) {
77 * We don't implement any other message types - such as
78 * certificate validation - yet
80 return NT_STATUS_INVALID_PARAMETER
;
83 if ((pac_validate
.ChecksumAndSignature
.length
!=
84 (pac_validate
.ChecksumLength
+ pac_validate
.SignatureLength
)) ||
85 (pac_validate
.ChecksumAndSignature
.length
<
86 pac_validate
.ChecksumLength
) ||
87 (pac_validate
.ChecksumAndSignature
.length
<
88 pac_validate
.SignatureLength
)) {
89 return NT_STATUS_INVALID_PARAMETER
;
93 pac_chksum
= data_blob_const(pac_validate
.ChecksumAndSignature
.data
,
94 pac_validate
.ChecksumLength
);
96 /* Create the krbtgt principal */
97 code
= smb_krb5_make_principal(mki_ctx
->krb5_context
,
99 lpcfg_realm(mki_ctx
->task
->lp_ctx
),
101 lpcfg_realm(mki_ctx
->task
->lp_ctx
),
104 DEBUG(0, ("Failed to create krbtgt@%s principal!\n",
105 lpcfg_realm(mki_ctx
->task
->lp_ctx
)));
106 return NT_STATUS_NO_MEMORY
;
109 /* Get the krbtgt from the DB */
110 code
= samba_kdc_fetch(mki_ctx
->krb5_context
,
113 SDB_F_GET_KRBTGT
| SDB_F_DECRYPT
,
116 krb5_free_principal(mki_ctx
->krb5_context
, principal
);
118 DEBUG(0, ("Failed to fetch krbtgt@%s principal entry!\n",
119 lpcfg_realm(mki_ctx
->task
->lp_ctx
)));
120 return NT_STATUS_LOGON_FAILURE
;
124 pac_kdc_sig
.type
= pac_validate
.SignatureType
;
126 d
= &pac_validate
.ChecksumAndSignature
.data
[pac_validate
.ChecksumLength
];
127 pac_kdc_sig
.signature
=
128 data_blob_const(d
, pac_validate
.SignatureLength
);
131 * Brute force variant because MIT KRB5 doesn't provide a function like
132 * krb5_checksum_to_enctype().
134 skeys
= sentry
.entry
.keys
;
136 for (i
= 0; i
< skeys
.len
; i
++) {
137 krb5_keyblock krbtgt_keyblock
= skeys
.val
[i
].key
;
139 code
= check_pac_checksum(pac_chksum
,
141 mki_ctx
->krb5_context
,
148 sdb_free_entry(&sentry
);
151 return NT_STATUS_LOGON_FAILURE
;
157 NTSTATUS
samba_setup_mit_kdc_irpc(struct task_server
*task
)
159 struct samba_kdc_base_context base_ctx
;
160 struct mit_kdc_irpc_context
*mki_ctx
;
164 mki_ctx
= talloc_zero(task
, struct mit_kdc_irpc_context
);
165 if (mki_ctx
== NULL
) {
166 return NT_STATUS_NO_MEMORY
;
168 mki_ctx
->task
= task
;
170 base_ctx
.ev_ctx
= task
->event_ctx
;
171 base_ctx
.lp_ctx
= task
->lp_ctx
;
174 status
= samba_kdc_setup_db_ctx(mki_ctx
,
177 if (!NT_STATUS_IS_OK(status
)) {
181 code
= smb_krb5_init_context_basic(mki_ctx
,
183 &mki_ctx
->krb5_context
);
185 return NT_STATUS_INTERNAL_ERROR
;
188 status
= IRPC_REGISTER(task
->msg_ctx
,
190 KDC_CHECK_GENERIC_KERBEROS
,
191 netr_samlogon_generic_logon
,
193 if (!NT_STATUS_IS_OK(status
)) {
197 irpc_add_name(task
->msg_ctx
, "kdc_server");