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