2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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
))
45 if (nt
== KRB5_NT_SRV_INST
|| nt
== KRB5_NT_UNKNOWN
)
47 if (config
->strict_nametypes
== 0)
52 struct timeval _kdc_now
;
54 static krb5_error_code
55 synthesize_hdb_close(krb5_context context
, struct HDB
*db
)
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
,
76 /* Hope this works! */
77 null_db
.hdb_destroy
= synthesize_hdb_close
;
78 null_db
.hdb_close
= synthesize_hdb_close
;
82 ret
= (e
= calloc(1, sizeof(*e
))) ? 0 : krb5_enomem(context
);
85 e
->flags
.immutable
= 1;
87 e
->flags
.synthetic
= 1;
88 e
->flags
.do_not_store
= 1;
92 e
->created_by
.time
= time(NULL
);
93 e
->modified_by
= NULL
;
94 e
->valid_start
= NULL
;
102 ret
= (e
->max_renew
= calloc(1, sizeof(*e
->max_renew
))) ?
103 0 : krb5_enomem(context
);
105 ret
= (e
->max_life
= calloc(1, sizeof(*e
->max_life
))) ?
106 0 : krb5_enomem(context
);
108 ret
= krb5_copy_principal(context
, princ
, &e
->principal
);
110 ret
= krb5_copy_principal(context
, princ
, &e
->created_by
.principal
);
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
;
120 hdb_free_entry(context
, &null_db
, e
);
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
,
130 krb5uint32
*kvno_ptr
,
134 hdb_entry
*ent
= NULL
;
135 krb5_error_code ret
= HDB_ERR_NOENTRY
;
138 krb5_principal enterprise_principal
= NULL
;
139 krb5_const_principal princ
;
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) {
151 flags
|= HDB_F_KVNO_SPECIFIED
;
153 flags
|= HDB_F_ALL_KVNOS
;
156 ent
= calloc(1, sizeof (*ent
));
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
);
169 ret
= krb5_parse_name(context
, principal
->name
.name_string
.val
[0],
170 &enterprise_principal
);
175 for (i
= 0; i
< config
->num_db
; i
++) {
176 HDB
*curdb
= config
->db
[i
];
181 ret
= curdb
->hdb_open(context
, curdb
, O_RDONLY
, 0);
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
);
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.
210 case HDB_ERR_WRONG_REALM
:
213 * the ent->entry.principal just contains hints for the client
214 * to retry. This is important for enterprise principal routing
221 case HDB_ERR_NOENTRY
:
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
);
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");
234 krb5_set_error_message(context
, ret
, "no such entry found in hdb");
245 krb5_free_principal(context
, enterprise_principal
);
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
);
258 * Use the order list of preferred encryption types and sort the
259 * available keys and return the most preferred key.
263 _kdc_get_preferred_key(krb5_context context
,
264 krb5_kdc_configuration
*config
,
267 krb5_enctype
*enctype
,
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
]))
280 ret
= hdb_enctype2key(context
, h
, NULL
, p
[i
], key
);
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
))
294 ret
= hdb_enctype2key(context
, h
, NULL
,
295 h
->keys
.val
[i
].key
.keytype
, key
);
299 *enctype
= (*key
)->key
.keytype
;
304 krb5_set_error_message(context
, ret
= KRB5KDC_ERR_ETYPE_NOSUPP
,
305 "No valid kerberos key found for %s", name
);
310 _kdc_verify_checksum(krb5_context context
,
312 krb5_key_usage usage
,
313 const krb5_data
*data
,
318 ret
= krb5_verify_checksum(context
, crypto
, usage
,
319 data
->data
, data
->length
,
321 if (ret
== KRB5_PROG_SUMTYPE_NOSUPP
)
322 ret
= KRB5KDC_ERR_SUMTYPE_NOSUPP
;
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.
341 _kdc_include_pac_p(astgs_request_t r
)
347 * Notify the HDB backend and KDC plugin of the audited event.
351 _kdc_audit_request(astgs_request_t r
)
356 ret
= _kdc_plugin_audit(r
);
358 (hdb
= r
->clientdb
? r
->clientdb
: r
->config
->db
[0]) &&
360 ret
= hdb
->hdb_audit(r
->context
, hdb
, r
->client
, (hdb_request_t
)r
);