Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "kdc_locl.h"
35 :
36 : static int
37 313879 : name_type_ok(krb5_context context,
38 : krb5_kdc_configuration *config,
39 : krb5_const_principal principal)
40 : {
41 313879 : int nt = krb5_principal_get_type(context, principal);
42 :
43 313879 : if (!krb5_principal_is_krbtgt(context, principal))
44 129237 : return 1;
45 180606 : if (nt == KRB5_NT_SRV_INST || nt == KRB5_NT_UNKNOWN)
46 174467 : return 1;
47 33 : if (config->strict_nametypes == 0)
48 33 : return 1;
49 0 : return 0;
50 : }
51 :
52 : struct timeval _kdc_now;
53 :
54 : static krb5_error_code
55 0 : synthesize_hdb_close(krb5_context context, struct HDB *db)
56 : {
57 0 : (void) context;
58 0 : (void) db;
59 0 : return 0;
60 : }
61 :
62 : /*
63 : * Synthesize an HDB entry suitable for PKINIT and GSS preauth.
64 : */
65 : static krb5_error_code
66 0 : synthesize_client(krb5_context context,
67 : krb5_kdc_configuration *config,
68 : krb5_const_principal princ,
69 : HDB **db,
70 : hdb_entry **h)
71 : {
72 0 : static HDB null_db;
73 0 : krb5_error_code ret;
74 0 : hdb_entry *e;
75 :
76 : /* Hope this works! */
77 0 : null_db.hdb_destroy = synthesize_hdb_close;
78 0 : null_db.hdb_close = synthesize_hdb_close;
79 0 : if (db)
80 0 : *db = &null_db;
81 :
82 0 : ret = (e = calloc(1, sizeof(*e))) ? 0 : krb5_enomem(context);
83 0 : if (ret == 0) {
84 0 : e->flags.client = 1;
85 0 : e->flags.immutable = 1;
86 0 : e->flags.virtual = 1;
87 0 : e->flags.synthetic = 1;
88 0 : e->flags.do_not_store = 1;
89 0 : e->kvno = 1;
90 0 : e->keys.len = 0;
91 0 : e->keys.val = NULL;
92 0 : e->created_by.time = time(NULL);
93 0 : e->modified_by = NULL;
94 0 : e->valid_start = NULL;
95 0 : e->valid_end = NULL;
96 0 : e->pw_end = NULL;
97 0 : e->etypes = NULL;
98 0 : e->generation = NULL;
99 0 : e->extensions = NULL;
100 : }
101 0 : if (ret == 0)
102 0 : ret = (e->max_renew = calloc(1, sizeof(*e->max_renew))) ?
103 0 : 0 : krb5_enomem(context);
104 0 : if (ret == 0)
105 0 : ret = (e->max_life = calloc(1, sizeof(*e->max_life))) ?
106 0 : 0 : krb5_enomem(context);
107 0 : if (ret == 0)
108 0 : ret = krb5_copy_principal(context, princ, &e->principal);
109 0 : if (ret == 0)
110 0 : ret = krb5_copy_principal(context, princ, &e->created_by.principal);
111 0 : if (ret == 0) {
112 : /*
113 : * We can't check OCSP in the TGS path, so we can't let tickets for
114 : * synthetic principals live very long.
115 : */
116 0 : *(e->max_renew) = config->synthetic_clients_max_renew;
117 0 : *(e->max_life) = config->synthetic_clients_max_life;
118 0 : *h = e;
119 0 : } else if (e) {
120 0 : hdb_free_entry(context, &null_db, e);
121 : }
122 0 : return ret;
123 : }
124 :
125 : KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL
126 313879 : _kdc_db_fetch(krb5_context context,
127 : krb5_kdc_configuration *config,
128 : krb5_const_principal principal,
129 : unsigned flags,
130 : krb5uint32 *kvno_ptr,
131 : HDB **db,
132 : hdb_entry **h)
133 : {
134 313879 : hdb_entry *ent = NULL;
135 313879 : krb5_error_code ret = HDB_ERR_NOENTRY;
136 10142 : int i;
137 313879 : unsigned kvno = 0;
138 313879 : krb5_principal enterprise_principal = NULL;
139 10142 : krb5_const_principal princ;
140 :
141 313879 : *h = NULL;
142 313879 : if (db)
143 313879 : *db = NULL;
144 :
145 313879 : if (!name_type_ok(context, config, principal))
146 0 : return HDB_ERR_NOENTRY;
147 :
148 313879 : flags |= HDB_F_DECRYPT;
149 313879 : if (kvno_ptr != NULL && *kvno_ptr != 0) {
150 53247 : kvno = *kvno_ptr;
151 53247 : flags |= HDB_F_KVNO_SPECIFIED;
152 : } else {
153 260632 : flags |= HDB_F_ALL_KVNOS;
154 : }
155 :
156 313879 : ent = calloc(1, sizeof (*ent));
157 313879 : if (ent == NULL)
158 0 : return krb5_enomem(context);
159 :
160 313879 : if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
161 3430 : if (principal->name.name_string.len != 1) {
162 6 : ret = KRB5_PARSE_MALFORMED;
163 6 : krb5_set_error_message(context, ret,
164 : "malformed request: "
165 : "enterprise name with %d name components",
166 6 : principal->name.name_string.len);
167 6 : goto out;
168 : }
169 3424 : ret = krb5_parse_name(context, principal->name.name_string.val[0],
170 : &enterprise_principal);
171 3424 : if (ret)
172 0 : goto out;
173 : }
174 :
175 315623 : for (i = 0; i < config->num_db; i++) {
176 313873 : HDB *curdb = config->db[i];
177 :
178 313873 : if (db)
179 313873 : *db = curdb;
180 :
181 313873 : ret = curdb->hdb_open(context, curdb, O_RDONLY, 0);
182 313873 : if (ret) {
183 0 : const char *msg = krb5_get_error_message(context, ret);
184 0 : kdc_log(context, config, 0, "Failed to open database: %s", msg);
185 0 : krb5_free_error_message(context, msg);
186 0 : continue;
187 : }
188 :
189 313873 : princ = principal;
190 313873 : if (!(curdb->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal)
191 0 : princ = enterprise_principal;
192 :
193 313873 : ret = hdb_fetch_kvno(context, curdb, princ, flags, 0, 0, kvno, ent);
194 313873 : curdb->hdb_close(context, curdb);
195 :
196 313873 : if (ret == HDB_ERR_NOENTRY)
197 1750 : continue; /* Check the other databases */
198 :
199 : /*
200 : * This is really important, because errors like
201 : * HDB_ERR_NOT_FOUND_HERE (used to indicate to Samba that
202 : * the RODC on which this code is running does not have
203 : * the key we need, and so a proxy to the KDC is required)
204 : * have specific meaning, and need to be propogated up.
205 : */
206 301981 : break;
207 : }
208 :
209 313873 : switch (ret) {
210 309103 : case HDB_ERR_WRONG_REALM:
211 : case 0:
212 : /*
213 : * the ent->entry.principal just contains hints for the client
214 : * to retry. This is important for enterprise principal routing
215 : * between trusts.
216 : */
217 309103 : *h = ent;
218 309103 : ent = NULL;
219 309103 : break;
220 :
221 1750 : case HDB_ERR_NOENTRY:
222 1750 : if (db)
223 1750 : *db = NULL;
224 1750 : if ((flags & HDB_F_GET_CLIENT) && (flags & HDB_F_SYNTHETIC_OK) &&
225 : config->synthetic_clients) {
226 0 : ret = synthesize_client(context, config, principal, db, h);
227 0 : if (ret) {
228 0 : krb5_set_error_message(context, ret, "could not synthesize "
229 : "HDB client principal entry");
230 0 : ret = HDB_ERR_NOENTRY;
231 0 : krb5_prepend_error_message(context, ret, "no such entry found in hdb");
232 : }
233 : } else {
234 1750 : krb5_set_error_message(context, ret, "no such entry found in hdb");
235 : }
236 1750 : break;
237 :
238 3020 : default:
239 3020 : if (db)
240 3020 : *db = NULL;
241 3020 : break;
242 : }
243 :
244 313879 : out:
245 313879 : krb5_free_principal(context, enterprise_principal);
246 313879 : free(ent);
247 313879 : return ret;
248 : }
249 :
250 : KDC_LIB_FUNCTION void KDC_LIB_CALL
251 308639 : _kdc_free_ent(krb5_context context, HDB *db, hdb_entry *ent)
252 : {
253 308639 : hdb_free_entry (context, db, ent);
254 308639 : free (ent);
255 308639 : }
256 :
257 : /*
258 : * Use the order list of preferred encryption types and sort the
259 : * available keys and return the most preferred key.
260 : */
261 :
262 : krb5_error_code
263 153474 : _kdc_get_preferred_key(krb5_context context,
264 : krb5_kdc_configuration *config,
265 : hdb_entry *h,
266 : const char *name,
267 : krb5_enctype *enctype,
268 : Key **key)
269 : {
270 5071 : krb5_error_code ret;
271 5071 : int i;
272 :
273 153474 : if (config->use_strongest_server_key) {
274 153474 : const krb5_enctype *p = krb5_kerberos_enctypes(context);
275 :
276 240027 : for (i = 0; p[i] != ETYPE_NULL; i++) {
277 234680 : if (krb5_enctype_valid(context, p[i]) != 0 &&
278 0 : !_kdc_is_weak_exception(h->principal, p[i]))
279 0 : continue;
280 234680 : ret = hdb_enctype2key(context, h, NULL, p[i], key);
281 234680 : if (ret != 0)
282 81482 : continue;
283 153198 : if (enctype != NULL)
284 48916 : *enctype = p[i];
285 153198 : return 0;
286 : }
287 : } else {
288 0 : *key = NULL;
289 :
290 0 : for (i = 0; i < h->keys.len; i++) {
291 0 : if (krb5_enctype_valid(context, h->keys.val[i].key.keytype) != 0 &&
292 0 : !_kdc_is_weak_exception(h->principal, h->keys.val[i].key.keytype))
293 0 : continue;
294 0 : ret = hdb_enctype2key(context, h, NULL,
295 0 : h->keys.val[i].key.keytype, key);
296 0 : if (ret != 0)
297 0 : continue;
298 0 : if (enctype != NULL)
299 0 : *enctype = (*key)->key.keytype;
300 0 : return 0;
301 : }
302 : }
303 :
304 276 : krb5_set_error_message(context, ret = KRB5KDC_ERR_ETYPE_NOSUPP,
305 : "No valid kerberos key found for %s", name);
306 276 : return ret;
307 : }
308 :
309 : krb5_error_code
310 96497 : _kdc_verify_checksum(krb5_context context,
311 : krb5_crypto crypto,
312 : krb5_key_usage usage,
313 : const krb5_data *data,
314 : Checksum *cksum)
315 : {
316 3316 : krb5_error_code ret;
317 :
318 99813 : ret = krb5_verify_checksum(context, crypto, usage,
319 96497 : data->data, data->length,
320 : cksum);
321 96497 : if (ret == KRB5_PROG_SUMTYPE_NOSUPP)
322 2 : ret = KRB5KDC_ERR_SUMTYPE_NOSUPP;
323 :
324 96497 : return ret;
325 : }
326 :
327 : /*
328 : * Returns TRUE if a PAC should be included in ticket authorization data.
329 : *
330 : * Per [MS-KILE] 3.3.5.3, PACs are always included for TGTs; for service
331 : * tickets, policy is governed by whether the client explicitly requested
332 : * a PAC be omitted when requesting a TGT, or if the no-auth-data-reqd
333 : * flag is set on the service principal entry.
334 : *
335 : * However, when issuing a cross-realm TGT to an AD realm our PAC might not
336 : * interoperate correctly. Therefore we honor the no-auth-data-reqd HDB entry
337 : * flag on cross-realm TGTs.
338 : */
339 :
340 : krb5_boolean
341 49286 : _kdc_include_pac_p(astgs_request_t r)
342 : {
343 49286 : return TRUE;
344 : }
345 :
346 : /*
347 : * Notify the HDB backend and KDC plugin of the audited event.
348 : */
349 :
350 : krb5_error_code
351 104689 : _kdc_audit_request(astgs_request_t r)
352 : {
353 3413 : krb5_error_code ret;
354 3413 : struct HDB *hdb;
355 :
356 104689 : ret = _kdc_plugin_audit(r);
357 104689 : if (ret == 0 &&
358 104689 : (hdb = r->clientdb ? r->clientdb : r->config->db[0]) &&
359 104689 : hdb->hdb_audit)
360 104689 : ret = hdb->hdb_audit(r->context, hdb, r->client, (hdb_request_t)r);
361 :
362 104689 : return ret;
363 : }
|