drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / third_party / heimdal / kdc / misc.c
blob00bbe0ce4bf613eb2483cb5d9d218aa48c572947
1 /*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "kdc_locl.h"
36 static int
37 name_type_ok(krb5_context context,
38 krb5_kdc_configuration *config,
39 krb5_const_principal principal)
41 int nt = krb5_principal_get_type(context, principal);
43 if (!krb5_principal_is_krbtgt(context, principal))
44 return 1;
45 if (nt == KRB5_NT_SRV_INST || nt == KRB5_NT_UNKNOWN)
46 return 1;
47 if (config->strict_nametypes == 0)
48 return 1;
49 return 0;
52 struct timeval _kdc_now;
54 static krb5_error_code
55 synthesize_hdb_close(krb5_context context, struct HDB *db)
57 (void) context;
58 (void) db;
59 return 0;
63 * Synthesize an HDB entry suitable for PKINIT and GSS preauth.
65 static krb5_error_code
66 synthesize_client(krb5_context context,
67 krb5_kdc_configuration *config,
68 krb5_const_principal princ,
69 HDB **db,
70 hdb_entry **h)
72 static HDB null_db;
73 krb5_error_code ret;
74 hdb_entry *e;
76 /* Hope this works! */
77 null_db.hdb_destroy = synthesize_hdb_close;
78 null_db.hdb_close = synthesize_hdb_close;
79 if (db)
80 *db = &null_db;
82 ret = (e = calloc(1, sizeof(*e))) ? 0 : krb5_enomem(context);
83 if (ret == 0) {
84 e->flags.client = 1;
85 e->flags.immutable = 1;
86 e->flags.virtual = 1;
87 e->flags.synthetic = 1;
88 e->flags.do_not_store = 1;
89 e->kvno = 1;
90 e->keys.len = 0;
91 e->keys.val = NULL;
92 e->created_by.time = time(NULL);
93 e->modified_by = NULL;
94 e->valid_start = NULL;
95 e->valid_end = NULL;
96 e->pw_end = NULL;
97 e->etypes = NULL;
98 e->generation = NULL;
99 e->extensions = NULL;
101 if (ret == 0)
102 ret = (e->max_renew = calloc(1, sizeof(*e->max_renew))) ?
103 0 : krb5_enomem(context);
104 if (ret == 0)
105 ret = (e->max_life = calloc(1, sizeof(*e->max_life))) ?
106 0 : krb5_enomem(context);
107 if (ret == 0)
108 ret = krb5_copy_principal(context, princ, &e->principal);
109 if (ret == 0)
110 ret = krb5_copy_principal(context, princ, &e->created_by.principal);
111 if (ret == 0) {
113 * We can't check OCSP in the TGS path, so we can't let tickets for
114 * synthetic principals live very long.
116 *(e->max_renew) = config->synthetic_clients_max_renew;
117 *(e->max_life) = config->synthetic_clients_max_life;
118 *h = e;
119 } else if (e) {
120 hdb_free_entry(context, &null_db, e);
122 return ret;
125 KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL
126 _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)
134 hdb_entry *ent = NULL;
135 krb5_error_code ret = HDB_ERR_NOENTRY;
136 int i;
137 unsigned kvno = 0;
138 krb5_principal enterprise_principal = NULL;
139 krb5_const_principal princ;
141 *h = NULL;
142 if (db)
143 *db = NULL;
145 if (!name_type_ok(context, config, principal))
146 return HDB_ERR_NOENTRY;
148 flags |= HDB_F_DECRYPT;
149 if (kvno_ptr != NULL && *kvno_ptr != 0) {
150 kvno = *kvno_ptr;
151 flags |= HDB_F_KVNO_SPECIFIED;
152 } else {
153 flags |= HDB_F_ALL_KVNOS;
156 ent = calloc(1, sizeof (*ent));
157 if (ent == NULL)
158 return krb5_enomem(context);
160 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
161 if (principal->name.name_string.len != 1) {
162 ret = KRB5_PARSE_MALFORMED;
163 krb5_set_error_message(context, ret,
164 "malformed request: "
165 "enterprise name with %d name components",
166 principal->name.name_string.len);
167 goto out;
169 ret = krb5_parse_name(context, principal->name.name_string.val[0],
170 &enterprise_principal);
171 if (ret)
172 goto out;
175 for (i = 0; i < config->num_db; i++) {
176 HDB *curdb = config->db[i];
178 if (db)
179 *db = curdb;
181 ret = curdb->hdb_open(context, curdb, O_RDONLY, 0);
182 if (ret) {
183 const char *msg = krb5_get_error_message(context, ret);
184 kdc_log(context, config, 0, "Failed to open database: %s", msg);
185 krb5_free_error_message(context, msg);
186 continue;
189 princ = principal;
190 if (!(curdb->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal)
191 princ = enterprise_principal;
193 ret = hdb_fetch_kvno(context, curdb, princ, flags, 0, 0, kvno, ent);
194 curdb->hdb_close(context, curdb);
196 if (ret == HDB_ERR_NOENTRY)
197 continue; /* Check the other databases */
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.
206 break;
209 switch (ret) {
210 case HDB_ERR_WRONG_REALM:
211 case 0:
213 * the ent->entry.principal just contains hints for the client
214 * to retry. This is important for enterprise principal routing
215 * between trusts.
217 *h = ent;
218 ent = NULL;
219 break;
221 case HDB_ERR_NOENTRY:
222 if (db)
223 *db = NULL;
224 if ((flags & HDB_F_GET_CLIENT) && (flags & HDB_F_SYNTHETIC_OK) &&
225 config->synthetic_clients) {
226 ret = synthesize_client(context, config, principal, db, h);
227 if (ret) {
228 krb5_set_error_message(context, ret, "could not synthesize "
229 "HDB client principal entry");
230 ret = HDB_ERR_NOENTRY;
231 krb5_prepend_error_message(context, ret, "no such entry found in hdb");
233 } else {
234 krb5_set_error_message(context, ret, "no such entry found in hdb");
236 break;
238 default:
239 if (db)
240 *db = NULL;
241 break;
244 out:
245 krb5_free_principal(context, enterprise_principal);
246 free(ent);
247 return ret;
250 KDC_LIB_FUNCTION void KDC_LIB_CALL
251 _kdc_free_ent(krb5_context context, HDB *db, hdb_entry *ent)
253 hdb_free_entry (context, db, ent);
254 free (ent);
258 * Use the order list of preferred encryption types and sort the
259 * available keys and return the most preferred key.
262 krb5_error_code
263 _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)
270 krb5_error_code ret;
271 int i;
273 if (config->use_strongest_server_key) {
274 const krb5_enctype *p = krb5_kerberos_enctypes(context);
276 for (i = 0; p[i] != ETYPE_NULL; i++) {
277 if (krb5_enctype_valid(context, p[i]) != 0 &&
278 !_kdc_is_weak_exception(h->principal, p[i]))
279 continue;
280 ret = hdb_enctype2key(context, h, NULL, p[i], key);
281 if (ret != 0)
282 continue;
283 if (enctype != NULL)
284 *enctype = p[i];
285 return 0;
287 } else {
288 *key = NULL;
290 for (i = 0; i < h->keys.len; i++) {
291 if (krb5_enctype_valid(context, h->keys.val[i].key.keytype) != 0 &&
292 !_kdc_is_weak_exception(h->principal, h->keys.val[i].key.keytype))
293 continue;
294 ret = hdb_enctype2key(context, h, NULL,
295 h->keys.val[i].key.keytype, key);
296 if (ret != 0)
297 continue;
298 if (enctype != NULL)
299 *enctype = (*key)->key.keytype;
300 return 0;
304 krb5_set_error_message(context, ret = KRB5KDC_ERR_ETYPE_NOSUPP,
305 "No valid kerberos key found for %s", name);
306 return ret;
309 krb5_error_code
310 _kdc_verify_checksum(krb5_context context,
311 krb5_crypto crypto,
312 krb5_key_usage usage,
313 const krb5_data *data,
314 Checksum *cksum)
316 krb5_error_code ret;
318 ret = krb5_verify_checksum(context, crypto, usage,
319 data->data, data->length,
320 cksum);
321 if (ret == KRB5_PROG_SUMTYPE_NOSUPP)
322 ret = KRB5KDC_ERR_SUMTYPE_NOSUPP;
324 return ret;
328 * Returns TRUE if a PAC should be included in ticket authorization data.
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.
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.
340 krb5_boolean
341 _kdc_include_pac_p(astgs_request_t r)
343 return TRUE;
347 * Notify the HDB backend and KDC plugin of the audited event.
350 krb5_error_code
351 _kdc_audit_request(astgs_request_t r)
353 krb5_error_code ret;
354 struct HDB *hdb;
356 ret = _kdc_plugin_audit(r);
357 if (ret == 0 &&
358 (hdb = r->clientdb ? r->clientdb : r->config->db[0]) &&
359 hdb->hdb_audit)
360 ret = hdb->hdb_audit(r->context, hdb, r->client, (hdb_request_t)r);
362 return ret;