1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/do_tgs_req.c - KDC Routines to deal with TGS_REQ's */
3 /*
4 * Copyright 1990, 1991, 2001, 2007, 2008, 2009, 2013, 2014 by the
5 * Massachusetts Institute of Technology. All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26 /*
27 * Copyright (c) 2006-2008, Novell, Inc.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions are met:
32 *
33 * * Redistributions of source code must retain the above copyright notice,
34 * this list of conditions and the following disclaimer.
35 * * Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * * The copyright holder's name is not used to endorse or promote products
39 * derived from this software without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
42 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
45 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
46 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
47 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
51 * POSSIBILITY OF SUCH DAMAGE.
52 */
53
54 #include "k5-int.h"
55
56 #include <syslog.h>
57 #ifdef HAVE_NETINET_IN_H
58 #include <sys/types.h>
59 #include <netinet/in.h>
60 #ifndef hpux
61 #include <arpa/inet.h>
62 #endif
63 #endif
64
65 #include "kdc_util.h"
66 #include "kdc_audit.h"
67 #include "policy.h"
68 #include "extern.h"
69 #include "adm_proto.h"
70 #include <ctype.h>
71
72 static krb5_error_code
73 find_alternate_tgs(kdc_realm_t *, krb5_principal, krb5_db_entry **,
74 const char**);
75
76 static krb5_error_code
77 prepare_error_tgs(struct kdc_request_state *, krb5_kdc_req *,krb5_ticket *,int,
78 krb5_principal,krb5_data **,const char *, krb5_pa_data **);
79
80 static krb5_error_code
81 decrypt_2ndtkt(kdc_realm_t *, krb5_kdc_req *, krb5_flags, const krb5_ticket **,
82 krb5_db_entry **, krb5_keyblock **, const char **);
83
84 static krb5_error_code
85 gen_session_key(kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *,
86 krb5_keyblock *, const char **);
87
88 static krb5_int32
89 find_referral_tgs(kdc_realm_t *, krb5_kdc_req *, krb5_principal *);
90
91 static krb5_error_code
92 db_get_svc_princ(krb5_context, krb5_principal, krb5_flags,
93 krb5_db_entry **, const char **);
94
95 static krb5_error_code
96 search_sprinc(kdc_realm_t *, krb5_kdc_req *, krb5_flags,
97 krb5_db_entry **, const char **);
98
99 /*ARGSUSED*/
100 krb5_error_code
process_tgs_req(krb5_kdc_req * request,krb5_data * pkt,const krb5_fulladdr * from,kdc_realm_t * kdc_active_realm,krb5_data ** response)101 process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
102 const krb5_fulladdr *from, kdc_realm_t *kdc_active_realm,
103 krb5_data **response)
104 {
105 krb5_keyblock * subkey = 0;
106 krb5_keyblock *header_key = NULL;
107 krb5_keyblock *stkt_server_key = NULL;
108 krb5_keyblock *subject_key;
109 krb5_db_entry *server = NULL;
110 krb5_db_entry *stkt_server = NULL;
111 krb5_db_entry *subject_server;
112 krb5_kdc_rep reply;
113 krb5_enc_kdc_rep_part reply_encpart;
114 krb5_ticket ticket_reply, *header_ticket = 0;
115 const krb5_ticket *stkt = NULL;
116 krb5_enc_tkt_part enc_tkt_reply;
117 int newtransited = 0;
118 krb5_error_code retval = 0;
119 krb5_keyblock server_keyblock, *encrypting_key;
120 krb5_timestamp kdc_time, authtime = 0;
121 krb5_keyblock session_key, local_tgt_key;
122 krb5_keyblock *reply_key = NULL;
123 krb5_principal cprinc = NULL, sprinc = NULL, altcprinc = NULL;
124 krb5_const_principal authdata_client;
125 krb5_principal stkt_authdata_client = NULL;
126 krb5_last_req_entry *nolrarray[2], nolrentry;
127 int errcode;
128 const char *status = 0;
129 krb5_enc_tkt_part *header_enc_tkt = NULL; /* TGT */
130 krb5_enc_tkt_part *subject_tkt = NULL; /* TGT or evidence ticket */
131 krb5_db_entry *client = NULL, *header_server = NULL;
132 krb5_db_entry *local_tgt, *local_tgt_storage = NULL;
133 krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */
134 krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
135 unsigned int c_flags = 0, s_flags = 0; /* client/server KDB flags */
136 krb5_boolean is_referral, is_crossrealm;
137 const char *emsg = NULL;
138 krb5_kvno ticket_kvno = 0;
139 struct kdc_request_state *state = NULL;
140 krb5_pa_data *pa_tgs_req; /*points into request*/
141 krb5_data scratch;
142 krb5_pa_data **e_data = NULL;
143 krb5_audit_state *au_state = NULL;
144 krb5_data **auth_indicators = NULL;
145 void *ad_info = NULL, *stkt_ad_info = NULL;
146
147 memset(&reply, 0, sizeof(reply));
148 memset(&reply_encpart, 0, sizeof(reply_encpart));
149 memset(&ticket_reply, 0, sizeof(ticket_reply));
150 memset(&enc_tkt_reply, 0, sizeof(enc_tkt_reply));
151 memset(&server_keyblock, 0, sizeof(server_keyblock));
152 memset(&local_tgt_key, 0, sizeof(local_tgt_key));
153 session_key.contents = NULL;
154
155 /* Save pointer to client-requested service principal, in case of
156 * errors before a successful call to search_sprinc(). */
157 sprinc = request->server;
158
159 if (request->msg_type != KRB5_TGS_REQ) {
160 krb5_free_kdc_req(kdc_context, request);
161 return KRB5_BADMSGTYPE;
162 }
163
164 errcode = kdc_make_rstate(kdc_active_realm, &state);
165 if (errcode !=0) {
166 krb5_free_kdc_req(kdc_context, request);
167 return errcode;
168 }
169
170 /* Initialize audit state. */
171 errcode = kau_init_kdc_req(kdc_context, request, from, &au_state);
172 if (errcode) {
173 krb5_free_kdc_req(kdc_context, request);
174 return errcode;
175 }
176 /* Seed the audit trail with the request ID and basic information. */
177 kau_tgs_req(kdc_context, TRUE, au_state);
178
179 errcode = kdc_process_tgs_req(kdc_active_realm,
180 request, from, pkt, &header_ticket,
181 &header_server, &header_key, &subkey,
182 &pa_tgs_req);
183 if (header_ticket && header_ticket->enc_part2)
184 cprinc = header_ticket->enc_part2->client;
185
186 if (errcode) {
187 status = "PROCESS_TGS";
188 goto cleanup;
189 }
190
191 if (!header_ticket) {
192 errcode = KRB5_NO_TKT_SUPPLIED; /* XXX? */
193 goto cleanup;
194 }
195 errcode = kau_make_tkt_id(kdc_context, header_ticket,
196 &au_state->tkt_in_id);
197 if (errcode)
198 goto cleanup;
199
200 scratch.length = pa_tgs_req->length;
201 scratch.data = (char *) pa_tgs_req->contents;
202 errcode = kdc_find_fast(&request, &scratch, subkey,
203 header_ticket->enc_part2->session, state, NULL);
204 /* Reset sprinc because kdc_find_fast() can replace request. */
205 sprinc = request->server;
206 if (errcode !=0) {
207 status = "FIND_FAST";
208 goto cleanup;
209 }
210
211 errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server,
212 &local_tgt, &local_tgt_storage, &local_tgt_key);
213 if (errcode) {
214 status = "GET_LOCAL_TGT";
215 goto cleanup;
216 }
217
218 /* Ignore (for now) the request modification due to FAST processing. */
219 au_state->request = request;
220
221 /*
222 * Pointer to the encrypted part of the header ticket, which may be
223 * replaced to point to the encrypted part of the evidence ticket
224 * if constrained delegation is used. This simplifies the number of
225 * special cases for constrained delegation.
226 */
227 header_enc_tkt = header_ticket->enc_part2;
228
229 /*
230 * We've already dealt with the AP_REQ authentication, so we can
231 * use header_ticket freely. The encrypted part (if any) has been
232 * decrypted with the session key.
233 */
234
235 au_state->stage = SRVC_PRINC;
236
237 /* XXX make sure server here has the proper realm...taken from AP_REQ
238 header? */
239
240 if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
241 setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
242 setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
243 }
244
245 errcode = search_sprinc(kdc_active_realm, request, s_flags, &server,
246 &status);
247 if (errcode != 0)
248 goto cleanup;
249 sprinc = server->princ;
250
251 /* If we got a cross-realm TGS which is not the requested server, we are
252 * issuing a referral (or alternate TGT, which we treat similarly). */
253 is_referral = is_cross_tgs_principal(server->princ) &&
254 !krb5_principal_compare(kdc_context, request->server, server->princ);
255
256 au_state->stage = VALIDATE_POL;
257
258 if ((errcode = krb5_timeofday(kdc_context, &kdc_time)))
259 goto cleanup;
260
261 is_crossrealm = !data_eq(header_server->princ->realm, sprinc->realm);
262 if (is_crossrealm)
263 setflag(c_flags, KRB5_KDB_FLAG_CROSS_REALM);
264 if (is_referral)
265 setflag(c_flags, KRB5_KDB_FLAG_ISSUING_REFERRAL);
266
267 /* Check for protocol transition */
268 errcode = kdc_process_s4u2self_req(kdc_active_realm, request, server,
269 subkey, header_enc_tkt->session,
270 &s4u_x509_user, &client, &status);
271 if (s4u_x509_user != NULL || errcode != 0) {
272 if (s4u_x509_user != NULL)
273 au_state->s4u2self_user = s4u_x509_user->user_id.user;
274 au_state->status = status;
275 kau_s4u2self(kdc_context, errcode ? FALSE : TRUE, au_state);
276 au_state->s4u2self_user = NULL;
277 }
278
279 /* For user-to-user and S4U2Proxy requests, decrypt the second ticket. */
280 errcode = decrypt_2ndtkt(kdc_active_realm, request, c_flags,
281 &stkt, &stkt_server, &stkt_server_key, &status);
282 if (errcode)
283 goto cleanup;
284
285 retval = validate_tgs_request(kdc_active_realm, request, server,
286 header_ticket, stkt, stkt_server, kdc_time,
287 s4u_x509_user, client, is_crossrealm,
288 is_referral, &status, &e_data);
289 if (retval) {
290 if (retval == KDC_ERR_POLICY || retval == KDC_ERR_BADOPTION)
291 au_state->violation = PROT_CONSTRAINT;
292 errcode = retval + ERROR_TABLE_BASE_krb5;
293 goto cleanup;
294 }
295
296 if (errcode)
297 goto cleanup;
298
299 if (s4u_x509_user != NULL && client == NULL) {
300 /*
301 * For an S4U2Self referral request (the requesting service is
302 * following a referral back to its own realm), the authdata in the
303 * header ticket should be for the requested client.
304 */
305 setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
306 authdata_client = s4u_x509_user->user_id.user;
307 } else {
308 /* Otherwise (including for initial S4U2Self requests), the authdata
309 * should be for the header ticket client. */
310 authdata_client = header_enc_tkt->client;
311 }
312 errcode = krb5_db_get_authdata_info(kdc_context, c_flags,
313 header_enc_tkt->authorization_data,
314 authdata_client, request->server,
315 header_key, &local_tgt_key, local_tgt,
316 header_enc_tkt->times.authtime,
317 &ad_info, NULL);
318 if (errcode && errcode != KRB5_PLUGIN_OP_NOTSUPP)
319 goto cleanup;
320
321 /* Flag all S4U2Self requests now that we have checked the authdata. */
322 if (s4u_x509_user != NULL)
323 setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
324
325 if (isflagset(request->kdc_options, KDC_OPT_CNAME_IN_ADDL_TKT)) {
326 /* Do constrained delegation protocol and authorization checks. */
327 setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
328
329 errcode = kdc_process_s4u2proxy_req(kdc_active_realm, c_flags, request,
330 stkt->enc_part2, local_tgt,
331 &local_tgt_key, stkt_server,
332 stkt_server_key,
333 header_ticket->enc_part2->client,
334 server, request->server, ad_info,
335 &stkt_ad_info,
336 &stkt_authdata_client,
337 &status);
338 if (errcode == KDC_ERR_POLICY || errcode == KDC_ERR_BADOPTION)
339 au_state->violation = PROT_CONSTRAINT;
340 else if (errcode)
341 au_state->violation = LOCAL_POLICY;
342 au_state->status = status;
343 retval = kau_make_tkt_id(kdc_context, stkt, &au_state->evid_tkt_id);
344 if (retval) {
345 errcode = retval;
346 goto cleanup;
347 }
348 kau_s4u2proxy(kdc_context, errcode ? FALSE : TRUE, au_state);
349 if (errcode)
350 goto cleanup;
351
352 assert(krb5_is_tgs_principal(header_ticket->server));
353
354 /* Use the parsed authdata from the second ticket during authdata
355 * handling. */
356 krb5_db_free_authdata_info(kdc_context, ad_info);
357 ad_info = stkt_ad_info;
358 stkt_ad_info = NULL;
359 }
360
361 au_state->stage = ISSUE_TKT;
362
363 errcode = gen_session_key(kdc_active_realm, request, server, &session_key,
364 &status);
365 if (errcode)
366 goto cleanup;
367
368 /*
369 * subject_tkt will refer to the evidence ticket (for constrained
370 * delegation) or the TGT. The distinction from header_enc_tkt is
371 * necessary because the TGS signature only protects some fields:
372 * the others could be forged by a malicious server.
373 */
374
375 if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
376 subject_tkt = stkt->enc_part2;
377 subject_server = stkt_server;
378 subject_key = stkt_server_key;
379 } else {
380 subject_tkt = header_enc_tkt;
381 subject_server = header_server;
382 subject_key = header_key;
383 }
384 authtime = subject_tkt->times.authtime;
385
386 /* Extract and check auth indicators from the subject ticket, except for
387 * S4U2Self requests (where the client didn't authenticate). */
388 if (s4u_x509_user == NULL) {
389 errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
390 &local_tgt_key, &auth_indicators);
391 if (errcode) {
392 status = "GET_AUTH_INDICATORS";
393 goto cleanup;
394 }
395
396 errcode = check_indicators(kdc_context, server, auth_indicators);
397 if (errcode) {
398 status = "HIGHER_AUTHENTICATION_REQUIRED";
399 goto cleanup;
400 }
401 }
402
403 if (is_referral)
404 ticket_reply.server = server->princ;
405 else
406 ticket_reply.server = request->server; /* XXX careful for realm... */
407
408 enc_tkt_reply.flags = get_ticket_flags(request->kdc_options, client,
409 server, header_enc_tkt);
410 enc_tkt_reply.times.starttime = 0;
411
412 /* OK_TO_AUTH_AS_DELEGATE must be set on the service requesting S4U2Self
413 * for forwardable tickets to be issued. */
414 if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
415 !is_referral &&
416 !isflagset(server->attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
417 clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
418
419 /* don't use new addresses unless forwarded, see below */
420
421 enc_tkt_reply.caddrs = header_enc_tkt->caddrs;
422 /* noaddrarray[0] = 0; */
423 reply_encpart.caddrs = 0;/* optional...don't put it in */
424 reply_encpart.enc_padata = NULL;
425
426 /*
427 * It should be noted that local policy may affect the
428 * processing of any of these flags. For example, some
429 * realms may refuse to issue renewable tickets
430 */
431
432 if (isflagset(request->kdc_options, KDC_OPT_FORWARDED) ||
433 isflagset(request->kdc_options, KDC_OPT_PROXY)) {
434
435 /* include new addresses in ticket & reply */
436
437 enc_tkt_reply.caddrs = request->addresses;
438 reply_encpart.caddrs = request->addresses;
439 }
440
441 if (isflagset(request->kdc_options, KDC_OPT_POSTDATED))
442 enc_tkt_reply.times.starttime = request->from;
443 else
444 enc_tkt_reply.times.starttime = kdc_time;
445
446 if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
447 assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
448 /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
449 to the caller */
450 ticket_reply = *(header_ticket);
451 enc_tkt_reply = *(header_ticket->enc_part2);
452 enc_tkt_reply.authorization_data = NULL;
453 clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
454 }
455
456 if (isflagset(request->kdc_options, KDC_OPT_RENEW)) {
457 krb5_timestamp old_starttime;
458 krb5_deltat old_life;
459
460 assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
461 /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
462 to the caller */
463 ticket_reply = *(header_ticket);
464 enc_tkt_reply = *(header_ticket->enc_part2);
465 enc_tkt_reply.authorization_data = NULL;
466
467 old_starttime = enc_tkt_reply.times.starttime ?
468 enc_tkt_reply.times.starttime : enc_tkt_reply.times.authtime;
469 old_life = ts_delta(enc_tkt_reply.times.endtime, old_starttime);
470
471 enc_tkt_reply.times.starttime = kdc_time;
472 enc_tkt_reply.times.endtime =
473 ts_min(header_ticket->enc_part2->times.renew_till,
474 ts_incr(kdc_time, old_life));
475 } else {
476 /* not a renew request */
477 enc_tkt_reply.times.starttime = kdc_time;
478
479 kdc_get_ticket_endtime(kdc_active_realm, enc_tkt_reply.times.starttime,
480 header_enc_tkt->times.endtime, request->till,
481 client, server, &enc_tkt_reply.times.endtime);
482 }
483
484 kdc_get_ticket_renewtime(kdc_active_realm, request, header_enc_tkt, client,
485 server, &enc_tkt_reply);
486
487 errcode = check_kdcpolicy_tgs(kdc_context, request, server, header_ticket,
488 auth_indicators, kdc_time,
489 &enc_tkt_reply.times, &status);
490 if (errcode)
491 goto cleanup;
492
493 /*
494 * Set authtime to be the same as header or evidence ticket's
495 */
496 enc_tkt_reply.times.authtime = authtime;
497
498 /* starttime is optional, and treated as authtime if not present.
499 so we can nuke it if it matches */
500 if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
501 enc_tkt_reply.times.starttime = 0;
502
503 if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
504 altcprinc = s4u_x509_user->user_id.user;
505 } else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
506 /* kdc_process_s4u2proxy_req() only allows cross-realm requests if
507 * stkt_authdata_client is set. */
508 altcprinc = is_crossrealm ? stkt_authdata_client : subject_tkt->client;
509 } else {
510 altcprinc = NULL;
511 }
512 if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
513 encrypting_key = stkt->enc_part2->session;
514 } else {
515 errcode = get_first_current_key(kdc_context, server, &server_keyblock);
516 if (errcode) {
517 status = "FINDING_SERVER_KEY";
518 goto cleanup;
519 }
520 encrypting_key = &server_keyblock;
521 }
522
523 if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
524 /*
525 * Don't allow authorization data to be disabled if constrained
526 * delegation is requested. We don't want to deny the server
527 * the ability to validate that delegation was used.
528 */
529 clear(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED);
530 }
531 if (isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) == 0) {
532 /* If we are not doing protocol transition, try to look up the subject
533 * principal so that KDB modules can add additional authdata. */
534 if (!isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
535 /* Generate authorization data so we can include it in ticket */
536 setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
537 /* Map principals from foreign (possibly non-AD) realms */
538 setflag(c_flags, KRB5_KDB_FLAG_MAP_PRINCIPALS);
539
540 assert(client == NULL); /* should not have been set already */
541
542 errcode = krb5_db_get_principal(kdc_context, subject_tkt->client,
543 c_flags, &client);
544 }
545 }
546
547 if (isflagset(c_flags, KRB5_KDB_FLAGS_S4U) && !is_referral)
548 enc_tkt_reply.client = altcprinc;
549 else
550 enc_tkt_reply.client = header_enc_tkt->client;
551
552 enc_tkt_reply.session = &session_key;
553 enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
554 enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
555
556 /*
557 * Only add the realm of the presented tgt to the transited list if
558 * it is different than the server realm (cross-realm) and it is different
559 * than the realm of the client (since the realm of the client is already
560 * implicitly part of the transited list and should not be explicitly
561 * listed).
562 */
563 if (!is_crossrealm ||
564 krb5_realm_compare(kdc_context, header_ticket->server,
565 enc_tkt_reply.client)) {
566 /* tgt issued by local realm or issued by realm of client */
567 enc_tkt_reply.transited = header_enc_tkt->transited;
568 } else {
569 /* tgt issued by some other realm and not the realm of the client */
570 /* assemble new transited field into allocated storage */
571 if (header_enc_tkt->transited.tr_type !=
572 KRB5_DOMAIN_X500_COMPRESS) {
573 status = "VALIDATE_TRANSIT_TYPE";
574 errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
575 goto cleanup;
576 }
577 memset(&enc_tkt_reply.transited, 0, sizeof(enc_tkt_reply.transited));
578 enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
579 if ((errcode =
580 add_to_transited(&header_enc_tkt->transited.tr_contents,
581 &enc_tkt_reply.transited.tr_contents,
582 header_ticket->server,
583 enc_tkt_reply.client,
584 request->server))) {
585 status = "ADD_TO_TRANSITED_LIST";
586 goto cleanup;
587 }
588 newtransited = 1;
589 }
590 if (!isflagset (request->kdc_options, KDC_OPT_DISABLE_TRANSITED_CHECK)) {
591 errcode = kdc_check_transited_list (kdc_active_realm,
592 &enc_tkt_reply.transited.tr_contents,
593 krb5_princ_realm (kdc_context, header_enc_tkt->client),
594 krb5_princ_realm (kdc_context, request->server));
595 if (errcode == 0) {
596 setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
597 } else {
598 log_tgs_badtrans(kdc_context, cprinc, sprinc,
599 &enc_tkt_reply.transited.tr_contents, errcode);
600 }
601 } else
602 krb5_klog_syslog(LOG_INFO, _("not checking transit path"));
603 if (kdc_active_realm->realm_reject_bad_transit &&
604 !isflagset(enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
605 errcode = KRB5KDC_ERR_POLICY;
606 status = "BAD_TRANSIT";
607 au_state->violation = LOCAL_POLICY;
608 goto cleanup;
609 }
610
611 errcode = handle_authdata(kdc_context, c_flags, client, server,
612 subject_server, local_tgt, &local_tgt_key,
613 subkey != NULL ? subkey :
614 header_ticket->enc_part2->session,
615 encrypting_key, subject_key, pkt, request,
616 altcprinc, ad_info, subject_tkt,
617 &auth_indicators, &enc_tkt_reply);
618 if (errcode) {
619 krb5_klog_syslog(LOG_INFO, _("TGS_REQ : handle_authdata (%d)"),
620 errcode);
621 status = "HANDLE_AUTHDATA";
622 goto cleanup;
623 }
624
625 ticket_reply.enc_part2 = &enc_tkt_reply;
626
627 /* If we are doing user-to-user authentication, encrypt the ticket using
628 * the session key of the second ticket. */
629 if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
630 ticket_kvno = 0;
631 ticket_reply.enc_part.enctype = stkt->enc_part2->session->enctype;
632 kau_u2u(kdc_context, TRUE, au_state);
633 } else {
634 ticket_kvno = current_kvno(server);
635 }
636
637 errcode = krb5_encrypt_tkt_part(kdc_context, encrypting_key,
638 &ticket_reply);
639 if (errcode)
640 goto cleanup;
641 ticket_reply.enc_part.kvno = ticket_kvno;
642 /* Start assembling the response */
643 au_state->stage = ENCR_REP;
644 reply.msg_type = KRB5_TGS_REP;
645 if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
646 krb5int_find_pa_data(kdc_context, request->padata,
647 KRB5_PADATA_S4U_X509_USER) != NULL) {
648 errcode = kdc_make_s4u2self_rep(kdc_context,
649 subkey,
650 header_ticket->enc_part2->session,
651 s4u_x509_user,
652 &reply,
653 &reply_encpart);
654 if (errcode)
655 au_state->status = status;
656 kau_s4u2self(kdc_context, errcode ? FALSE : TRUE, au_state);
657 if (errcode)
658 goto cleanup;
659 }
660
661 reply.client = enc_tkt_reply.client;
662 reply.enc_part.kvno = 0;/* We are using the session key */
663 reply.ticket = &ticket_reply;
664
665 reply_encpart.session = &session_key;
666 reply_encpart.nonce = request->nonce;
667
668 /* copy the time fields */
669 reply_encpart.times = enc_tkt_reply.times;
670
671 nolrentry.lr_type = KRB5_LRQ_NONE;
672 nolrentry.value = 0;
673 nolrentry.magic = 0;
674 nolrarray[0] = &nolrentry;
675 nolrarray[1] = 0;
676 reply_encpart.last_req = nolrarray; /* not available for TGS reqs */
677 reply_encpart.key_exp = 0;/* ditto */
678 reply_encpart.flags = enc_tkt_reply.flags;
679 reply_encpart.server = ticket_reply.server;
680
681 /* use the session key in the ticket, unless there's a subsession key
682 in the AP_REQ */
683 reply.enc_part.enctype = subkey ? subkey->enctype :
684 header_ticket->enc_part2->session->enctype;
685 errcode = kdc_fast_response_handle_padata(state, request, &reply,
686 subkey ? subkey->enctype : header_ticket->enc_part2->session->enctype);
687 if (errcode)
688 goto cleanup;
689 errcode =kdc_fast_handle_reply_key(state,
690 subkey?subkey:header_ticket->enc_part2->session, &reply_key);
691 if (errcode)
692 goto cleanup;
693 errcode = return_enc_padata(kdc_context, pkt, request,
694 reply_key, server, &reply_encpart,
695 is_referral &&
696 isflagset(s_flags,
697 KRB5_KDB_FLAG_CANONICALIZE));
698 if (errcode) {
699 status = "KDC_RETURN_ENC_PADATA";
700 goto cleanup;
701 }
702
703 errcode = kau_make_tkt_id(kdc_context, &ticket_reply, &au_state->tkt_out_id);
704 if (errcode)
705 goto cleanup;
706
707 if (kdc_fast_hide_client(state))
708 reply.client = (krb5_principal)krb5_anonymous_principal();
709 errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart,
710 subkey ? 1 : 0,
711 reply_key,
712 &reply, response);
713 if (!errcode)
714 status = "ISSUE";
715
716 memset(ticket_reply.enc_part.ciphertext.data, 0,
717 ticket_reply.enc_part.ciphertext.length);
718 free(ticket_reply.enc_part.ciphertext.data);
719 /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
720 can use them in raw form if needed. But, we don't... */
721 memset(reply.enc_part.ciphertext.data, 0,
722 reply.enc_part.ciphertext.length);
723 free(reply.enc_part.ciphertext.data);
724
725 cleanup:
726 if (status == NULL)
727 status = "UNKNOWN_REASON";
728 krb5_free_keyblock_contents(kdc_context, &server_keyblock);
729 if (reply_key)
730 krb5_free_keyblock(kdc_context, reply_key);
731 if (stkt_server_key)
732 krb5_free_keyblock(kdc_context, stkt_server_key);
733 if (errcode)
734 emsg = krb5_get_error_message (kdc_context, errcode);
735
736 au_state->status = status;
737 if (!errcode)
738 au_state->reply = &reply;
739 kau_tgs_req(kdc_context, errcode ? FALSE : TRUE, au_state);
740 kau_free_kdc_req(au_state);
741
742 log_tgs_req(kdc_context, from, request, &reply, cprinc,
743 sprinc, altcprinc, authtime,
744 c_flags, status, errcode, emsg);
745 if (errcode) {
746 krb5_free_error_message (kdc_context, emsg);
747 emsg = NULL;
748 }
749
750 if (errcode) {
751 int got_err = 0;
752 if (status == 0) {
753 status = krb5_get_error_message (kdc_context, errcode);
754 got_err = 1;
755 }
756 errcode -= ERROR_TABLE_BASE_krb5;
757 if (errcode < 0 || errcode > KRB_ERR_MAX)
758 errcode = KRB_ERR_GENERIC;
759
760 retval = prepare_error_tgs(state, request, header_ticket, errcode,
761 (server != NULL) ? server->princ : NULL,
762 response, status, e_data);
763 if (got_err) {
764 krb5_free_error_message (kdc_context, status);
765 status = 0;
766 }
767 }
768
769 if (header_ticket != NULL)
770 krb5_free_ticket(kdc_context, header_ticket);
771 if (request != NULL)
772 krb5_free_kdc_req(kdc_context, request);
773 if (state)
774 kdc_free_rstate(state);
775 krb5_db_free_principal(kdc_context, server);
776 krb5_db_free_principal(kdc_context, stkt_server);
777 krb5_db_free_principal(kdc_context, header_server);
778 krb5_db_free_principal(kdc_context, client);
779 krb5_db_free_principal(kdc_context, local_tgt_storage);
780 if (local_tgt_key.contents != NULL)
781 krb5_free_keyblock_contents(kdc_context, &local_tgt_key);
782 if (session_key.contents != NULL)
783 krb5_free_keyblock_contents(kdc_context, &session_key);
784 if (newtransited)
785 free(enc_tkt_reply.transited.tr_contents.data);
786 if (s4u_x509_user != NULL)
787 krb5_free_pa_s4u_x509_user(kdc_context, s4u_x509_user);
788 if (kdc_issued_auth_data != NULL)
789 krb5_free_authdata(kdc_context, kdc_issued_auth_data);
790 if (subkey != NULL)
791 krb5_free_keyblock(kdc_context, subkey);
792 if (header_key != NULL)
793 krb5_free_keyblock(kdc_context, header_key);
794 if (reply.padata)
795 krb5_free_pa_data(kdc_context, reply.padata);
796 if (reply_encpart.enc_padata)
797 krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);
798 if (enc_tkt_reply.authorization_data != NULL)
799 krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
800 krb5_free_pa_data(kdc_context, e_data);
801 k5_free_data_ptr_list(auth_indicators);
802 krb5_db_free_authdata_info(kdc_context, ad_info);
803 krb5_db_free_authdata_info(kdc_context, stkt_ad_info);
804 krb5_free_principal(kdc_context, stkt_authdata_client);
805
806 return retval;
807 }
808
809 static krb5_error_code
prepare_error_tgs(struct kdc_request_state * state,krb5_kdc_req * request,krb5_ticket * ticket,int error,krb5_principal canon_server,krb5_data ** response,const char * status,krb5_pa_data ** e_data)810 prepare_error_tgs (struct kdc_request_state *state,
811 krb5_kdc_req *request, krb5_ticket *ticket, int error,
812 krb5_principal canon_server,
813 krb5_data **response, const char *status,
814 krb5_pa_data **e_data)
815 {
816 krb5_error errpkt;
817 krb5_error_code retval = 0;
818 krb5_data *scratch, *e_data_asn1 = NULL, *fast_edata = NULL;
819 kdc_realm_t *kdc_active_realm = state->realm_data;
820
821 errpkt.magic = KV5M_ERROR;
822 errpkt.ctime = 0;
823 errpkt.cusec = 0;
824
825 if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime,
826 &errpkt.susec)))
827 return(retval);
828 errpkt.error = error;
829 errpkt.server = request->server;
830 if (ticket && ticket->enc_part2)
831 errpkt.client = ticket->enc_part2->client;
832 else
833 errpkt.client = NULL;
834 errpkt.text.length = strlen(status);
835 if (!(errpkt.text.data = strdup(status)))
836 return ENOMEM;
837
838 if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) {
839 free(errpkt.text.data);
840 return ENOMEM;
841 }
842
843 if (e_data != NULL) {
844 retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
845 if (retval) {
846 free(scratch);
847 free(errpkt.text.data);
848 return retval;
849 }
850 errpkt.e_data = *e_data_asn1;
851 } else
852 errpkt.e_data = empty_data();
853
854 retval = kdc_fast_handle_error(kdc_context, state, request, e_data,
855 &errpkt, &fast_edata);
856 if (retval) {
857 free(scratch);
858 free(errpkt.text.data);
859 krb5_free_data(kdc_context, e_data_asn1);
860 return retval;
861 }
862 if (fast_edata)
863 errpkt.e_data = *fast_edata;
864 if (kdc_fast_hide_client(state) && errpkt.client != NULL)
865 errpkt.client = (krb5_principal)krb5_anonymous_principal();
866 retval = krb5_mk_error(kdc_context, &errpkt, scratch);
867 free(errpkt.text.data);
868 krb5_free_data(kdc_context, e_data_asn1);
869 krb5_free_data(kdc_context, fast_edata);
870 if (retval)
871 free(scratch);
872 else
873 *response = scratch;
874
875 return retval;
876 }
877
878 /* KDC options that require a second ticket */
879 #define STKT_OPTIONS (KDC_OPT_CNAME_IN_ADDL_TKT | KDC_OPT_ENC_TKT_IN_SKEY)
880 /*
881 * If req is a second-ticket request and a second ticket is present, decrypt
882 * it. Set *stkt_out to an alias to the ticket with populated enc_part2. Set
883 * *server_out to the server DB entry and *key_out to the ticket decryption
884 * key.
885 */
886 static krb5_error_code
decrypt_2ndtkt(kdc_realm_t * kdc_active_realm,krb5_kdc_req * req,krb5_flags flags,const krb5_ticket ** stkt_out,krb5_db_entry ** server_out,krb5_keyblock ** key_out,const char ** status)887 decrypt_2ndtkt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
888 krb5_flags flags, const krb5_ticket **stkt_out,
889 krb5_db_entry **server_out, krb5_keyblock **key_out,
890 const char **status)
891 {
892 krb5_error_code retval;
893 krb5_db_entry *server = NULL;
894 krb5_keyblock *key = NULL;
895 krb5_kvno kvno;
896 krb5_ticket *stkt;
897
898 *stkt_out = NULL;
899 *server_out = NULL;
900 *key_out = NULL;
901
902 if (!(req->kdc_options & STKT_OPTIONS) || req->second_ticket == NULL ||
903 req->second_ticket[0] == NULL)
904 return 0;
905
906 stkt = req->second_ticket[0];
907 retval = kdc_get_server_key(kdc_context, stkt, flags, TRUE,
908 &server, &key, &kvno);
909 if (retval != 0) {
910 *status = "2ND_TKT_SERVER";
911 goto cleanup;
912 }
913 retval = krb5_decrypt_tkt_part(kdc_context, key, stkt);
914 if (retval != 0) {
915 *status = "2ND_TKT_DECRYPT";
916 goto cleanup;
917 }
918 *stkt_out = stkt;
919 *server_out = server;
920 *key_out = key;
921 server = NULL;
922 key = NULL;
923
924 cleanup:
925 krb5_db_free_principal(kdc_context, server);
926 krb5_free_keyblock(kdc_context, key);
927 return retval;
928 }
929
930 static krb5_error_code
get_2ndtkt_enctype(kdc_realm_t * kdc_active_realm,krb5_kdc_req * req,krb5_enctype * useenctype,const char ** status)931 get_2ndtkt_enctype(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
932 krb5_enctype *useenctype, const char **status)
933 {
934 krb5_enctype etype;
935 krb5_ticket *stkt = req->second_ticket[0];
936 int i;
937
938 etype = stkt->enc_part2->session->enctype;
939 if (!krb5_c_valid_enctype(etype)) {
940 *status = "BAD_ETYPE_IN_2ND_TKT";
941 return KRB5KDC_ERR_ETYPE_NOSUPP;
942 }
943 for (i = 0; i < req->nktypes; i++) {
944 if (req->ktype[i] == etype) {
945 *useenctype = etype;
946 break;
947 }
948 }
949 return 0;
950 }
951
952 static krb5_error_code
gen_session_key(kdc_realm_t * kdc_active_realm,krb5_kdc_req * req,krb5_db_entry * server,krb5_keyblock * skey,const char ** status)953 gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
954 krb5_db_entry *server, krb5_keyblock *skey,
955 const char **status)
956 {
957 krb5_error_code retval;
958 krb5_enctype useenctype = 0;
959
960 /*
961 * Some special care needs to be taken in the user-to-user
962 * case, since we don't know what keytypes the application server
963 * which is doing user-to-user authentication can support. We
964 * know that it at least must be able to support the encryption
965 * type of the session key in the TGT, since otherwise it won't be
966 * able to decrypt the U2U ticket! So we use that in preference
967 * to anything else.
968 */
969 if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
970 retval = get_2ndtkt_enctype(kdc_active_realm, req, &useenctype,
971 status);
972 if (retval != 0)
973 return retval;
974 }
975 if (useenctype == 0) {
976 useenctype = select_session_keytype(kdc_active_realm, server,
977 req->nktypes,
978 req->ktype);
979 }
980 if (useenctype == 0) {
981 /* unsupported ktype */
982 *status = "BAD_ENCRYPTION_TYPE";
983 return KRB5KDC_ERR_ETYPE_NOSUPP;
984 }
985
986 return krb5_c_make_random_key(kdc_context, useenctype, skey);
987 }
988
989 /*
990 * The request seems to be for a ticket-granting service somewhere else,
991 * but we don't have a ticket for the final TGS. Try to give the requestor
992 * some intermediate realm.
993 */
994 static krb5_error_code
find_alternate_tgs(kdc_realm_t * kdc_active_realm,krb5_principal princ,krb5_db_entry ** server_ptr,const char ** status)995 find_alternate_tgs(kdc_realm_t *kdc_active_realm, krb5_principal princ,
996 krb5_db_entry **server_ptr, const char **status)
997 {
998 krb5_error_code retval;
999 krb5_principal *plist = NULL, *pl2;
1000 krb5_data tmp;
1001 krb5_db_entry *server = NULL;
1002
1003 *server_ptr = NULL;
1004 assert(is_cross_tgs_principal(princ));
1005 if ((retval = krb5_walk_realm_tree(kdc_context,
1006 krb5_princ_realm(kdc_context, princ),
1007 krb5_princ_component(kdc_context, princ, 1),
1008 &plist, KRB5_REALM_BRANCH_CHAR))) {
1009 goto cleanup;
1010 }
1011 /* move to the end */
1012 for (pl2 = plist; *pl2; pl2++);
1013
1014 /* the first entry in this array is for krbtgt/local@local, so we
1015 ignore it */
1016 while (--pl2 > plist) {
1017 tmp = *krb5_princ_realm(kdc_context, *pl2);
1018 krb5_princ_set_realm(kdc_context, *pl2,
1019 krb5_princ_realm(kdc_context, princ));
1020 retval = db_get_svc_princ(kdc_context, *pl2, 0, &server, status);
1021 krb5_princ_set_realm(kdc_context, *pl2, &tmp);
1022 if (retval == KRB5_KDB_NOENTRY)
1023 continue;
1024 else if (retval)
1025 goto cleanup;
1026
1027 log_tgs_alt_tgt(kdc_context, server->princ);
1028 *server_ptr = server;
1029 server = NULL;
1030 goto cleanup;
1031 }
1032 cleanup:
1033 if (retval == 0 && *server_ptr == NULL)
1034 retval = KRB5_KDB_NOENTRY;
1035 if (retval != 0)
1036 *status = "UNKNOWN_SERVER";
1037
1038 krb5_free_realm_tree(kdc_context, plist);
1039 krb5_db_free_principal(kdc_context, server);
1040 return retval;
1041 }
1042
1043 /* Return true if item is an element of the space/comma-separated list. */
1044 static krb5_boolean
in_list(const char * list,const char * item)1045 in_list(const char *list, const char *item)
1046 {
1047 const char *p;
1048 int len = strlen(item);
1049
1050 if (list == NULL)
1051 return FALSE;
1052 for (p = strstr(list, item); p != NULL; p = strstr(p + 1, item)) {
1053 if ((p == list || isspace((unsigned char)p[-1]) || p[-1] == ',') &&
1054 (p[len] == '\0' || isspace((unsigned char)p[len]) ||
1055 p[len] == ','))
1056 return TRUE;
1057 }
1058 return FALSE;
1059 }
1060
1061 /*
1062 * Check whether the request satisfies the conditions for generating a referral
1063 * TGT. The caller checks whether the hostname component looks like a FQDN.
1064 */
1065 static krb5_boolean
is_referral_req(kdc_realm_t * kdc_active_realm,krb5_kdc_req * request)1066 is_referral_req(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request)
1067 {
1068 krb5_boolean ret = FALSE;
1069 char *stype = NULL;
1070 char *hostbased = kdc_active_realm->realm_hostbased;
1071 char *no_referral = kdc_active_realm->realm_no_referral;
1072
1073 if (!(request->kdc_options & KDC_OPT_CANONICALIZE))
1074 return FALSE;
1075
1076 if (request->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY)
1077 return FALSE;
1078
1079 if (krb5_princ_size(kdc_context, request->server) != 2)
1080 return FALSE;
1081
1082 stype = data2string(krb5_princ_component(kdc_context, request->server, 0));
1083 if (stype == NULL)
1084 return FALSE;
1085 switch (krb5_princ_type(kdc_context, request->server)) {
1086 case KRB5_NT_UNKNOWN:
1087 /* Allow referrals for NT-UNKNOWN principals, if configured. */
1088 if (!in_list(hostbased, stype) && !in_list(hostbased, "*"))
1089 goto cleanup;
1090 /* FALLTHROUGH */
1091 case KRB5_NT_SRV_HST:
1092 case KRB5_NT_SRV_INST:
1093 /* Deny referrals for specific service types, if configured. */
1094 if (in_list(no_referral, stype) || in_list(no_referral, "*"))
1095 goto cleanup;
1096 ret = TRUE;
1097 break;
1098 default:
1099 goto cleanup;
1100 }
1101 cleanup:
1102 free(stype);
1103 return ret;
1104 }
1105
1106 /*
1107 * Find a remote realm TGS principal for an unknown host-based service
1108 * principal.
1109 */
1110 static krb5_int32
find_referral_tgs(kdc_realm_t * kdc_active_realm,krb5_kdc_req * request,krb5_principal * krbtgt_princ)1111 find_referral_tgs(kdc_realm_t *kdc_active_realm, krb5_kdc_req *request,
1112 krb5_principal *krbtgt_princ)
1113 {
1114 krb5_error_code retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1115 char **realms = NULL, *hostname = NULL;
1116 krb5_data srealm = request->server->realm;
1117
1118 if (!is_referral_req(kdc_active_realm, request))
1119 goto cleanup;
1120
1121 hostname = data2string(krb5_princ_component(kdc_context,
1122 request->server, 1));
1123 if (hostname == NULL) {
1124 retval = ENOMEM;
1125 goto cleanup;
1126 }
1127 /* If the hostname doesn't contain a '.', it's not a FQDN. */
1128 if (strchr(hostname, '.') == NULL)
1129 goto cleanup;
1130 retval = krb5_get_host_realm(kdc_context, hostname, &realms);
1131 if (retval) {
1132 /* no match found */
1133 kdc_err(kdc_context, retval, "unable to find realm of host");
1134 goto cleanup;
1135 }
1136 /* Don't return a referral to the empty realm or the service realm. */
1137 if (realms == NULL || realms[0] == NULL || *realms[0] == '\0' ||
1138 data_eq_string(srealm, realms[0])) {
1139 retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1140 goto cleanup;
1141 }
1142 retval = krb5_build_principal(kdc_context, krbtgt_princ,
1143 srealm.length, srealm.data,
1144 "krbtgt", realms[0], (char *)0);
1145 cleanup:
1146 krb5_free_host_realm(kdc_context, realms);
1147 free(hostname);
1148
1149 return retval;
1150 }
1151
1152 static krb5_error_code
db_get_svc_princ(krb5_context ctx,krb5_principal princ,krb5_flags flags,krb5_db_entry ** server,const char ** status)1153 db_get_svc_princ(krb5_context ctx, krb5_principal princ,
1154 krb5_flags flags, krb5_db_entry **server,
1155 const char **status)
1156 {
1157 krb5_error_code ret;
1158
1159 ret = krb5_db_get_principal(ctx, princ, flags, server);
1160 if (ret == KRB5_KDB_CANTLOCK_DB)
1161 ret = KRB5KDC_ERR_SVC_UNAVAILABLE;
1162 if (ret != 0) {
1163 *status = "LOOKING_UP_SERVER";
1164 }
1165 return ret;
1166 }
1167
1168 static krb5_error_code
search_sprinc(kdc_realm_t * kdc_active_realm,krb5_kdc_req * req,krb5_flags flags,krb5_db_entry ** server,const char ** status)1169 search_sprinc(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
1170 krb5_flags flags, krb5_db_entry **server, const char **status)
1171 {
1172 krb5_error_code ret;
1173 krb5_principal princ = req->server;
1174 krb5_principal reftgs = NULL;
1175 krb5_boolean allow_referral;
1176
1177 /* Do not allow referrals for u2u or ticket modification requests, because
1178 * the server is supposed to match an already-issued ticket. */
1179 allow_referral = !(req->kdc_options & NO_REFERRAL_OPTION);
1180 if (!allow_referral)
1181 flags &= ~KRB5_KDB_FLAG_CANONICALIZE;
1182
1183 ret = db_get_svc_princ(kdc_context, princ, flags, server, status);
1184 if (ret == 0 || ret != KRB5_KDB_NOENTRY || !allow_referral)
1185 goto cleanup;
1186
1187 if (!is_cross_tgs_principal(req->server)) {
1188 ret = find_referral_tgs(kdc_active_realm, req, &reftgs);
1189 if (ret != 0)
1190 goto cleanup;
1191 ret = db_get_svc_princ(kdc_context, reftgs, flags, server, status);
1192 if (ret == 0 || ret != KRB5_KDB_NOENTRY)
1193 goto cleanup;
1194
1195 princ = reftgs;
1196 }
1197 ret = find_alternate_tgs(kdc_active_realm, princ, server, status);
1198
1199 cleanup:
1200 if (ret != 0 && ret != KRB5KDC_ERR_SVC_UNAVAILABLE) {
1201 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1202 if (*status == NULL)
1203 *status = "LOOKING_UP_SERVER";
1204 }
1205 krb5_free_principal(kdc_context, reftgs);
1206 return ret;
1207 }
1208