Line data Source code
1 : /*
2 : * Copyright (c) 1997-2008 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 : /*
37 : * return the realm of a krbtgt-ticket or NULL
38 : */
39 :
40 : static Realm
41 38595 : get_krbtgt_realm(const PrincipalName *p)
42 : {
43 38595 : if(p->name_string.len == 2
44 38595 : && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
45 38595 : return p->name_string.val[1];
46 : else
47 0 : return NULL;
48 : }
49 :
50 : /*
51 : * return TRUE if client was a synthetic principal, as indicated by
52 : * authorization data
53 : */
54 : krb5_boolean
55 35986 : _kdc_synthetic_princ_used_p(krb5_context context, krb5_ticket *ticket)
56 : {
57 : krb5_data synthetic_princ_used;
58 : krb5_error_code ret;
59 :
60 35986 : ret = krb5_ticket_get_authorization_data_type(context, ticket,
61 : KRB5_AUTHDATA_SYNTHETIC_PRINC_USED,
62 : &synthetic_princ_used);
63 35986 : if (ret == ENOENT)
64 35986 : ret = krb5_ticket_get_authorization_data_type(context, ticket,
65 : KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
66 : &synthetic_princ_used);
67 :
68 35986 : if (ret == 0)
69 0 : krb5_data_free(&synthetic_princ_used);
70 :
71 35986 : return ret == 0;
72 : }
73 :
74 : /*
75 : *
76 : */
77 :
78 : krb5_error_code
79 36080 : _kdc_check_pac(astgs_request_t r,
80 : const krb5_principal client_principal,
81 : const krb5_principal delegated_proxy_principal,
82 : hdb_entry *client,
83 : hdb_entry *server,
84 : hdb_entry *krbtgt,
85 : hdb_entry *ticket_server,
86 : const EncryptionKey *server_check_key,
87 : const EncryptionKey *krbtgt_check_key,
88 : EncTicketPart *tkt,
89 : krb5_boolean *kdc_issued,
90 : krb5_pac *ppac,
91 : krb5_principal *pac_canon_name,
92 : uint64_t *pac_attributes)
93 : {
94 36080 : krb5_context context = r->context;
95 36080 : krb5_kdc_configuration *config = r->config;
96 36080 : krb5_pac pac = NULL;
97 : krb5_error_code ret;
98 : krb5_boolean signedticket;
99 :
100 36080 : *kdc_issued = FALSE;
101 36080 : *ppac = NULL;
102 36080 : if (pac_canon_name)
103 36080 : *pac_canon_name = NULL;
104 36080 : if (pac_attributes)
105 36080 : *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
106 :
107 36080 : ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
108 36080 : if (ret)
109 0 : return ret;
110 :
111 36080 : if (pac == NULL) {
112 10 : if (config->require_pac)
113 10 : ret = KRB5KDC_ERR_TGT_REVOKED;
114 10 : return ret;
115 : }
116 :
117 : /* Verify the server signature. */
118 36070 : ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
119 : server_check_key, NULL);
120 36070 : if (ret) {
121 28 : krb5_pac_free(context, pac);
122 28 : return ret;
123 : }
124 :
125 36042 : if (pac_canon_name) {
126 36042 : ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
127 36042 : if (ret && ret != ENOENT) {
128 0 : krb5_pac_free(context, pac);
129 0 : return ret;
130 : }
131 : }
132 36042 : if (pac_attributes) {
133 36042 : ret = _krb5_pac_get_attributes_info(context, pac, pac_attributes);
134 36042 : if (ret && ret != ENOENT) {
135 0 : krb5_pac_free(context, pac);
136 0 : return ret;
137 : }
138 36042 : if (ret == ENOENT)
139 78 : *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
140 : }
141 :
142 : /* Verify the KDC signatures. */
143 36042 : ret = _kdc_pac_verify(r,
144 : client_principal, delegated_proxy_principal,
145 : client, server, krbtgt, &pac);
146 36042 : if (ret == 0) {
147 36015 : if (pac == NULL) {
148 : /* the plugin may indicate no PAC should be generated */
149 9 : *pac_attributes = 0;
150 : }
151 27 : } else if (ret == KRB5_PLUGIN_NO_HANDLE) {
152 : /*
153 : * We can't verify the KDC signatures if the ticket was issued by
154 : * another realm's KDC.
155 : */
156 0 : if (krb5_realm_compare(context, server->principal,
157 0 : ticket_server->principal)) {
158 0 : ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
159 : krbtgt_check_key);
160 0 : if (ret) {
161 0 : krb5_pac_free(context, pac);
162 0 : return ret;
163 : }
164 : }
165 :
166 : /* Discard the PAC if the plugin didn't handle it */
167 0 : krb5_pac_free(context, pac);
168 0 : ret = krb5_pac_init(context, &pac);
169 0 : if (ret)
170 0 : return ret;
171 : } else {
172 27 : krb5_pac_free(context, pac);
173 27 : return ret;
174 : }
175 :
176 71971 : *kdc_issued = signedticket ||
177 35956 : krb5_principal_is_krbtgt(context,
178 35956 : ticket_server->principal);
179 36015 : *ppac = pac;
180 :
181 36015 : return 0;
182 : }
183 :
184 : static krb5_boolean
185 71609 : is_anon_tgs_request_p(const KDC_REQ_BODY *b,
186 : const EncTicketPart *tgt)
187 : {
188 71609 : KDCOptions f = b->kdc_options;
189 :
190 : /*
191 : * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
192 : * request-anonymous and cname-in-addl-tkt flags for constrained
193 : * delegation requests. A true anonymous TGS request will only
194 : * have the request-anonymous flag set. (A corollary of this is
195 : * that it is not possible to support anonymous constrained
196 : * delegation requests, although they would be of limited utility.)
197 : */
198 143218 : return tgt->flags.anonymous ||
199 71609 : (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
200 : }
201 :
202 : /*
203 : *
204 : */
205 :
206 : static krb5_error_code
207 35881 : check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
208 : krb5_const_principal tgt_name,
209 : const EncTicketPart *tgt, EncTicketPart *et)
210 : {
211 35881 : KDCOptions f = b->kdc_options;
212 :
213 35881 : if(f.validate){
214 0 : if (!tgt->flags.invalid || tgt->starttime == NULL) {
215 0 : kdc_audit_addreason((kdc_request_t)r,
216 : "Bad request to validate ticket");
217 0 : return KRB5KDC_ERR_BADOPTION;
218 : }
219 0 : if(*tgt->starttime > kdc_time){
220 0 : kdc_audit_addreason((kdc_request_t)r,
221 : "Early request to validate ticket");
222 0 : return KRB5KRB_AP_ERR_TKT_NYV;
223 : }
224 : /* XXX tkt = tgt */
225 0 : et->flags.invalid = 0;
226 35881 : } else if (tgt->flags.invalid) {
227 0 : kdc_audit_addreason((kdc_request_t)r,
228 : "Ticket-granting ticket has INVALID flag set");
229 0 : return KRB5KRB_AP_ERR_TKT_INVALID;
230 : }
231 :
232 35881 : if(f.forwardable){
233 25648 : if (!tgt->flags.forwardable) {
234 0 : kdc_audit_addreason((kdc_request_t)r,
235 : "Bad request for forwardable ticket");
236 0 : return KRB5KDC_ERR_BADOPTION;
237 : }
238 25648 : et->flags.forwardable = 1;
239 : }
240 35881 : if(f.forwarded){
241 17283 : if (!tgt->flags.forwardable) {
242 153 : kdc_audit_addreason((kdc_request_t)r,
243 : "Request to forward non-forwardable ticket");
244 153 : return KRB5KDC_ERR_BADOPTION;
245 : }
246 17130 : et->flags.forwarded = 1;
247 17130 : et->caddr = b->addresses;
248 : }
249 35728 : if(tgt->flags.forwarded)
250 299 : et->flags.forwarded = 1;
251 :
252 35728 : if(f.proxiable){
253 0 : if (!tgt->flags.proxiable) {
254 0 : kdc_audit_addreason((kdc_request_t)r,
255 : "Bad request for proxiable ticket");
256 0 : return KRB5KDC_ERR_BADOPTION;
257 : }
258 0 : et->flags.proxiable = 1;
259 : }
260 35728 : if(f.proxy){
261 0 : if (!tgt->flags.proxiable) {
262 0 : kdc_audit_addreason((kdc_request_t)r,
263 : "Request to proxy non-proxiable ticket");
264 0 : return KRB5KDC_ERR_BADOPTION;
265 : }
266 0 : et->flags.proxy = 1;
267 0 : et->caddr = b->addresses;
268 : }
269 35728 : if(tgt->flags.proxy)
270 0 : et->flags.proxy = 1;
271 :
272 35728 : if(f.allow_postdate){
273 0 : if (!tgt->flags.may_postdate) {
274 0 : kdc_audit_addreason((kdc_request_t)r,
275 : "Bad request for post-datable ticket");
276 0 : return KRB5KDC_ERR_BADOPTION;
277 : }
278 0 : et->flags.may_postdate = 1;
279 : }
280 35728 : if(f.postdated){
281 0 : if (!tgt->flags.may_postdate) {
282 0 : kdc_audit_addreason((kdc_request_t)r,
283 : "Bad request for postdated ticket");
284 0 : return KRB5KDC_ERR_BADOPTION;
285 : }
286 0 : if(b->from)
287 0 : *et->starttime = *b->from;
288 0 : et->flags.postdated = 1;
289 0 : et->flags.invalid = 1;
290 35728 : } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
291 0 : kdc_audit_addreason((kdc_request_t)r,
292 : "Ticket cannot be postdated");
293 0 : return KRB5KDC_ERR_CANNOT_POSTDATE;
294 : }
295 :
296 35728 : if(f.renewable){
297 1909 : if (!tgt->flags.renewable || tgt->renew_till == NULL) {
298 0 : kdc_audit_addreason((kdc_request_t)r,
299 : "Bad request for renewable ticket");
300 0 : return KRB5KDC_ERR_BADOPTION;
301 : }
302 1909 : et->flags.renewable = 1;
303 1909 : ALLOC(et->renew_till);
304 1909 : _kdc_fix_time(&b->rtime);
305 1909 : *et->renew_till = *b->rtime;
306 : }
307 35728 : if(f.renew){
308 : time_t old_life;
309 6 : if (!tgt->flags.renewable || tgt->renew_till == NULL) {
310 0 : kdc_audit_addreason((kdc_request_t)r,
311 : "Request to renew non-renewable ticket");
312 0 : return KRB5KDC_ERR_BADOPTION;
313 : }
314 6 : old_life = tgt->endtime;
315 6 : if(tgt->starttime)
316 0 : old_life -= *tgt->starttime;
317 : else
318 6 : old_life -= tgt->authtime;
319 6 : et->endtime = *et->starttime + old_life;
320 6 : if (et->renew_till != NULL)
321 6 : et->endtime = min(*et->renew_till, et->endtime);
322 : }
323 :
324 : /*
325 : * RFC 8062 section 3 defines an anonymous ticket as one containing
326 : * the anonymous principal and the anonymous ticket flag.
327 : */
328 35728 : if (tgt->flags.anonymous &&
329 0 : !_kdc_is_anonymous(r->context, tgt_name)) {
330 0 : kdc_audit_addreason((kdc_request_t)r,
331 : "Anonymous ticket flag set without "
332 : "anonymous principal");
333 0 : return KRB5KDC_ERR_BADOPTION;
334 : }
335 :
336 : /*
337 : * RFC 8062 section 4.2 states that if the TGT is anonymous, the
338 : * anonymous KDC option SHOULD be set, but it is not required.
339 : * Treat an anonymous TGT as if the anonymous flag was set.
340 : */
341 35728 : if (is_anon_tgs_request_p(b, tgt))
342 0 : et->flags.anonymous = 1;
343 :
344 35728 : return 0;
345 : }
346 :
347 : /*
348 : * Determine if s4u2self is allowed from this client to this server
349 : *
350 : * also:
351 : *
352 : * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
353 : * service given by the client.
354 : *
355 : * For example, regardless of the principal being impersonated, if the
356 : * 'client' and 'server' (target) are the same, or server is an SPN
357 : * alias of client, then it's safe.
358 : */
359 :
360 : krb5_error_code
361 636 : _kdc_check_client_matches_target_service(krb5_context context,
362 : krb5_kdc_configuration *config,
363 : HDB *clientdb,
364 : hdb_entry *client,
365 : hdb_entry *target_server,
366 : krb5_const_principal target_server_principal)
367 : {
368 : krb5_error_code ret;
369 :
370 : /*
371 : * Always allow the plugin to check, this might be faster, allow a
372 : * policy or audit check and can look into the DB records
373 : * directly
374 : */
375 636 : if (clientdb->hdb_check_client_matches_target_service) {
376 636 : ret = clientdb->hdb_check_client_matches_target_service(context,
377 : clientdb,
378 : client,
379 : target_server);
380 636 : if (ret == 0)
381 634 : return 0;
382 0 : } else if (krb5_principal_compare(context,
383 0 : client->principal,
384 : target_server_principal) == TRUE) {
385 : /* if client does a s4u2self to itself, and there is no plugin, that is ok */
386 0 : return 0;
387 : } else {
388 0 : ret = KRB5KDC_ERR_BADOPTION;
389 : }
390 2 : return ret;
391 : }
392 :
393 : /*
394 : *
395 : */
396 :
397 : krb5_error_code
398 96 : _kdc_verify_flags(krb5_context context,
399 : krb5_kdc_configuration *config,
400 : const EncTicketPart *et,
401 : const char *pstr)
402 : {
403 96 : if(et->endtime < kdc_time){
404 0 : kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
405 0 : return KRB5KRB_AP_ERR_TKT_EXPIRED;
406 : }
407 96 : if(et->flags.invalid){
408 0 : kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
409 0 : return KRB5KRB_AP_ERR_TKT_NYV;
410 : }
411 96 : return 0;
412 : }
413 :
414 : /*
415 : *
416 : */
417 :
418 : static krb5_error_code
419 35728 : fix_transited_encoding(krb5_context context,
420 : krb5_kdc_configuration *config,
421 : krb5_boolean check_policy,
422 : const TransitedEncoding *tr,
423 : EncTicketPart *et,
424 : const char *client_realm,
425 : const char *server_realm,
426 : const char *tgt_realm)
427 : {
428 35728 : krb5_error_code ret = 0;
429 : char **realms, **tmp;
430 : unsigned int num_realms;
431 : size_t i;
432 :
433 35728 : switch (tr->tr_type) {
434 35728 : case domain_X500_Compress:
435 35728 : break;
436 0 : case 0:
437 : /*
438 : * Allow empty content of type 0 because that is was Microsoft
439 : * generates in their TGT.
440 : */
441 0 : if (tr->contents.length == 0)
442 0 : break;
443 0 : kdc_log(context, config, 4,
444 : "Transited type 0 with non empty content");
445 0 : return KRB5KDC_ERR_TRTYPE_NOSUPP;
446 0 : default:
447 0 : kdc_log(context, config, 4,
448 : "Unknown transited type: %u", tr->tr_type);
449 0 : return KRB5KDC_ERR_TRTYPE_NOSUPP;
450 : }
451 :
452 35728 : ret = krb5_domain_x500_decode(context,
453 : tr->contents,
454 : &realms,
455 : &num_realms,
456 : client_realm,
457 : server_realm);
458 35728 : if(ret){
459 0 : krb5_warn(context, ret,
460 : "Decoding transited encoding");
461 0 : return ret;
462 : }
463 :
464 : /*
465 : * If the realm of the presented tgt is neither the client nor the server
466 : * realm, it is a transit realm and must be added to transited set.
467 : */
468 35736 : if (strcmp(client_realm, tgt_realm) != 0 &&
469 8 : strcmp(server_realm, tgt_realm) != 0) {
470 0 : if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
471 0 : ret = ERANGE;
472 0 : goto free_realms;
473 : }
474 0 : tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
475 0 : if(tmp == NULL){
476 0 : ret = ENOMEM;
477 0 : goto free_realms;
478 : }
479 0 : realms = tmp;
480 0 : realms[num_realms] = strdup(tgt_realm);
481 0 : if(realms[num_realms] == NULL){
482 0 : ret = ENOMEM;
483 0 : goto free_realms;
484 : }
485 0 : num_realms++;
486 : }
487 35728 : if(num_realms == 0) {
488 35728 : if (strcmp(client_realm, server_realm) != 0)
489 56 : kdc_log(context, config, 4,
490 : "cross-realm %s -> %s", client_realm, server_realm);
491 : } else {
492 0 : size_t l = 0;
493 : char *rs;
494 0 : for(i = 0; i < num_realms; i++)
495 0 : l += strlen(realms[i]) + 2;
496 0 : rs = malloc(l);
497 0 : if(rs != NULL) {
498 0 : *rs = '\0';
499 0 : for(i = 0; i < num_realms; i++) {
500 0 : if(i > 0)
501 0 : strlcat(rs, ", ", l);
502 0 : strlcat(rs, realms[i], l);
503 : }
504 0 : kdc_log(context, config, 4,
505 : "cross-realm %s -> %s via [%s]",
506 : client_realm, server_realm, rs);
507 0 : free(rs);
508 : }
509 : }
510 35728 : if(check_policy) {
511 35728 : ret = krb5_check_transited(context, client_realm,
512 : server_realm,
513 : realms, num_realms, NULL);
514 35728 : if(ret) {
515 0 : krb5_warn(context, ret, "cross-realm %s -> %s",
516 : client_realm, server_realm);
517 0 : goto free_realms;
518 : }
519 35728 : et->flags.transited_policy_checked = 1;
520 : }
521 35728 : et->transited.tr_type = domain_X500_Compress;
522 35728 : ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
523 35728 : if(ret)
524 0 : krb5_warn(context, ret, "Encoding transited encoding");
525 71456 : free_realms:
526 35728 : for(i = 0; i < num_realms; i++)
527 0 : free(realms[i]);
528 35728 : free(realms);
529 35728 : return ret;
530 : }
531 :
532 :
533 : static krb5_error_code
534 35881 : tgs_make_reply(astgs_request_t r,
535 : const EncTicketPart *tgt,
536 : const EncryptionKey *serverkey,
537 : const EncryptionKey *krbtgtkey,
538 : const krb5_keyblock *sessionkey,
539 : krb5_kvno kvno,
540 : AuthorizationData *auth_data,
541 : const char *tgt_realm,
542 : uint16_t rodc_id,
543 : krb5_boolean add_ticket_sig)
544 : {
545 35881 : KDC_REQ_BODY *b = &r->req.req_body;
546 35881 : krb5_data *reply = r->reply;
547 35881 : KDC_REP *rep = &r->rep;
548 35881 : EncTicketPart *et = &r->et;
549 35881 : EncKDCRepPart *ek = &r->ek;
550 35881 : KDCOptions f = b->kdc_options;
551 : krb5_error_code ret;
552 35881 : int is_weak = 0;
553 :
554 35881 : heim_assert(r->client_princ != NULL, "invalid client name passed to tgs_make_reply");
555 :
556 35881 : rep->pvno = 5;
557 35881 : rep->msg_type = krb_tgs_rep;
558 :
559 35881 : et->authtime = tgt->authtime;
560 35881 : _kdc_fix_time(&b->till);
561 35881 : et->endtime = min(tgt->endtime, *b->till);
562 35881 : ALLOC(et->starttime);
563 35881 : *et->starttime = kdc_time;
564 :
565 35881 : ret = check_tgs_flags(r, b, r->client_princ, tgt, et);
566 35881 : if(ret)
567 153 : goto out;
568 :
569 : /* We should check the transited encoding if:
570 : 1) the request doesn't ask not to be checked
571 : 2) globally enforcing a check
572 : 3) principal requires checking
573 : 4) we allow non-check per-principal, but principal isn't marked as allowing this
574 : 5) we don't globally allow this
575 : */
576 :
577 : #define GLOBAL_FORCE_TRANSITED_CHECK \
578 : (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
579 : #define GLOBAL_ALLOW_PER_PRINCIPAL \
580 : (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
581 : #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
582 : (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
583 :
584 : /* these will consult the database in future release */
585 : #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
586 : #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
587 :
588 107184 : ret = fix_transited_encoding(r->context, r->config,
589 35728 : !f.disable_transited_check ||
590 0 : GLOBAL_FORCE_TRANSITED_CHECK ||
591 : PRINCIPAL_FORCE_TRANSITED_CHECK(r->server) ||
592 : !((GLOBAL_ALLOW_PER_PRINCIPAL &&
593 : PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r->server)) ||
594 0 : GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
595 : &tgt->transited, et,
596 35728 : krb5_principal_get_realm(r->context, r->client_princ),
597 35728 : krb5_principal_get_realm(r->context, r->server->principal),
598 : tgt_realm);
599 :
600 : {
601 : /*
602 : * RFC 6806 notes that names MUST NOT be changed in the response to a
603 : * TGS request. Hence we ignore the setting of the canonicalize KDC
604 : * option. However, for legacy interoperability we do allow the backend
605 : * to override this by setting the force-canonicalize HDB flag in the
606 : * server entry.
607 : */
608 : krb5_const_principal rsp;
609 :
610 35728 : if (r->server->flags.force_canonicalize)
611 34698 : rsp = r->server->principal;
612 : else
613 1030 : rsp = r->server_princ;
614 35728 : if (ret == 0)
615 35728 : ret = copy_Realm(&rsp->realm, &rep->ticket.realm);
616 35728 : if (ret == 0)
617 35728 : ret = _krb5_principal2principalname(&rep->ticket.sname, rsp);
618 : }
619 :
620 35728 : if (ret == 0)
621 35728 : ret = copy_Realm(&r->client_princ->realm, &rep->crealm);
622 35728 : if (ret)
623 0 : goto out;
624 :
625 : /*
626 : * RFC 8062 states "if the ticket in the TGS request is an anonymous
627 : * one, the client and client realm are copied from that ticket". So
628 : * whilst the TGT flag check below is superfluous, it is included in
629 : * order to follow the specification to its letter.
630 : */
631 35728 : if (et->flags.anonymous && !tgt->flags.anonymous)
632 0 : _kdc_make_anonymous_principalname(&rep->cname);
633 : else
634 35728 : ret = copy_PrincipalName(&r->client_princ->name, &rep->cname);
635 35728 : if (ret)
636 0 : goto out;
637 35728 : rep->ticket.tkt_vno = 5;
638 :
639 35728 : ek->caddr = et->caddr;
640 :
641 : {
642 : time_t life;
643 35728 : life = et->endtime - *et->starttime;
644 35728 : if(r->client && r->client->max_life)
645 35679 : life = min(life, *r->client->max_life);
646 35728 : if(r->server->max_life)
647 34698 : life = min(life, *r->server->max_life);
648 35728 : et->endtime = *et->starttime + life;
649 : }
650 35728 : if(f.renewable_ok && tgt->flags.renewable &&
651 0 : et->renew_till == NULL && et->endtime < *b->till &&
652 0 : tgt->renew_till != NULL)
653 : {
654 0 : et->flags.renewable = 1;
655 0 : ALLOC(et->renew_till);
656 0 : *et->renew_till = *b->till;
657 : }
658 35728 : if(et->renew_till){
659 : time_t renew;
660 1909 : renew = *et->renew_till - *et->starttime;
661 1909 : if(r->client && r->client->max_renew)
662 1875 : renew = min(renew, *r->client->max_renew);
663 1909 : if(r->server->max_renew)
664 1875 : renew = min(renew, *r->server->max_renew);
665 1909 : *et->renew_till = *et->starttime + renew;
666 : }
667 :
668 35728 : if(et->renew_till){
669 1909 : *et->renew_till = min(*et->renew_till, *tgt->renew_till);
670 1909 : *et->starttime = min(*et->starttime, *et->renew_till);
671 1909 : et->endtime = min(et->endtime, *et->renew_till);
672 : }
673 :
674 35728 : *et->starttime = min(*et->starttime, et->endtime);
675 :
676 35728 : if(*et->starttime == et->endtime){
677 0 : ret = KRB5KDC_ERR_NEVER_VALID;
678 0 : goto out;
679 : }
680 35728 : if(et->renew_till && et->endtime == *et->renew_till){
681 0 : free(et->renew_till);
682 0 : et->renew_till = NULL;
683 0 : et->flags.renewable = 0;
684 : }
685 :
686 35728 : et->flags.pre_authent = tgt->flags.pre_authent;
687 35728 : et->flags.hw_authent = tgt->flags.hw_authent;
688 35728 : et->flags.ok_as_delegate = r->server->flags.ok_as_delegate;
689 :
690 : /* See MS-KILE 3.3.5.1 */
691 35728 : if (!r->server->flags.forwardable)
692 1 : et->flags.forwardable = 0;
693 35728 : if (!r->server->flags.proxiable)
694 1031 : et->flags.proxiable = 0;
695 :
696 35728 : if (auth_data) {
697 0 : unsigned int i = 0;
698 :
699 : /* XXX check authdata */
700 :
701 0 : if (et->authorization_data == NULL) {
702 0 : et->authorization_data = calloc(1, sizeof(*et->authorization_data));
703 0 : if (et->authorization_data == NULL) {
704 0 : ret = ENOMEM;
705 0 : krb5_set_error_message(r->context, ret, "malloc: out of memory");
706 0 : goto out;
707 : }
708 : }
709 0 : for(i = 0; i < auth_data->len ; i++) {
710 0 : ret = add_AuthorizationData(et->authorization_data, &auth_data->val[i]);
711 0 : if (ret) {
712 0 : krb5_set_error_message(r->context, ret, "malloc: out of memory");
713 0 : goto out;
714 : }
715 : }
716 : }
717 :
718 35728 : ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et->key);
719 35728 : if (ret)
720 0 : goto out;
721 35728 : et->crealm = rep->crealm;
722 35728 : et->cname = rep->cname;
723 :
724 35728 : ek->key = et->key;
725 : /* MIT must have at least one last_req */
726 35728 : ek->last_req.val = calloc(1, sizeof(*ek->last_req.val));
727 35728 : if (ek->last_req.val == NULL) {
728 0 : ret = ENOMEM;
729 0 : goto out;
730 : }
731 35728 : ek->last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
732 35728 : ek->nonce = b->nonce;
733 35728 : ek->flags = et->flags;
734 35728 : ek->authtime = et->authtime;
735 35728 : ek->starttime = et->starttime;
736 35728 : ek->endtime = et->endtime;
737 35728 : ek->renew_till = et->renew_till;
738 35728 : ek->srealm = rep->ticket.realm;
739 35728 : ek->sname = rep->ticket.sname;
740 :
741 35728 : _kdc_log_timestamp(r, "TGS-REQ", et->authtime, et->starttime,
742 : et->endtime, et->renew_till);
743 :
744 35728 : if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
745 0 : && _kdc_is_weak_exception(r->server->principal, serverkey->keytype))
746 : {
747 0 : krb5_enctype_enable(r->context, serverkey->keytype);
748 0 : is_weak = 1;
749 : }
750 :
751 35728 : if (r->canon_client_princ) {
752 : char *cpn;
753 :
754 35728 : (void) krb5_unparse_name(r->context, r->canon_client_princ, &cpn);
755 35728 : kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s",
756 35728 : cpn ? cpn : "<unknown>");
757 35728 : krb5_xfree(cpn);
758 : }
759 :
760 : /*
761 : * For anonymous tickets, we should filter out positive authorization data
762 : * that could reveal the client's identity, and return a policy error for
763 : * restrictive authorization data. Policy for unknown authorization types
764 : * is implementation dependent.
765 : */
766 35728 : if (r->pac && !et->flags.anonymous) {
767 35728 : kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes",
768 35728 : r->pac_attributes);
769 :
770 : /*
771 : * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
772 : * buffer (legacy behavior) or if the attributes buffer indicates the
773 : * AS client requested one.
774 : */
775 35728 : if (_kdc_include_pac_p(r)) {
776 35728 : krb5_boolean is_tgs =
777 35728 : krb5_principal_is_krbtgt(r->context, r->server->principal);
778 :
779 71456 : ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey,
780 35728 : krbtgtkey, rodc_id, NULL, r->canon_client_princ,
781 : add_ticket_sig, add_ticket_sig, et,
782 : is_tgs ? &r->pac_attributes : NULL);
783 35728 : if (ret)
784 0 : goto out;
785 : }
786 : }
787 :
788 35728 : ret = _kdc_finalize_reply(r);
789 35728 : if (ret)
790 0 : goto out;
791 :
792 : /* It is somewhat unclear where the etype in the following
793 : encryption should come from. What we have is a session
794 : key in the passed tgt, and a list of preferred etypes
795 : *for the new ticket*. Should we pick the best possible
796 : etype, given the keytype in the tgt, or should we look
797 : at the etype list here as well? What if the tgt
798 : session key is DES3 and we want a ticket with a (say)
799 : CAST session key. Should the DES3 etype be added to the
800 : etype list, even if we don't want a session key with
801 : DES3? */
802 71456 : ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
803 35728 : serverkey->keytype, kvno,
804 35728 : serverkey, 0, r->rk_is_subkey, reply);
805 35728 : if (is_weak)
806 0 : krb5_enctype_disable(r->context, serverkey->keytype);
807 :
808 35728 : _log_astgs_req(r, serverkey->keytype);
809 :
810 35881 : out:
811 35881 : return ret;
812 : }
813 :
814 : static krb5_error_code
815 37242 : tgs_check_authenticator(krb5_context context,
816 : krb5_kdc_configuration *config,
817 : krb5_auth_context ac,
818 : KDC_REQ_BODY *b,
819 : krb5_keyblock *key)
820 : {
821 : krb5_authenticator auth;
822 : krb5_error_code ret;
823 : krb5_crypto crypto;
824 :
825 37242 : ret = krb5_auth_con_getauthenticator(context, ac, &auth);
826 37242 : if (ret) {
827 0 : kdc_log(context, config, 2,
828 : "Out of memory checking PA-TGS Authenticator");
829 0 : goto out;
830 : }
831 37242 : if(auth->cksum == NULL){
832 0 : kdc_log(context, config, 4, "No authenticator in request");
833 0 : ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
834 0 : goto out;
835 : }
836 :
837 37242 : if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
838 0 : kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
839 0 : auth->cksum->cksumtype);
840 0 : ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
841 0 : goto out;
842 : }
843 :
844 37242 : ret = krb5_crypto_init(context, key, 0, &crypto);
845 37242 : if (ret) {
846 0 : const char *msg = krb5_get_error_message(context, ret);
847 0 : kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
848 0 : krb5_free_error_message(context, msg);
849 0 : goto out;
850 : }
851 :
852 : /*
853 : * RFC4120 says the checksum must be collision-proof, but it does
854 : * not require it to be keyed (as the authenticator is encrypted).
855 : */
856 37242 : _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
857 74484 : ret = _kdc_verify_checksum(context,
858 : crypto,
859 : KRB5_KU_TGS_REQ_AUTH_CKSUM,
860 37242 : &b->_save,
861 37242 : auth->cksum);
862 37242 : krb5_crypto_destroy(context, crypto);
863 37242 : if(ret){
864 0 : const char *msg = krb5_get_error_message(context, ret);
865 0 : kdc_log(context, config, 4,
866 : "Failed to verify authenticator checksum: %s", msg);
867 0 : krb5_free_error_message(context, msg);
868 : }
869 74484 : out:
870 37242 : free_Authenticator(auth);
871 37242 : free(auth);
872 37242 : return ret;
873 : }
874 :
875 : static krb5_boolean
876 0 : need_referral(krb5_context context, krb5_kdc_configuration *config,
877 : const KDCOptions * const options, krb5_principal server,
878 : krb5_realm **realms)
879 : {
880 : const char *name;
881 :
882 0 : if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
883 0 : return FALSE;
884 :
885 0 : if (server->name.name_string.len == 1)
886 0 : name = server->name.name_string.val[0];
887 0 : else if (server->name.name_string.len > 1)
888 0 : name = server->name.name_string.val[1];
889 : else
890 0 : return FALSE;
891 :
892 0 : kdc_log(context, config, 5, "Searching referral for %s", name);
893 :
894 0 : return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
895 : }
896 :
897 : static krb5_error_code
898 74484 : validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
899 : {
900 : krb5_error_code ret;
901 : krb5_data data;
902 :
903 74484 : krb5_data_zero(&data);
904 :
905 74484 : if (!r->config->enable_fast)
906 7412 : return 0;
907 :
908 67072 : ret = _krb5_get_ad(r->context, auth_data, NULL,
909 : KRB5_AUTHDATA_FX_FAST_USED, &data);
910 67072 : if (ret == 0) {
911 32153 : r->fast_asserted = 1;
912 32153 : krb5_data_free(&data);
913 : }
914 :
915 67072 : ret = _krb5_get_ad(r->context, auth_data, NULL,
916 : KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
917 67072 : if (ret == 0) {
918 0 : kdc_log(r->context, r->config, 2,
919 : "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
920 0 : krb5_data_free(&data);
921 0 : return KRB5KRB_AP_ERR_BAD_INTEGRITY;
922 : }
923 :
924 67072 : return 0;
925 : }
926 :
927 : static krb5_error_code
928 38595 : tgs_parse_request(astgs_request_t r,
929 : const PA_DATA *tgs_req,
930 : krb5_enctype *krbtgt_etype,
931 : const char *from,
932 : const struct sockaddr *from_addr,
933 : time_t **csec,
934 : int **cusec,
935 : AuthorizationData **auth_data)
936 : {
937 38595 : krb5_kdc_configuration *config = r->config;
938 38595 : KDC_REQ_BODY *b = &r->req.req_body;
939 : static char failed[] = "<unparse_name failed>";
940 : krb5_ap_req ap_req;
941 : krb5_error_code ret;
942 : krb5_principal princ;
943 38595 : krb5_auth_context ac = NULL;
944 : krb5_flags ap_req_options;
945 38595 : krb5_flags verify_ap_req_flags = 0;
946 : krb5_crypto crypto;
947 : krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
948 : krb5uint32 krbtgt_kvno_try;
949 38595 : int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
950 : const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
951 : Key *tkey;
952 38595 : krb5_keyblock *subkey = NULL;
953 : unsigned usage;
954 :
955 38595 : *auth_data = NULL;
956 38595 : *csec = NULL;
957 38595 : *cusec = NULL;
958 :
959 38595 : memset(&ap_req, 0, sizeof(ap_req));
960 38595 : ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
961 38595 : if(ret){
962 0 : const char *msg = krb5_get_error_message(r->context, ret);
963 0 : kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
964 0 : krb5_free_error_message(r->context, msg);
965 0 : goto out;
966 : }
967 :
968 38595 : if(!get_krbtgt_realm(&ap_req.ticket.sname)){
969 : /* XXX check for ticket.sname == req.sname */
970 0 : kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
971 0 : ret = KRB5KDC_ERR_POLICY; /* ? */
972 0 : goto out;
973 : }
974 :
975 38595 : _krb5_principalname2krb5_principal(r->context,
976 : &princ,
977 : ap_req.ticket.sname,
978 : ap_req.ticket.realm);
979 :
980 38595 : krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
981 38595 : ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
982 : &krbtgt_kvno, &r->krbtgtdb, &r->krbtgt);
983 :
984 38595 : if (ret == HDB_ERR_NOT_FOUND_HERE) {
985 : /* XXX Factor out this unparsing of the same princ all over */
986 : char *p;
987 1353 : ret = krb5_unparse_name(r->context, princ, &p);
988 1353 : if (ret != 0)
989 0 : p = failed;
990 1353 : krb5_free_principal(r->context, princ);
991 1353 : kdc_log(r->context, config, 5,
992 : "Ticket-granting ticket account %s does not have secrets at "
993 : "this KDC, need to proxy", p);
994 1353 : if (ret == 0)
995 1353 : free(p);
996 1353 : ret = HDB_ERR_NOT_FOUND_HERE;
997 1353 : goto out;
998 37242 : } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
999 : char *p;
1000 0 : ret = krb5_unparse_name(r->context, princ, &p);
1001 0 : if (ret != 0)
1002 0 : p = failed;
1003 0 : krb5_free_principal(r->context, princ);
1004 0 : kdc_log(r->context, config, 5,
1005 : "Ticket-granting ticket account %s does not have keys for "
1006 : "kvno %d at this KDC", p, krbtgt_kvno);
1007 0 : if (ret == 0)
1008 0 : free(p);
1009 0 : ret = HDB_ERR_KVNO_NOT_FOUND;
1010 0 : goto out;
1011 37242 : } else if (ret == HDB_ERR_NO_MKEY) {
1012 : char *p;
1013 0 : ret = krb5_unparse_name(r->context, princ, &p);
1014 0 : if (ret != 0)
1015 0 : p = failed;
1016 0 : krb5_free_principal(r->context, princ);
1017 0 : kdc_log(r->context, config, 5,
1018 : "Missing master key for decrypting keys for ticket-granting "
1019 : "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1020 0 : if (ret == 0)
1021 0 : free(p);
1022 0 : ret = HDB_ERR_KVNO_NOT_FOUND;
1023 0 : goto out;
1024 37242 : } else if (ret) {
1025 0 : const char *msg = krb5_get_error_message(r->context, ret);
1026 : char *p;
1027 0 : ret = krb5_unparse_name(r->context, princ, &p);
1028 0 : if (ret != 0)
1029 0 : p = failed;
1030 0 : kdc_log(r->context, config, 4,
1031 : "Ticket-granting ticket %s not found in database: %s", p, msg);
1032 0 : krb5_free_principal(r->context, princ);
1033 0 : krb5_free_error_message(r->context, msg);
1034 0 : if (ret == 0)
1035 0 : free(p);
1036 0 : ret = KRB5KRB_AP_ERR_NOT_US;
1037 0 : goto out;
1038 : }
1039 :
1040 37242 : krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : r->krbtgt->kvno;
1041 37242 : *krbtgt_etype = ap_req.ticket.enc_part.etype;
1042 :
1043 37242 : next_kvno:
1044 37242 : krbtgt_keys = hdb_kvno2keys(r->context, r->krbtgt, krbtgt_kvno_try);
1045 37242 : ret = hdb_enctype2key(r->context, r->krbtgt, krbtgt_keys,
1046 : ap_req.ticket.enc_part.etype, &tkey);
1047 37242 : if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1048 0 : kvno_search_tries--;
1049 0 : krbtgt_kvno_try--;
1050 0 : goto next_kvno;
1051 37242 : } else if (ret) {
1052 0 : char *str = NULL, *p = NULL;
1053 :
1054 0 : krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
1055 0 : krb5_unparse_name(r->context, princ, &p);
1056 0 : kdc_log(r->context, config, 4,
1057 : "No server key with enctype %s found for %s",
1058 0 : str ? str : "<unknown enctype>",
1059 0 : p ? p : "<unparse_name failed>");
1060 0 : free(str);
1061 0 : free(p);
1062 0 : ret = KRB5KRB_AP_ERR_BADKEYVER;
1063 0 : goto out;
1064 : }
1065 :
1066 37242 : if (b->kdc_options.validate)
1067 0 : verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1068 :
1069 37242 : if (r->config->warn_ticket_addresses)
1070 0 : verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
1071 :
1072 74484 : ret = krb5_verify_ap_req2(r->context,
1073 : &ac,
1074 : &ap_req,
1075 : princ,
1076 37242 : &tkey->key,
1077 : verify_ap_req_flags,
1078 : &ap_req_options,
1079 : &r->ticket,
1080 : KRB5_KU_TGS_REQ_AUTH);
1081 37242 : if (r->ticket && r->ticket->ticket.caddr)
1082 317 : kdc_audit_addaddrs((kdc_request_t)r, r->ticket->ticket.caddr, "tixaddrs");
1083 37242 : if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
1084 0 : r->ticket != NULL) {
1085 0 : kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE);
1086 0 : ret = 0;
1087 : }
1088 37242 : if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1089 0 : kvno_search_tries--;
1090 0 : krbtgt_kvno_try--;
1091 0 : goto next_kvno;
1092 : }
1093 :
1094 37242 : krb5_free_principal(r->context, princ);
1095 37242 : if(ret) {
1096 0 : const char *msg = krb5_get_error_message(r->context, ret);
1097 0 : kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
1098 0 : krb5_free_error_message(r->context, msg);
1099 0 : goto out;
1100 : }
1101 :
1102 37242 : r->ticket_key = tkey;
1103 :
1104 : {
1105 : krb5_authenticator auth;
1106 :
1107 37242 : ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
1108 37242 : if (ret == 0) {
1109 37242 : *csec = malloc(sizeof(**csec));
1110 37242 : if (*csec == NULL) {
1111 0 : krb5_free_authenticator(r->context, &auth);
1112 0 : kdc_log(r->context, config, 4, "malloc failed");
1113 0 : goto out;
1114 : }
1115 37242 : **csec = auth->ctime;
1116 37242 : *cusec = malloc(sizeof(**cusec));
1117 37242 : if (*cusec == NULL) {
1118 0 : krb5_free_authenticator(r->context, &auth);
1119 0 : kdc_log(r->context, config, 4, "malloc failed");
1120 0 : goto out;
1121 : }
1122 37242 : **cusec = auth->cusec;
1123 :
1124 37242 : ret = validate_fast_ad(r, auth->authorization_data);
1125 37242 : krb5_free_authenticator(r->context, &auth);
1126 37242 : if (ret)
1127 0 : goto out;
1128 : }
1129 : }
1130 :
1131 37242 : ret = tgs_check_authenticator(r->context, config, ac, b, &r->ticket->ticket.key);
1132 37242 : if (ret) {
1133 0 : krb5_auth_con_free(r->context, ac);
1134 0 : goto out;
1135 : }
1136 :
1137 37242 : usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1138 37242 : r->rk_is_subkey = 1;
1139 :
1140 37242 : ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
1141 37242 : if(ret){
1142 0 : const char *msg = krb5_get_error_message(r->context, ret);
1143 0 : krb5_auth_con_free(r->context, ac);
1144 0 : kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
1145 0 : krb5_free_error_message(r->context, msg);
1146 0 : goto out;
1147 : }
1148 37242 : if(subkey == NULL){
1149 0 : usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1150 0 : r->rk_is_subkey = 0;
1151 :
1152 0 : ret = krb5_auth_con_getkey(r->context, ac, &subkey);
1153 0 : if(ret) {
1154 0 : const char *msg = krb5_get_error_message(r->context, ret);
1155 0 : krb5_auth_con_free(r->context, ac);
1156 0 : kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
1157 0 : krb5_free_error_message(r->context, msg);
1158 0 : goto out;
1159 : }
1160 : }
1161 37242 : if(subkey == NULL){
1162 0 : krb5_auth_con_free(r->context, ac);
1163 0 : kdc_log(r->context, config, 4,
1164 : "Failed to get key for enc-authorization-data");
1165 0 : ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1166 0 : goto out;
1167 : }
1168 :
1169 37242 : krb5_free_keyblock_contents(r->context, &r->reply_key);
1170 37242 : ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
1171 37242 : krb5_free_keyblock(r->context, subkey);
1172 37242 : if (ret)
1173 0 : goto out;
1174 :
1175 37242 : if (b->enc_authorization_data) {
1176 : krb5_data ad;
1177 :
1178 0 : ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto);
1179 0 : if (ret) {
1180 0 : const char *msg = krb5_get_error_message(r->context, ret);
1181 0 : krb5_auth_con_free(r->context, ac);
1182 0 : kdc_log(r->context, config, 4, "krb5_crypto_init failed: %s", msg);
1183 0 : krb5_free_error_message(r->context, msg);
1184 0 : goto out;
1185 : }
1186 0 : ret = krb5_decrypt_EncryptedData (r->context,
1187 : crypto,
1188 : usage,
1189 0 : b->enc_authorization_data,
1190 : &ad);
1191 0 : krb5_crypto_destroy(r->context, crypto);
1192 0 : if(ret){
1193 0 : krb5_auth_con_free(r->context, ac);
1194 0 : kdc_log(r->context, config, 4,
1195 : "Failed to decrypt enc-authorization-data");
1196 0 : ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1197 0 : goto out;
1198 : }
1199 0 : ALLOC(*auth_data);
1200 0 : if (*auth_data == NULL) {
1201 0 : krb5_auth_con_free(r->context, ac);
1202 0 : ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1203 0 : goto out;
1204 : }
1205 0 : ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1206 0 : if(ret){
1207 0 : krb5_auth_con_free(r->context, ac);
1208 0 : free(*auth_data);
1209 0 : *auth_data = NULL;
1210 0 : kdc_log(r->context, config, 4, "Failed to decode authorization data");
1211 0 : ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1212 0 : goto out;
1213 : }
1214 : }
1215 :
1216 37242 : ret = validate_fast_ad(r, r->ticket->ticket.authorization_data);
1217 37242 : if (ret)
1218 0 : goto out;
1219 :
1220 :
1221 : /*
1222 : * Check for FAST request
1223 : */
1224 :
1225 37242 : ret = _kdc_fast_unwrap_request(r, r->ticket, ac);
1226 37242 : if (ret)
1227 0 : goto out;
1228 :
1229 37242 : krb5_auth_con_free(r->context, ac);
1230 :
1231 38595 : out:
1232 38595 : free_AP_REQ(&ap_req);
1233 :
1234 38595 : return ret;
1235 : }
1236 :
1237 : static krb5_error_code
1238 576 : build_server_referral(krb5_context context,
1239 : krb5_kdc_configuration *config,
1240 : krb5_crypto session,
1241 : krb5_const_realm referred_realm,
1242 : const PrincipalName *true_principal_name,
1243 : const PrincipalName *requested_principal,
1244 : krb5_data *outdata)
1245 : {
1246 : PA_ServerReferralData ref;
1247 : krb5_error_code ret;
1248 : EncryptedData ed;
1249 : krb5_data data;
1250 576 : size_t size = 0;
1251 :
1252 576 : memset(&ref, 0, sizeof(ref));
1253 :
1254 576 : if (referred_realm) {
1255 576 : ALLOC(ref.referred_realm);
1256 576 : if (ref.referred_realm == NULL)
1257 0 : goto eout;
1258 576 : *ref.referred_realm = strdup(referred_realm);
1259 576 : if (*ref.referred_realm == NULL)
1260 0 : goto eout;
1261 : }
1262 576 : if (true_principal_name) {
1263 0 : ALLOC(ref.true_principal_name);
1264 0 : if (ref.true_principal_name == NULL)
1265 0 : goto eout;
1266 0 : ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1267 0 : if (ret)
1268 0 : goto eout;
1269 : }
1270 576 : if (requested_principal) {
1271 576 : ALLOC(ref.requested_principal_name);
1272 576 : if (ref.requested_principal_name == NULL)
1273 0 : goto eout;
1274 576 : ret = copy_PrincipalName(requested_principal,
1275 : ref.requested_principal_name);
1276 576 : if (ret)
1277 0 : goto eout;
1278 : }
1279 :
1280 576 : ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1281 : data.data, data.length,
1282 : &ref, &size, ret);
1283 576 : free_PA_ServerReferralData(&ref);
1284 576 : if (ret)
1285 0 : return ret;
1286 576 : if (data.length != size)
1287 0 : krb5_abortx(context, "internal asn.1 encoder error");
1288 :
1289 576 : ret = krb5_encrypt_EncryptedData(context, session,
1290 : KRB5_KU_PA_SERVER_REFERRAL,
1291 : data.data, data.length,
1292 : 0 /* kvno */, &ed);
1293 576 : free(data.data);
1294 576 : if (ret)
1295 0 : return ret;
1296 :
1297 576 : ASN1_MALLOC_ENCODE(EncryptedData,
1298 : outdata->data, outdata->length,
1299 : &ed, &size, ret);
1300 576 : free_EncryptedData(&ed);
1301 576 : if (ret)
1302 0 : return ret;
1303 576 : if (outdata->length != size)
1304 0 : krb5_abortx(context, "internal asn.1 encoder error");
1305 :
1306 576 : return 0;
1307 0 : eout:
1308 0 : free_PA_ServerReferralData(&ref);
1309 0 : krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1310 0 : return ENOMEM;
1311 : }
1312 :
1313 : /*
1314 : * This function is intended to be used when failure to find the client is
1315 : * acceptable.
1316 : */
1317 : krb5_error_code
1318 36080 : _kdc_db_fetch_client(krb5_context context,
1319 : krb5_kdc_configuration *config,
1320 : int flags,
1321 : krb5_principal cp,
1322 : const char *cpn,
1323 : const char *krbtgt_realm,
1324 : HDB **clientdb,
1325 : hdb_entry **client_out)
1326 : {
1327 : krb5_error_code ret;
1328 36080 : hdb_entry *client = NULL;
1329 :
1330 36080 : *client_out = NULL;
1331 :
1332 36080 : ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1333 : NULL, clientdb, &client);
1334 36080 : if (ret == HDB_ERR_NOT_FOUND_HERE) {
1335 : /*
1336 : * This is OK, we are just trying to find out if they have
1337 : * been disabled or deleted in the meantime; missing secrets
1338 : * are OK.
1339 : */
1340 36080 : } else if (ret) {
1341 : /*
1342 : * If the client belongs to the same realm as our TGS, it
1343 : * should exist in the local database.
1344 : */
1345 : const char *msg;
1346 :
1347 49 : if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1348 0 : if (ret == HDB_ERR_NOENTRY)
1349 0 : ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1350 0 : kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1351 0 : return ret;
1352 : }
1353 :
1354 49 : msg = krb5_get_error_message(context, ret);
1355 49 : kdc_log(context, config, 4, "Client not found in database: %s", msg);
1356 49 : krb5_free_error_message(context, msg);
1357 36031 : } else if (client->flags.invalid || !client->flags.client) {
1358 0 : kdc_log(context, config, 4, "Client has invalid bit set");
1359 0 : _kdc_free_ent(context, *clientdb, client);
1360 0 : return KRB5KDC_ERR_POLICY;
1361 : }
1362 :
1363 36080 : *client_out = client;
1364 :
1365 36080 : return 0;
1366 : }
1367 :
1368 : static krb5_error_code
1369 37242 : tgs_build_reply(astgs_request_t priv,
1370 : krb5_enctype krbtgt_etype,
1371 : AuthorizationData **auth_data,
1372 : const struct sockaddr *from_addr)
1373 : {
1374 37242 : krb5_context context = priv->context;
1375 37242 : krb5_kdc_configuration *config = priv->config;
1376 37242 : KDC_REQ_BODY *b = &priv->req.req_body;
1377 37242 : const char *from = priv->from;
1378 : krb5_error_code ret, ret2;
1379 37242 : krb5_principal krbtgt_out_principal = NULL;
1380 37242 : krb5_principal user2user_princ = NULL;
1381 37242 : char *spn = NULL, *cpn = NULL, *krbtgt_out_n = NULL;
1382 37242 : char *user2user_name = NULL;
1383 : HDB *user2user_krbtgtdb;
1384 37242 : hdb_entry *user2user_krbtgt = NULL;
1385 : HDB *clientdb;
1386 37242 : HDB *serverdb = NULL;
1387 37242 : krb5_realm ref_realm = NULL;
1388 37242 : EncTicketPart *tgt = &priv->ticket->ticket;
1389 : const EncryptionKey *ekey;
1390 : krb5_keyblock sessionkey;
1391 : krb5_kvno kvno;
1392 37242 : krb5_pac user2user_pac = NULL;
1393 : uint16_t rodc_id;
1394 37242 : krb5_boolean add_ticket_sig = FALSE;
1395 37242 : const char *tgt_realm = /* Realm of TGT issuer */
1396 37242 : krb5_principal_get_realm(context, priv->krbtgt->principal);
1397 37242 : const char *our_realm = /* Realm of this KDC */
1398 37242 : krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1);
1399 37242 : char **capath = NULL;
1400 37242 : size_t num_capath = 0;
1401 :
1402 : HDB *krbtgt_outdb;
1403 37242 : hdb_entry *krbtgt_out = NULL;
1404 :
1405 : PrincipalName *s;
1406 : Realm r;
1407 : EncTicketPart adtkt;
1408 : char opt_str[128];
1409 37242 : krb5_boolean kdc_issued = FALSE;
1410 :
1411 : Key *tkey_sign;
1412 37242 : int flags = HDB_F_FOR_TGS_REQ;
1413 :
1414 : int result;
1415 :
1416 37242 : memset(&sessionkey, 0, sizeof(sessionkey));
1417 37242 : memset(&adtkt, 0, sizeof(adtkt));
1418 :
1419 37242 : s = b->sname;
1420 37242 : r = b->realm;
1421 :
1422 : /*
1423 : * The canonicalize KDC option is passed as a hint to the backend, but
1424 : * can typically be ignored. Per RFC 6806, names are not canonicalized
1425 : * in response to a TGS request (although we make an exception, see
1426 : * force-canonicalize below).
1427 : */
1428 37242 : if (b->kdc_options.canonicalize)
1429 6808 : flags |= HDB_F_CANON;
1430 :
1431 37242 : if (s == NULL) {
1432 0 : ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1433 0 : _kdc_set_const_e_text(priv, "No server in request");
1434 0 : goto out;
1435 : }
1436 :
1437 37242 : _krb5_principalname2krb5_principal(context, &priv->server_princ, *s, r);
1438 37242 : ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1439 37242 : if (ret)
1440 0 : goto out;
1441 37242 : spn = priv->sname;
1442 37242 : _krb5_principalname2krb5_principal(context, &priv->client_princ,
1443 : tgt->cname, tgt->crealm);
1444 37242 : ret = krb5_unparse_name(context, priv->client_princ, &priv->cname);
1445 37242 : if (ret)
1446 0 : goto out;
1447 37242 : cpn = priv->cname;
1448 37242 : result = unparse_flags(KDCOptions2int(b->kdc_options),
1449 : asn1_KDCOptions_units(),
1450 : opt_str, sizeof(opt_str));
1451 37242 : if (result > 0)
1452 32830 : kdc_log(context, config, 4,
1453 : "TGS-REQ %s from %s for %s [%s]",
1454 : cpn, from, spn, opt_str);
1455 : else
1456 4412 : kdc_log(context, config, 4,
1457 : "TGS-REQ %s from %s for %s", cpn, from, spn);
1458 :
1459 : /*
1460 : * Fetch server
1461 : */
1462 :
1463 37242 : server_lookup:
1464 37818 : if (priv->server)
1465 576 : _kdc_free_ent(context, serverdb, priv->server);
1466 37818 : priv->server = NULL;
1467 75636 : ret = _kdc_db_fetch(context, config, priv->server_princ,
1468 37818 : HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
1469 : NULL, &serverdb, &priv->server);
1470 37818 : priv->serverdb = serverdb;
1471 37818 : if (ret == HDB_ERR_NOT_FOUND_HERE) {
1472 47 : kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
1473 47 : kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
1474 47 : goto out;
1475 37771 : } else if (ret == HDB_ERR_WRONG_REALM) {
1476 576 : free(ref_realm);
1477 576 : ref_realm = strdup(priv->server->principal->realm);
1478 576 : if (ref_realm == NULL) {
1479 0 : ret = krb5_enomem(context);
1480 0 : goto out;
1481 : }
1482 :
1483 576 : kdc_log(context, config, 4,
1484 : "Returning a referral to realm %s for "
1485 : "server %s.",
1486 : ref_realm, spn);
1487 576 : krb5_free_principal(context, priv->server_princ);
1488 576 : priv->server_princ = NULL;
1489 576 : ret = krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1490 : ref_realm, NULL);
1491 576 : if (ret)
1492 0 : goto out;
1493 576 : free(priv->sname);
1494 576 : priv->sname = NULL;
1495 576 : ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1496 576 : if (ret)
1497 0 : goto out;
1498 576 : spn = priv->sname;
1499 :
1500 576 : goto server_lookup;
1501 37195 : } else if (ret) {
1502 : const char *new_rlm, *msg;
1503 : Realm req_rlm;
1504 : krb5_realm *realms;
1505 :
1506 1092 : priv->error_code = ret; /* advise policy plugin of failure reason */
1507 1092 : ret2 = _kdc_referral_policy(priv);
1508 1092 : if (ret2 == 0) {
1509 0 : krb5_xfree(priv->sname);
1510 0 : priv->sname = NULL;
1511 0 : ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1512 0 : if (ret)
1513 1092 : goto out;
1514 0 : goto server_lookup;
1515 1092 : } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) {
1516 1092 : ret = ret2;
1517 0 : } else if ((req_rlm = get_krbtgt_realm(&priv->server_princ->name)) != NULL) {
1518 0 : if (capath == NULL) {
1519 : /* With referalls, hierarchical capaths are always enabled */
1520 0 : ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1521 : req_rlm, TRUE, &capath, &num_capath);
1522 0 : if (ret2) {
1523 0 : ret = ret2;
1524 0 : kdc_audit_addreason((kdc_request_t)priv,
1525 : "No trusted path from client realm to ours");
1526 0 : goto out;
1527 : }
1528 : }
1529 0 : new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1530 0 : if (new_rlm) {
1531 0 : kdc_log(context, config, 5, "krbtgt from %s via %s for "
1532 : "realm %s not found, trying %s", tgt->crealm,
1533 : our_realm, req_rlm, new_rlm);
1534 :
1535 0 : free(ref_realm);
1536 0 : ref_realm = strdup(new_rlm);
1537 0 : if (ref_realm == NULL) {
1538 0 : ret = krb5_enomem(context);
1539 0 : goto out;
1540 : }
1541 :
1542 0 : krb5_free_principal(context, priv->server_princ);
1543 0 : priv->server_princ = NULL;
1544 0 : krb5_make_principal(context, &priv->server_princ, r,
1545 : KRB5_TGS_NAME, ref_realm, NULL);
1546 0 : free(priv->sname);
1547 0 : priv->sname = NULL;
1548 0 : ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1549 0 : if (ret)
1550 0 : goto out;
1551 0 : spn = priv->sname;
1552 0 : goto server_lookup;
1553 : }
1554 0 : } else if (need_referral(context, config, &b->kdc_options, priv->server_princ, &realms)) {
1555 0 : if (strcmp(realms[0], priv->server_princ->realm) != 0) {
1556 0 : kdc_log(context, config, 4,
1557 : "Returning a referral to realm %s for "
1558 : "server %s that was not found",
1559 : realms[0], spn);
1560 0 : krb5_free_principal(context, priv->server_princ);
1561 0 : priv->server_princ = NULL;
1562 0 : krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1563 : realms[0], NULL);
1564 0 : free(priv->sname);
1565 0 : priv->sname = NULL;
1566 0 : ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1567 0 : if (ret) {
1568 0 : krb5_free_host_realm(context, realms);
1569 0 : goto out;
1570 : }
1571 0 : spn = priv->sname;
1572 :
1573 0 : free(ref_realm);
1574 0 : ref_realm = strdup(realms[0]);
1575 :
1576 0 : krb5_free_host_realm(context, realms);
1577 0 : goto server_lookup;
1578 : }
1579 0 : krb5_free_host_realm(context, realms);
1580 : }
1581 1092 : msg = krb5_get_error_message(context, ret);
1582 1092 : kdc_log(context, config, 3,
1583 : "Server not found in database: %s: %s", spn, msg);
1584 1092 : krb5_free_error_message(context, msg);
1585 1092 : if (ret == HDB_ERR_NOENTRY)
1586 1092 : ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1587 1092 : kdc_audit_addreason((kdc_request_t)priv,
1588 : "Service principal unknown");
1589 1092 : goto out;
1590 : }
1591 :
1592 : /*
1593 : * Now refetch the primary krbtgt, and get the current kvno (the
1594 : * sign check may have been on an old kvno, and the server may
1595 : * have been an incoming trust)
1596 : */
1597 :
1598 36103 : ret = krb5_make_principal(context,
1599 : &krbtgt_out_principal,
1600 : our_realm,
1601 : KRB5_TGS_NAME,
1602 : our_realm,
1603 : NULL);
1604 36103 : if (ret) {
1605 0 : kdc_log(context, config, 4,
1606 : "Failed to make krbtgt principal name object for "
1607 : "authz-data signatures");
1608 0 : goto out;
1609 : }
1610 36103 : ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1611 36103 : if (ret) {
1612 0 : kdc_log(context, config, 4,
1613 : "Failed to make krbtgt principal name object for "
1614 : "authz-data signatures");
1615 0 : goto out;
1616 : }
1617 :
1618 36103 : ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1619 : HDB_F_GET_KRBTGT, NULL, &krbtgt_outdb, &krbtgt_out);
1620 36103 : if (ret) {
1621 0 : char *ktpn = NULL;
1622 0 : ret = krb5_unparse_name(context, priv->krbtgt->principal, &ktpn);
1623 0 : kdc_log(context, config, 4,
1624 : "No such principal %s (needed for authz-data signature keys) "
1625 : "while processing TGS-REQ for service %s with krbtg %s",
1626 : krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1627 0 : free(ktpn);
1628 0 : ret = KRB5KRB_AP_ERR_NOT_US;
1629 0 : goto out;
1630 : }
1631 :
1632 : /*
1633 : * Select enctype, return key and kvno.
1634 : */
1635 :
1636 : {
1637 : krb5_enctype etype;
1638 :
1639 36103 : if(b->kdc_options.enc_tkt_in_skey) {
1640 : Ticket *t;
1641 : krb5_principal p;
1642 : Key *uukey;
1643 0 : krb5uint32 second_kvno = 0;
1644 0 : krb5uint32 *kvno_ptr = NULL;
1645 : size_t i;
1646 : HDB *user2user_db;
1647 0 : hdb_entry *user2user_client = NULL;
1648 0 : krb5_boolean user2user_kdc_issued = FALSE;
1649 : char *tpn;
1650 :
1651 0 : if(b->additional_tickets == NULL ||
1652 0 : b->additional_tickets->len == 0){
1653 0 : ret = KRB5KDC_ERR_BADOPTION; /* ? */
1654 0 : kdc_log(context, config, 4,
1655 : "No second ticket present in user-to-user request");
1656 0 : kdc_audit_addreason((kdc_request_t)priv,
1657 : "No second ticket present in user-to-user request");
1658 0 : goto out;
1659 : }
1660 0 : t = &b->additional_tickets->val[0];
1661 0 : if(!get_krbtgt_realm(&t->sname)){
1662 0 : kdc_log(context, config, 4,
1663 : "Additional ticket is not a ticket-granting ticket");
1664 0 : kdc_audit_addreason((kdc_request_t)priv,
1665 : "Additional ticket is not a ticket-granting ticket");
1666 0 : ret = KRB5KDC_ERR_POLICY;
1667 0 : goto out;
1668 : }
1669 0 : ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1670 0 : if (ret)
1671 0 : goto out;
1672 :
1673 0 : ret = krb5_unparse_name(context, p, &tpn);
1674 0 : if (ret)
1675 0 : goto out;
1676 0 : if(t->enc_part.kvno){
1677 0 : second_kvno = *t->enc_part.kvno;
1678 0 : kvno_ptr = &second_kvno;
1679 : }
1680 0 : ret = _kdc_db_fetch(context, config, p,
1681 : HDB_F_GET_KRBTGT, kvno_ptr,
1682 : &user2user_krbtgtdb, &user2user_krbtgt);
1683 0 : krb5_free_principal(context, p);
1684 0 : if(ret){
1685 0 : if (ret == HDB_ERR_NOENTRY)
1686 0 : ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1687 0 : kdc_audit_addreason((kdc_request_t)priv,
1688 : "User-to-user service principal (TGS) unknown");
1689 0 : krb5_xfree(tpn);
1690 0 : goto out;
1691 : }
1692 0 : ret = hdb_enctype2key(context, user2user_krbtgt, NULL,
1693 : t->enc_part.etype, &uukey);
1694 0 : if(ret){
1695 0 : ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1696 0 : kdc_audit_addreason((kdc_request_t)priv,
1697 : "User-to-user enctype not supported");
1698 0 : krb5_xfree(tpn);
1699 0 : goto out;
1700 : }
1701 0 : ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1702 0 : if(ret) {
1703 0 : kdc_audit_addreason((kdc_request_t)priv,
1704 : "User-to-user TGT decrypt failure");
1705 0 : krb5_xfree(tpn);
1706 0 : goto out;
1707 : }
1708 :
1709 0 : ret = _kdc_verify_flags(context, config, &adtkt, tpn);
1710 0 : if (ret) {
1711 0 : kdc_audit_addreason((kdc_request_t)priv,
1712 : "User-to-user TGT expired or invalid");
1713 0 : krb5_xfree(tpn);
1714 0 : goto out;
1715 : }
1716 0 : krb5_xfree(tpn);
1717 :
1718 : /* Fetch the name from the TGT. */
1719 0 : ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1720 : adtkt.cname, adtkt.crealm);
1721 0 : if (ret)
1722 0 : goto out;
1723 :
1724 0 : ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1725 0 : if (ret)
1726 0 : goto out;
1727 :
1728 : /*
1729 : * Look up the name given in the TGT in the database. The user
1730 : * claims to have a ticket-granting-ticket to our KDC, so we should
1731 : * fail hard if we can't find the user - otherwise we can't do
1732 : * proper checks.
1733 : */
1734 0 : ret = _kdc_db_fetch(context, config, user2user_princ,
1735 0 : HDB_F_GET_CLIENT | flags,
1736 : NULL, &user2user_db, &user2user_client);
1737 0 : if (ret == HDB_ERR_NOENTRY)
1738 0 : ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1739 0 : if (ret)
1740 0 : goto out;
1741 :
1742 : /*
1743 : * The account is present in the database, now check the
1744 : * account flags.
1745 : *
1746 : * We check this as a client (because the purpose of
1747 : * user2user is that the server flag is not set, because
1748 : * the long-term key is not strong, but this does mean
1749 : * that a client with an expired password can't get accept
1750 : * a user2user ticket.
1751 : */
1752 0 : ret = kdc_check_flags(priv,
1753 : FALSE,
1754 : user2user_client,
1755 : NULL);
1756 0 : if (ret) {
1757 0 : _kdc_free_ent(context, user2user_db, user2user_client);
1758 0 : goto out;
1759 : }
1760 :
1761 : /*
1762 : * Also check that the account is the same one specified in the
1763 : * request.
1764 : */
1765 0 : ret = _kdc_check_client_matches_target_service(context,
1766 : config,
1767 : serverdb,
1768 : priv->server,
1769 : user2user_client,
1770 : user2user_princ);
1771 0 : if (ret) {
1772 0 : _kdc_free_ent(context, user2user_db, user2user_client);
1773 0 : goto out;
1774 : }
1775 :
1776 : /* Verify the PAC of the TGT. */
1777 0 : ret = _kdc_check_pac(priv, user2user_princ, NULL,
1778 : user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1779 0 : &uukey->key, &priv->ticket_key->key, &adtkt,
1780 : &user2user_kdc_issued, &user2user_pac, NULL, NULL);
1781 0 : _kdc_free_ent(context, user2user_db, user2user_client);
1782 0 : if (ret) {
1783 0 : const char *msg = krb5_get_error_message(context, ret);
1784 0 : kdc_log(context, config, 0,
1785 : "Verify PAC failed for %s (%s) from %s with %s",
1786 : spn, user2user_name, from, msg);
1787 0 : krb5_free_error_message(context, msg);
1788 0 : goto out;
1789 : }
1790 :
1791 0 : if ((config->require_pac && !user2user_pac)
1792 0 : || (user2user_pac && !user2user_kdc_issued))
1793 : {
1794 0 : ret = KRB5KDC_ERR_BADOPTION;
1795 0 : kdc_log(context, config, 0,
1796 : "Ticket not signed with PAC; user-to-user failed (%s).",
1797 0 : user2user_pac ? "Ticket unsigned" : "No PAC");
1798 0 : goto out;
1799 : }
1800 :
1801 0 : ekey = &adtkt.key;
1802 0 : for(i = 0; i < b->etype.len; i++)
1803 0 : if (b->etype.val[i] == adtkt.key.keytype)
1804 0 : break;
1805 0 : if(i == b->etype.len) {
1806 0 : kdc_log(context, config, 4,
1807 : "Addition ticket have not matching etypes");
1808 0 : krb5_clear_error_message(context);
1809 0 : ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1810 0 : kdc_audit_addreason((kdc_request_t)priv,
1811 : "No matching enctypes for 2nd ticket");
1812 0 : goto out;
1813 : }
1814 0 : etype = b->etype.val[i];
1815 0 : kvno = 0;
1816 : } else {
1817 : Key *skey;
1818 :
1819 36103 : ret = _kdc_find_session_etype(priv, b->etype.val, b->etype.len,
1820 36103 : priv->server, &etype);
1821 36103 : if(ret) {
1822 35 : kdc_log(context, config, 4,
1823 : "Server (%s) has no support for etypes", spn);
1824 35 : kdc_audit_addreason((kdc_request_t)priv,
1825 : "Enctype not supported");
1826 35 : goto out;
1827 : }
1828 36068 : ret = _kdc_get_preferred_key(context, config, priv->server, spn,
1829 : NULL, &skey);
1830 36068 : if(ret) {
1831 82 : kdc_log(context, config, 4,
1832 : "Server (%s) has no supported etypes", spn);
1833 82 : kdc_audit_addreason((kdc_request_t)priv,
1834 : "Enctype not supported");
1835 82 : goto out;
1836 : }
1837 35986 : ekey = &skey->key;
1838 35986 : kvno = priv->server->kvno;
1839 : }
1840 :
1841 35986 : ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1842 35986 : if (ret)
1843 0 : goto out;
1844 : }
1845 :
1846 : /*
1847 : * Check that service is in the same realm as the krbtgt. If it's
1848 : * not the same, it's someone that is using a uni-directional trust
1849 : * backward.
1850 : */
1851 :
1852 : /*
1853 : * The first realm is the realm of the service, the second is
1854 : * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1855 : * encrypted to. The redirection via the krbtgt_out entry allows
1856 : * the DB to possibly correct the case of the realm (Samba4 does
1857 : * this) before the strcmp()
1858 : */
1859 35986 : if (strcmp(krb5_principal_get_realm(context, priv->server->principal),
1860 35986 : krb5_principal_get_realm(context, krbtgt_out->principal)) != 0) {
1861 : char *ktpn;
1862 0 : ret = krb5_unparse_name(context, krbtgt_out->principal, &ktpn);
1863 0 : kdc_log(context, config, 4,
1864 : "Request with wrong krbtgt: %s",
1865 : (ret == 0) ? ktpn : "<unknown>");
1866 0 : if(ret == 0)
1867 0 : free(ktpn);
1868 0 : ret = KRB5KRB_AP_ERR_NOT_US;
1869 0 : kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
1870 0 : goto out;
1871 : }
1872 :
1873 35986 : ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1874 : NULL, &tkey_sign);
1875 35986 : if (ret) {
1876 0 : kdc_log(context, config, 4,
1877 : "Failed to find key for krbtgt PAC signature");
1878 0 : kdc_audit_addreason((kdc_request_t)priv,
1879 : "Failed to find key for krbtgt PAC signature");
1880 0 : goto out;
1881 : }
1882 35986 : ret = hdb_enctype2key(context, krbtgt_out, NULL,
1883 35986 : tkey_sign->key.keytype, &tkey_sign);
1884 35986 : if(ret) {
1885 0 : kdc_log(context, config, 4,
1886 : "Failed to find key for krbtgt PAC signature");
1887 0 : kdc_audit_addreason((kdc_request_t)priv,
1888 : "Failed to find key for krbtgt PAC signature");
1889 0 : goto out;
1890 : }
1891 :
1892 35986 : if (_kdc_synthetic_princ_used_p(context, priv->ticket))
1893 0 : flags |= HDB_F_SYNTHETIC_OK;
1894 :
1895 35986 : ret = _kdc_db_fetch_client(context, config, flags, priv->client_princ,
1896 : cpn, our_realm, &clientdb, &priv->client);
1897 35986 : if (ret)
1898 0 : goto out;
1899 35986 : flags &= ~HDB_F_SYNTHETIC_OK;
1900 35986 : priv->clientdb = clientdb;
1901 :
1902 107958 : ret = _kdc_check_pac(priv, priv->client_princ, NULL,
1903 : priv->client, priv->server,
1904 : priv->krbtgt, priv->krbtgt,
1905 71972 : &priv->ticket_key->key, &priv->ticket_key->key, tgt,
1906 : &kdc_issued, &priv->pac, &priv->canon_client_princ,
1907 : &priv->pac_attributes);
1908 35986 : if (ret) {
1909 22 : const char *msg = krb5_get_error_message(context, ret);
1910 22 : kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
1911 22 : kdc_log(context, config, 4,
1912 : "Verify PAC failed for %s (%s) from %s with %s",
1913 : spn, cpn, from, msg);
1914 22 : krb5_free_error_message(context, msg);
1915 22 : goto out;
1916 : }
1917 :
1918 : /*
1919 : * Process request
1920 : */
1921 :
1922 : /*
1923 : * Services for User: protocol transition and constrained delegation
1924 : */
1925 :
1926 35964 : ret = _kdc_validate_services_for_user(priv);
1927 35964 : if (ret)
1928 83 : goto out;
1929 :
1930 : /*
1931 : * Check flags
1932 : */
1933 :
1934 35881 : ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
1935 35881 : if(ret)
1936 0 : goto out;
1937 :
1938 35887 : if((b->kdc_options.validate || b->kdc_options.renew) &&
1939 6 : !krb5_principal_compare(context,
1940 6 : priv->krbtgt->principal,
1941 6 : priv->server->principal)){
1942 0 : kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
1943 0 : kdc_log(context, config, 4, "Inconsistent request.");
1944 0 : ret = KRB5KDC_ERR_SERVER_NOMATCH;
1945 0 : goto out;
1946 : }
1947 :
1948 : /* check for valid set of addresses */
1949 35881 : if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
1950 0 : if (config->check_ticket_addresses) {
1951 0 : ret = KRB5KRB_AP_ERR_BADADDR;
1952 0 : kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
1953 0 : kdc_log(context, config, 4, "Request from wrong address");
1954 0 : kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
1955 0 : goto out;
1956 0 : } else if (config->warn_ticket_addresses) {
1957 0 : kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
1958 : }
1959 : }
1960 :
1961 : /* check local and per-principal anonymous ticket issuance policy */
1962 35881 : if (is_anon_tgs_request_p(b, tgt)) {
1963 0 : ret = _kdc_check_anon_policy(priv);
1964 0 : if (ret)
1965 0 : goto out;
1966 : }
1967 :
1968 : /*
1969 : * If this is an referral, add server referral data to the
1970 : * auth_data reply .
1971 : */
1972 35881 : if (ref_realm) {
1973 : PA_DATA pa;
1974 : krb5_crypto crypto;
1975 :
1976 576 : kdc_log(context, config, 3,
1977 : "Adding server referral to %s", ref_realm);
1978 :
1979 576 : ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1980 576 : if (ret)
1981 0 : goto out;
1982 :
1983 576 : ret = build_server_referral(context, config, crypto, ref_realm,
1984 : NULL, s, &pa.padata_value);
1985 576 : krb5_crypto_destroy(context, crypto);
1986 576 : if (ret) {
1987 0 : kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
1988 0 : kdc_log(context, config, 4,
1989 : "Failed building server referral");
1990 0 : goto out;
1991 : }
1992 576 : pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1993 :
1994 576 : ret = add_METHOD_DATA(priv->rep.padata, &pa);
1995 576 : krb5_data_free(&pa.padata_value);
1996 576 : if (ret) {
1997 0 : kdc_log(context, config, 4,
1998 : "Add server referral METHOD-DATA failed");
1999 0 : goto out;
2000 : }
2001 : }
2002 :
2003 : /*
2004 : * Only add ticket signature if the requested server is not krbtgt, and
2005 : * either the header server is krbtgt or, in the case of renewal/validation
2006 : * if it was signed with PAC ticket signature and we verified it.
2007 : * Currently Heimdal only allows renewal of krbtgt anyway but that might
2008 : * change one day (see issue #763) so make sure to check for it.
2009 : */
2010 :
2011 71762 : if (kdc_issued &&
2012 35881 : !krb5_principal_is_krbtgt(context, priv->server->principal)) {
2013 :
2014 : /* Validate armor TGT before potentially including device claims */
2015 14682 : if (priv->armor_ticket) {
2016 0 : ret = _kdc_fast_check_armor_pac(priv);
2017 0 : if (ret)
2018 0 : goto out;
2019 : }
2020 :
2021 14682 : add_ticket_sig = TRUE;
2022 : }
2023 :
2024 : /*
2025 : * Active-Directory implementations use the high part of the kvno as the
2026 : * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2027 : */
2028 :
2029 35881 : rodc_id = krbtgt_out->kvno >> 16;
2030 :
2031 : /*
2032 : *
2033 : */
2034 :
2035 71762 : ret = tgs_make_reply(priv,
2036 : tgt,
2037 : ekey,
2038 35881 : &tkey_sign->key,
2039 : &sessionkey,
2040 : kvno,
2041 : *auth_data,
2042 : tgt_realm,
2043 : rodc_id,
2044 : add_ticket_sig);
2045 :
2046 37242 : out:
2047 37242 : free(user2user_name);
2048 37242 : free(krbtgt_out_n);
2049 37242 : _krb5_free_capath(context, capath);
2050 :
2051 37242 : krb5_free_keyblock_contents(context, &sessionkey);
2052 37242 : if(krbtgt_out)
2053 36103 : _kdc_free_ent(context, krbtgt_outdb, krbtgt_out);
2054 37242 : if(user2user_krbtgt)
2055 0 : _kdc_free_ent(context, user2user_krbtgtdb, user2user_krbtgt);
2056 :
2057 37242 : krb5_free_principal(context, user2user_princ);
2058 37242 : krb5_free_principal(context, krbtgt_out_principal);
2059 37242 : free(ref_realm);
2060 :
2061 37242 : free_EncTicketPart(&adtkt);
2062 :
2063 37242 : krb5_pac_free(context, user2user_pac);
2064 :
2065 37242 : return ret;
2066 : }
2067 :
2068 : /*
2069 : *
2070 : */
2071 :
2072 : krb5_error_code
2073 38595 : _kdc_tgs_rep(astgs_request_t r)
2074 : {
2075 38595 : krb5_kdc_configuration *config = r->config;
2076 38595 : KDC_REQ *req = &r->req;
2077 38595 : krb5_data *data = r->reply;
2078 38595 : const char *from = r->from;
2079 38595 : struct sockaddr *from_addr = r->addr;
2080 38595 : int datagram_reply = r->datagram_reply;
2081 38595 : AuthorizationData *auth_data = NULL;
2082 : krb5_error_code ret;
2083 38595 : int i = 0;
2084 : const PA_DATA *tgs_req, *pa;
2085 38595 : krb5_enctype krbtgt_etype = ETYPE_NULL;
2086 :
2087 38595 : time_t *csec = NULL;
2088 38595 : int *cusec = NULL;
2089 :
2090 38595 : r->e_text = NULL;
2091 :
2092 38595 : if(req->padata == NULL){
2093 0 : ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2094 0 : kdc_log(r->context, config, 4,
2095 : "TGS-REQ from %s without PA-DATA", from);
2096 0 : goto out;
2097 : }
2098 :
2099 38595 : i = 0;
2100 38595 : pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
2101 38595 : if (pa) {
2102 0 : kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2103 0 : ret = KRB5KRB_ERR_GENERIC;
2104 0 : goto out;
2105 : }
2106 :
2107 38595 : i = 0;
2108 38595 : tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2109 38595 : if(tgs_req == NULL){
2110 0 : ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2111 :
2112 0 : kdc_log(r->context, config, 4,
2113 : "TGS-REQ from %s without PA-TGS-REQ", from);
2114 0 : goto out;
2115 : }
2116 38595 : ret = tgs_parse_request(r, tgs_req,
2117 : &krbtgt_etype,
2118 : from, from_addr,
2119 : &csec, &cusec,
2120 : &auth_data);
2121 38595 : if (ret == HDB_ERR_NOT_FOUND_HERE) {
2122 : /* kdc_log() is called in tgs_parse_request() */
2123 1353 : goto out;
2124 : }
2125 37242 : if (ret) {
2126 0 : kdc_log(r->context, config, 4,
2127 : "Failed parsing TGS-REQ from %s", from);
2128 0 : goto out;
2129 : }
2130 :
2131 37242 : ret = _kdc_fast_strengthen_reply_key(r);
2132 37242 : if (ret)
2133 0 : goto out;
2134 :
2135 37242 : ALLOC(r->rep.padata);
2136 37242 : if (r->rep.padata == NULL) {
2137 0 : ret = ENOMEM;
2138 0 : krb5_set_error_message(r->context, ret, N_("malloc: out of memory", ""));
2139 0 : goto out;
2140 : }
2141 :
2142 37242 : ret = tgs_build_reply(r,
2143 : krbtgt_etype,
2144 : &auth_data,
2145 : from_addr);
2146 37242 : if (ret) {
2147 1514 : kdc_log(r->context, config, 4,
2148 : "Failed building TGS-REP to %s", from);
2149 1514 : goto out;
2150 : }
2151 :
2152 : /* */
2153 35728 : if (datagram_reply && data->length > config->max_datagram_reply_length) {
2154 0 : krb5_data_free(data);
2155 0 : ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2156 0 : _kdc_set_const_e_text(r, "Reply packet too large");
2157 : }
2158 :
2159 74323 : out:
2160 38595 : r->error_code = ret;
2161 : {
2162 38595 : krb5_error_code ret2 = _kdc_audit_request(r);
2163 38595 : if (ret2) {
2164 0 : krb5_data_free(data);
2165 0 : ret = ret2;
2166 : }
2167 : }
2168 :
2169 38595 : if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2170 1467 : METHOD_DATA error_method = { 0, NULL };
2171 :
2172 1467 : kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
2173 5868 : ret = _kdc_fast_mk_error(r,
2174 : &error_method,
2175 : r->armor_crypto,
2176 1467 : &req->req_body,
2177 : r->error_code,
2178 1467 : r->client_princ ? r->client_princ :(r->ticket != NULL ? r->ticket->client : NULL),
2179 1467 : r->server_princ ? r->server_princ :(r->ticket != NULL ? r->ticket->server : NULL),
2180 : csec, cusec,
2181 : data);
2182 1467 : free_METHOD_DATA(&error_method);
2183 : }
2184 38595 : free(csec);
2185 38595 : free(cusec);
2186 :
2187 38595 : free_TGS_REP(&r->rep);
2188 38595 : free_TransitedEncoding(&r->et.transited);
2189 38595 : free(r->et.starttime);
2190 38595 : free(r->et.renew_till);
2191 38595 : if(r->et.authorization_data) {
2192 35728 : free_AuthorizationData(r->et.authorization_data);
2193 35728 : free(r->et.authorization_data);
2194 : }
2195 38595 : free_LastReq(&r->ek.last_req);
2196 38595 : if (r->et.key.keyvalue.data) {
2197 35728 : memset_s(r->et.key.keyvalue.data, 0, r->et.key.keyvalue.length,
2198 : r->et.key.keyvalue.length);
2199 : }
2200 38595 : free_EncryptionKey(&r->et.key);
2201 :
2202 38595 : if (r->canon_client_princ) {
2203 35964 : krb5_free_principal(r->context, r->canon_client_princ);
2204 35964 : r->canon_client_princ = NULL;
2205 : }
2206 38595 : if (r->armor_crypto) {
2207 32153 : krb5_crypto_destroy(r->context, r->armor_crypto);
2208 32153 : r->armor_crypto = NULL;
2209 : }
2210 38595 : if (r->armor_ticket)
2211 0 : krb5_free_ticket(r->context, r->armor_ticket);
2212 38595 : if (r->armor_server)
2213 0 : _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server);
2214 38595 : if (r->explicit_armor_client)
2215 0 : _kdc_free_ent(r->context,
2216 : r->explicit_armor_clientdb,
2217 : r->explicit_armor_client);
2218 38595 : if (r->explicit_armor_pac)
2219 0 : krb5_pac_free(r->context, r->explicit_armor_pac);
2220 38595 : krb5_free_keyblock_contents(r->context, &r->reply_key);
2221 38595 : krb5_free_keyblock_contents(r->context, &r->strengthen_key);
2222 :
2223 38595 : if (r->ticket)
2224 37242 : krb5_free_ticket(r->context, r->ticket);
2225 38595 : if (r->krbtgt)
2226 37242 : _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt);
2227 :
2228 38595 : if (r->client)
2229 35937 : _kdc_free_ent(r->context, r->clientdb, r->client);
2230 38595 : krb5_free_principal(r->context, r->client_princ);
2231 38595 : if (r->server)
2232 36103 : _kdc_free_ent(r->context, r->serverdb, r->server);
2233 38595 : krb5_free_principal(r->context, r->server_princ);
2234 38595 : _kdc_free_fast_state(&r->fast);
2235 38595 : krb5_pac_free(r->context, r->pac);
2236 :
2237 38595 : if (auth_data) {
2238 0 : free_AuthorizationData(auth_data);
2239 0 : free(auth_data);
2240 : }
2241 :
2242 38595 : return ret;
2243 : }
|