Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
5 : *
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.
10 : *
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.
15 : *
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/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/kerberos.h"
22 : #include "source4/auth/kerberos/kerberos.h"
23 : #include "auth/kerberos/pac_utils.h"
24 :
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"
29 :
30 : #include "librpc/gen_ndr/ndr_krb5pac.h"
31 :
32 : #include "source4/samba/process_model.h"
33 : #include "lib/param/param.h"
34 :
35 : #include "samba_kdc.h"
36 : #include "db-glue.h"
37 : #include "sdb.h"
38 : #include "mit_kdc_irpc.h"
39 :
40 : #undef DBGC_CLASS
41 : #define DBGC_CLASS DBGC_KERBEROS
42 :
43 : struct mit_kdc_irpc_context {
44 : struct task_server *task;
45 : krb5_context krb5_context;
46 : struct samba_kdc_db_context *db_ctx;
47 : };
48 :
49 0 : static NTSTATUS netr_samlogon_generic_logon(struct irpc_message *msg,
50 : struct kdc_check_generic_kerberos *r)
51 : {
52 : struct PAC_Validate pac_validate;
53 : DATA_BLOB pac_chksum;
54 : struct PAC_SIGNATURE_DATA pac_kdc_sig;
55 : struct mit_kdc_irpc_context *mki_ctx =
56 0 : talloc_get_type(msg->private_data,
57 : struct mit_kdc_irpc_context);
58 : enum ndr_err_code ndr_err;
59 : int code;
60 : krb5_principal principal;
61 0 : struct sdb_entry sentry = {};
62 : struct sdb_keys skeys;
63 : unsigned int i;
64 0 : const uint8_t *d = NULL;
65 :
66 : /* There is no reply to this request */
67 0 : r->out.generic_reply = data_blob(NULL, 0);
68 :
69 : ndr_err =
70 0 : ndr_pull_struct_blob(&r->in.generic_request,
71 : msg,
72 : &pac_validate,
73 : (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
74 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
75 0 : return NT_STATUS_INVALID_PARAMETER;
76 : }
77 :
78 0 : if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) {
79 : /*
80 : * We don't implement any other message types - such as
81 : * certificate validation - yet
82 : */
83 0 : return NT_STATUS_INVALID_PARAMETER;
84 : }
85 :
86 0 : if ((pac_validate.ChecksumAndSignature.length !=
87 0 : (pac_validate.ChecksumLength + pac_validate.SignatureLength)) ||
88 0 : (pac_validate.ChecksumAndSignature.length <
89 0 : pac_validate.ChecksumLength) ||
90 0 : (pac_validate.ChecksumAndSignature.length <
91 0 : pac_validate.SignatureLength)) {
92 0 : return NT_STATUS_INVALID_PARAMETER;
93 : }
94 :
95 : /* PAC Checksum */
96 0 : pac_chksum = data_blob_const(pac_validate.ChecksumAndSignature.data,
97 0 : pac_validate.ChecksumLength);
98 :
99 : /* Create the krbtgt principal */
100 0 : code = smb_krb5_make_principal(mki_ctx->krb5_context,
101 : &principal,
102 0 : lpcfg_realm(mki_ctx->task->lp_ctx),
103 : "krbtgt",
104 0 : lpcfg_realm(mki_ctx->task->lp_ctx),
105 : NULL);
106 0 : if (code != 0) {
107 0 : DEBUG(0, ("Failed to create krbtgt@%s principal!\n",
108 : lpcfg_realm(mki_ctx->task->lp_ctx)));
109 0 : return NT_STATUS_NO_MEMORY;
110 : }
111 :
112 : /* Get the krbtgt from the DB */
113 0 : code = samba_kdc_fetch(mki_ctx->krb5_context,
114 : mki_ctx->db_ctx,
115 : principal,
116 : SDB_F_GET_KRBTGT | SDB_F_DECRYPT,
117 : 0,
118 : &sentry);
119 0 : krb5_free_principal(mki_ctx->krb5_context, principal);
120 0 : if (code != 0) {
121 0 : DEBUG(0, ("Failed to fetch krbtgt@%s principal entry!\n",
122 : lpcfg_realm(mki_ctx->task->lp_ctx)));
123 0 : return NT_STATUS_LOGON_FAILURE;
124 : }
125 :
126 : /* PAC Signature */
127 0 : pac_kdc_sig.type = pac_validate.SignatureType;
128 :
129 0 : d = &pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength];
130 : pac_kdc_sig.signature =
131 0 : data_blob_const(d, pac_validate.SignatureLength);
132 :
133 : /*
134 : * Brute force variant because MIT KRB5 doesn't provide a function like
135 : * krb5_checksum_to_enctype().
136 : */
137 0 : skeys = sentry.keys;
138 :
139 0 : for (i = 0; i < skeys.len; i++) {
140 0 : krb5_keyblock krbtgt_keyblock = skeys.val[i].key;
141 :
142 0 : code = check_pac_checksum(pac_chksum,
143 : &pac_kdc_sig,
144 : mki_ctx->krb5_context,
145 : &krbtgt_keyblock);
146 0 : if (code == 0) {
147 0 : break;
148 : }
149 : }
150 :
151 0 : sdb_entry_free(&sentry);
152 :
153 0 : if (code != 0) {
154 0 : return NT_STATUS_LOGON_FAILURE;
155 : }
156 :
157 0 : return NT_STATUS_OK;
158 : }
159 :
160 13 : NTSTATUS samba_setup_mit_kdc_irpc(struct task_server *task)
161 : {
162 : struct samba_kdc_base_context base_ctx;
163 : struct mit_kdc_irpc_context *mki_ctx;
164 : NTSTATUS status;
165 : int code;
166 :
167 13 : mki_ctx = talloc_zero(task, struct mit_kdc_irpc_context);
168 13 : if (mki_ctx == NULL) {
169 0 : return NT_STATUS_NO_MEMORY;
170 : }
171 13 : mki_ctx->task = task;
172 :
173 13 : base_ctx.ev_ctx = task->event_ctx;
174 13 : base_ctx.lp_ctx = task->lp_ctx;
175 :
176 : /* db-glue.h */
177 13 : status = samba_kdc_setup_db_ctx(mki_ctx,
178 : &base_ctx,
179 : &mki_ctx->db_ctx);
180 13 : if (!NT_STATUS_IS_OK(status)) {
181 0 : return status;
182 : }
183 :
184 13 : code = smb_krb5_init_context_basic(mki_ctx,
185 : task->lp_ctx,
186 : &mki_ctx->krb5_context);
187 13 : if (code != 0) {
188 0 : return NT_STATUS_INTERNAL_ERROR;
189 : }
190 :
191 13 : status = IRPC_REGISTER(task->msg_ctx,
192 : irpc,
193 : KDC_CHECK_GENERIC_KERBEROS,
194 : netr_samlogon_generic_logon,
195 : mki_ctx);
196 13 : if (!NT_STATUS_IS_OK(status)) {
197 0 : return status;
198 : }
199 :
200 13 : irpc_add_name(task->msg_ctx, "kdc_server");
201 :
202 13 : return status;
203 : }
|