Allow KDC to always return the salt in the PA-ETYPE-INFO[2]
[heimdal.git] / kdc / misc.c
blobdaa49a39e41b110b148b4d3a7d539c4ae789ddeb
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 only PKINIT.
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_ex **h)
72 static HDB null_db;
73 krb5_error_code ret;
74 hdb_entry_ex *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->entry.flags.client = 1;
85 e->entry.flags.immutable = 1;
86 e->entry.flags.virtual = 1;
87 e->entry.flags.synthetic = 1;
88 e->entry.flags.do_not_store = 1;
89 e->entry.kvno = 1;
90 e->entry.keys.len = 0;
91 e->entry.keys.val = NULL;
92 e->entry.created_by.time = time(NULL);
93 e->entry.modified_by = NULL;
94 e->entry.valid_start = NULL;
95 e->entry.valid_end = NULL;
96 e->entry.pw_end = NULL;
97 e->entry.etypes = NULL;
98 e->entry.generation = NULL;
99 e->entry.extensions = NULL;
101 if (ret == 0)
102 ret = (e->entry.max_renew = calloc(1, sizeof(*e->entry.max_renew))) ?
103 0 : krb5_enomem(context);
104 if (ret == 0)
105 ret = (e->entry.max_life = calloc(1, sizeof(*e->entry.max_life))) ?
106 0 : krb5_enomem(context);
107 if (ret == 0)
108 ret = krb5_copy_principal(context, princ, &e->entry.principal);
109 if (ret == 0)
110 ret = krb5_copy_principal(context, princ, &e->entry.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->entry.max_renew) = config->synthetic_clients_max_renew;
117 *(e->entry.max_life) = config->synthetic_clients_max_life;
118 *h = e;
119 } else {
120 hdb_free_entry(context, e);
122 return ret;
125 krb5_error_code
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_ex **h)
134 hdb_entry_ex *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;
143 if (!name_type_ok(context, config, principal))
144 return HDB_ERR_NOENTRY;
146 flags |= HDB_F_DECRYPT;
147 if (kvno_ptr != NULL && *kvno_ptr != 0) {
148 kvno = *kvno_ptr;
149 flags |= HDB_F_KVNO_SPECIFIED;
150 } else {
151 flags |= HDB_F_ALL_KVNOS;
154 ent = calloc(1, sizeof (*ent));
155 if (ent == NULL)
156 return krb5_enomem(context);
158 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
159 if (principal->name.name_string.len != 1) {
160 ret = KRB5_PARSE_MALFORMED;
161 krb5_set_error_message(context, ret,
162 "malformed request: "
163 "enterprise name with %d name components",
164 principal->name.name_string.len);
165 goto out;
167 ret = krb5_parse_name(context, principal->name.name_string.val[0],
168 &enterprise_principal);
169 if (ret)
170 goto out;
173 for (i = 0; i < config->num_db; i++) {
174 HDB *curdb = config->db[i];
176 if (db)
177 *db = curdb;
179 ret = curdb->hdb_open(context, curdb, O_RDONLY, 0);
180 if (ret) {
181 const char *msg = krb5_get_error_message(context, ret);
182 kdc_log(context, config, 0, "Failed to open database: %s", msg);
183 krb5_free_error_message(context, msg);
184 continue;
187 princ = principal;
188 if (!(curdb->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal)
189 princ = enterprise_principal;
191 ret = hdb_fetch_kvno(context, curdb, princ, flags, 0, 0, kvno, ent);
192 curdb->hdb_close(context, curdb);
194 if (ret == HDB_ERR_NOENTRY)
195 continue; /* Check the other databases */
198 * This is really important, because errors like
199 * HDB_ERR_NOT_FOUND_HERE (used to indicate to Samba that
200 * the RODC on which this code is running does not have
201 * the key we need, and so a proxy to the KDC is required)
202 * have specific meaning, and need to be propogated up.
204 break;
207 switch (ret) {
208 case HDB_ERR_WRONG_REALM:
209 case 0:
211 * the ent->entry.principal just contains hints for the client
212 * to retry. This is important for enterprise principal routing
213 * between trusts.
215 *h = ent;
216 ent = NULL;
217 break;
219 case HDB_ERR_NOENTRY:
220 if (db)
221 *db = NULL;
222 if ((flags & HDB_F_GET_CLIENT) && (flags & HDB_F_SYNTHETIC_OK) &&
223 config->synthetic_clients) {
224 ret = synthesize_client(context, config, principal, db, h);
225 if (ret) {
226 krb5_set_error_message(context, ret, "could not synthesize "
227 "HDB client principal entry");
228 ret = HDB_ERR_NOENTRY;
229 krb5_prepend_error_message(context, ret, "no such entry found in hdb");
231 } else {
232 krb5_set_error_message(context, ret, "no such entry found in hdb");
234 break;
236 default:
237 if (db)
238 *db = NULL;
239 break;
242 out:
243 krb5_free_principal(context, enterprise_principal);
244 free(ent);
245 return ret;
248 void
249 _kdc_free_ent(krb5_context context, hdb_entry_ex *ent)
251 hdb_free_entry (context, ent);
252 free (ent);
256 * Use the order list of preferred encryption types and sort the
257 * available keys and return the most preferred key.
260 krb5_error_code
261 _kdc_get_preferred_key(krb5_context context,
262 krb5_kdc_configuration *config,
263 hdb_entry_ex *h,
264 const char *name,
265 krb5_enctype *enctype,
266 Key **key)
268 krb5_error_code ret;
269 int i;
271 if (config->use_strongest_server_key) {
272 const krb5_enctype *p = krb5_kerberos_enctypes(context);
274 for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) {
275 if (krb5_enctype_valid(context, p[i]) != 0 &&
276 !_kdc_is_weak_exception(h->entry.principal, p[i]))
277 continue;
278 ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key);
279 if (ret != 0)
280 continue;
281 if (enctype != NULL)
282 *enctype = p[i];
283 return 0;
285 } else {
286 *key = NULL;
288 for (i = 0; i < h->entry.keys.len; i++) {
289 if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) != 0 &&
290 !_kdc_is_weak_exception(h->entry.principal, h->entry.keys.val[i].key.keytype))
291 continue;
292 ret = hdb_enctype2key(context, &h->entry, NULL,
293 h->entry.keys.val[i].key.keytype, key);
294 if (ret != 0)
295 continue;
296 if (enctype != NULL)
297 *enctype = (*key)->key.keytype;
298 return 0;
302 krb5_set_error_message(context, EINVAL,
303 "No valid kerberos key found for %s", name);
304 return EINVAL; /* XXX */