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/samba/process_model.h"
33 #include "lib/param/param.h"
35 #include "samba_kdc.h"
38 #include "mit_kdc_irpc.h"
41 #define DBGC_CLASS DBGC_KERBEROS
43 struct mit_kdc_irpc_context
{
44 struct task_server
*task
;
45 krb5_context krb5_context
;
46 struct samba_kdc_db_context
*db_ctx
;
49 static NTSTATUS
netr_samlogon_generic_logon(struct irpc_message
*msg
,
50 struct kdc_check_generic_kerberos
*r
)
52 struct PAC_Validate pac_validate
;
54 struct PAC_SIGNATURE_DATA pac_kdc_sig
;
55 struct mit_kdc_irpc_context
*mki_ctx
=
56 talloc_get_type(msg
->private_data
,
57 struct mit_kdc_irpc_context
);
58 enum ndr_err_code ndr_err
;
60 krb5_principal principal
;
61 struct sdb_entry sentry
= {};
62 struct sdb_keys skeys
;
64 const uint8_t *d
= NULL
;
66 /* There is no reply to this request */
67 r
->out
.generic_reply
= data_blob(NULL
, 0);
70 ndr_pull_struct_blob(&r
->in
.generic_request
,
73 (ndr_pull_flags_fn_t
)ndr_pull_PAC_Validate
);
74 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
75 return NT_STATUS_INVALID_PARAMETER
;
78 if (pac_validate
.MessageType
!= NETLOGON_GENERIC_KRB5_PAC_VALIDATE
) {
80 * We don't implement any other message types - such as
81 * certificate validation - yet
83 return NT_STATUS_INVALID_PARAMETER
;
86 if ((pac_validate
.ChecksumAndSignature
.length
!=
87 (pac_validate
.ChecksumLength
+ pac_validate
.SignatureLength
)) ||
88 (pac_validate
.ChecksumAndSignature
.length
<
89 pac_validate
.ChecksumLength
) ||
90 (pac_validate
.ChecksumAndSignature
.length
<
91 pac_validate
.SignatureLength
)) {
92 return NT_STATUS_INVALID_PARAMETER
;
96 pac_chksum
= data_blob_const(pac_validate
.ChecksumAndSignature
.data
,
97 pac_validate
.ChecksumLength
);
99 /* Create the krbtgt principal */
100 code
= smb_krb5_make_principal(mki_ctx
->krb5_context
,
102 lpcfg_realm(mki_ctx
->task
->lp_ctx
),
104 lpcfg_realm(mki_ctx
->task
->lp_ctx
),
107 DBG_ERR("Failed to create krbtgt@%s principal!\n",
108 lpcfg_realm(mki_ctx
->task
->lp_ctx
));
109 return NT_STATUS_NO_MEMORY
;
112 /* Get the krbtgt from the DB */
113 code
= samba_kdc_fetch(mki_ctx
->krb5_context
,
116 SDB_F_GET_KRBTGT
| SDB_F_DECRYPT
,
119 krb5_free_principal(mki_ctx
->krb5_context
, principal
);
121 DBG_ERR("Failed to fetch krbtgt@%s principal entry!\n",
122 lpcfg_realm(mki_ctx
->task
->lp_ctx
));
123 return NT_STATUS_LOGON_FAILURE
;
127 pac_kdc_sig
.type
= pac_validate
.SignatureType
;
129 d
= &pac_validate
.ChecksumAndSignature
.data
[pac_validate
.ChecksumLength
];
130 pac_kdc_sig
.signature
=
131 data_blob_const(d
, pac_validate
.SignatureLength
);
134 * Brute force variant because MIT KRB5 doesn't provide a function like
135 * krb5_checksum_to_enctype().
140 for (i
= 0; i
< skeys
.len
; i
++) {
141 krb5_keyblock krbtgt_keyblock
= skeys
.val
[i
].key
;
143 code
= check_pac_checksum(pac_chksum
,
145 mki_ctx
->krb5_context
,
152 sdb_entry_free(&sentry
);
155 return NT_STATUS_LOGON_FAILURE
;
161 NTSTATUS
samba_setup_mit_kdc_irpc(struct task_server
*task
)
163 struct samba_kdc_base_context base_ctx
= {};
164 struct mit_kdc_irpc_context
*mki_ctx
;
168 mki_ctx
= talloc_zero(task
, struct mit_kdc_irpc_context
);
169 if (mki_ctx
== NULL
) {
170 return NT_STATUS_NO_MEMORY
;
172 mki_ctx
->task
= task
;
174 base_ctx
.ev_ctx
= task
->event_ctx
;
175 base_ctx
.lp_ctx
= task
->lp_ctx
;
178 status
= samba_kdc_setup_db_ctx(mki_ctx
,
181 if (!NT_STATUS_IS_OK(status
)) {
185 code
= smb_krb5_init_context_basic(mki_ctx
,
187 &mki_ctx
->krb5_context
);
189 return NT_STATUS_INTERNAL_ERROR
;
192 status
= IRPC_REGISTER(task
->msg_ctx
,
194 KDC_CHECK_GENERIC_KERBEROS
,
195 netr_samlogon_generic_logon
,
197 if (!NT_STATUS_IS_OK(status
)) {
201 irpc_add_name(task
->msg_ctx
, "kdc_server");