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 305873 : name_type_ok(krb5_context context,
38 : krb5_kdc_configuration *config,
39 : krb5_const_principal principal)
40 : {
41 305873 : int nt = krb5_principal_get_type(context, principal);
42 :
43 305873 : if (!krb5_principal_is_krbtgt(context, principal))
44 125865 : return 1;
45 175972 : if (nt == KRB5_NT_SRV_INST || nt == KRB5_NT_UNKNOWN)
46 169833 : 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 305873 : _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 305873 : hdb_entry *ent = NULL;
135 305873 : krb5_error_code ret = HDB_ERR_NOENTRY;
136 10142 : int i;
137 305873 : unsigned kvno = 0;
138 305873 : krb5_principal enterprise_principal = NULL;
139 10142 : krb5_const_principal princ;
140 :
141 305873 : *h = NULL;
142 305873 : if (db)
143 305873 : *db = NULL;
144 :
145 305873 : if (!name_type_ok(context, config, principal))
146 0 : return HDB_ERR_NOENTRY;
147 :
148 305873 : flags |= HDB_F_DECRYPT;
149 305873 : if (kvno_ptr != NULL && *kvno_ptr != 0) {
150 51936 : kvno = *kvno_ptr;
151 51936 : flags |= HDB_F_KVNO_SPECIFIED;
152 : } else {
153 253937 : flags |= HDB_F_ALL_KVNOS;
154 : }
155 :
156 305873 : ent = calloc(1, sizeof (*ent));
157 305873 : if (ent == NULL)
158 0 : return krb5_enomem(context);
159 :
160 305873 : if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
161 3178 : 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 3172 : ret = krb5_parse_name(context, principal->name.name_string.val[0],
170 : &enterprise_principal);
171 3172 : if (ret)
172 0 : goto out;
173 : }
174 :
175 307473 : for (i = 0; i < config->num_db; i++) {
176 305867 : HDB *curdb = config->db[i];
177 :
178 305867 : if (db)
179 305867 : *db = curdb;
180 :
181 305867 : ret = curdb->hdb_open(context, curdb, O_RDONLY, 0);
182 305867 : 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 305867 : princ = principal;
190 305867 : if (!(curdb->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal)
191 0 : princ = enterprise_principal;
192 :
193 305867 : ret = hdb_fetch_kvno(context, curdb, princ, flags, 0, 0, kvno, ent);
194 305867 : curdb->hdb_close(context, curdb);
195 :
196 305867 : if (ret == HDB_ERR_NOENTRY)
197 1606 : 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 294119 : break;
207 : }
208 :
209 305867 : switch (ret) {
210 301241 : 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 301241 : *h = ent;
218 301241 : ent = NULL;
219 301241 : break;
220 :
221 1606 : case HDB_ERR_NOENTRY:
222 1606 : if (db)
223 1606 : *db = NULL;
224 1606 : 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 1606 : krb5_set_error_message(context, ret, "no such entry found in hdb");
235 : }
236 1606 : break;
237 :
238 3020 : default:
239 3020 : if (db)
240 3020 : *db = NULL;
241 3020 : break;
242 : }
243 :
244 305873 : out:
245 305873 : krb5_free_principal(context, enterprise_principal);
246 305873 : free(ent);
247 305873 : return ret;
248 : }
249 :
250 : KDC_LIB_FUNCTION void KDC_LIB_CALL
251 300783 : _kdc_free_ent(krb5_context context, HDB *db, hdb_entry *ent)
252 : {
253 300783 : hdb_free_entry (context, db, ent);
254 300783 : free (ent);
255 300783 : }
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 150031 : _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 150031 : if (config->use_strongest_server_key) {
274 150031 : const krb5_enctype *p = krb5_kerberos_enctypes(context);
275 :
276 236524 : for (i = 0; p[i] != ETYPE_NULL; i++) {
277 231177 : if (krb5_enctype_valid(context, p[i]) != 0 &&
278 0 : !_kdc_is_weak_exception(h->principal, p[i]))
279 0 : continue;
280 231177 : ret = hdb_enctype2key(context, h, NULL, p[i], key);
281 231177 : if (ret != 0)
282 81422 : continue;
283 149755 : if (enctype != NULL)
284 47815 : *enctype = p[i];
285 149755 : 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 93877 : _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 97193 : ret = krb5_verify_checksum(context, crypto, usage,
319 93877 : data->data, data->length,
320 : cksum);
321 93877 : if (ret == KRB5_PROG_SUMTYPE_NOSUPP)
322 2 : ret = KRB5KDC_ERR_SUMTYPE_NOSUPP;
323 :
324 93877 : 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 48121 : _kdc_include_pac_p(astgs_request_t r)
342 : {
343 48121 : return TRUE;
344 : }
345 :
346 : /*
347 : * Notify the HDB backend and KDC plugin of the audited event.
348 : */
349 :
350 : krb5_error_code
351 102025 : _kdc_audit_request(astgs_request_t r)
352 : {
353 3413 : krb5_error_code ret;
354 3413 : struct HDB *hdb;
355 :
356 102025 : ret = _kdc_plugin_audit(r);
357 102025 : if (ret == 0 &&
358 102025 : (hdb = r->clientdb ? r->clientdb : r->config->db[0]) &&
359 102025 : hdb->hdb_audit)
360 102025 : ret = hdb->hdb_audit(r->context, hdb, r->client, (hdb_request_t)r);
361 :
362 102025 : return ret;
363 : }
|