This commit was manufactured by cvs2svn to create tag
[heimdal.git] / kdc / kerberos5.c
blob4a475b4c74999cf1920288eaaf6d4ab0d265371a
1 /*
2 * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "kdc_locl.h"
36 RCSID("$Id$");
38 #define MAX_TIME ((time_t)((1U << 31) - 1))
40 static void
41 fix_time(time_t **t)
43 if(*t == NULL){
44 ALLOC(*t);
45 **t = MAX_TIME;
47 if(**t == 0) **t = MAX_TIME; /* fix for old clients */
50 static void
51 set_salt_padata (METHOD_DATA **m, Salt *salt)
53 if (salt) {
54 ALLOC(*m);
55 (*m)->len = 1;
56 ALLOC((*m)->val);
57 (*m)->val->padata_type = salt->type;
58 copy_octet_string(&salt->salt,
59 &(*m)->val->padata_value);
63 static PA_DATA*
64 find_padata(KDC_REQ *req, int *start, int type)
66 while(*start < req->padata->len){
67 (*start)++;
68 if(req->padata->val[*start - 1].padata_type == type)
69 return &req->padata->val[*start - 1];
71 return NULL;
75 * return the first appropriate key of `princ' in `ret_key'. Look for
76 * all the etypes in (`etypes', `len'), stopping as soon as we find
77 * one, but preferring one that has default salt
80 static krb5_error_code
81 find_etype(hdb_entry *princ, krb5_enctype *etypes, unsigned len,
82 Key **ret_key, krb5_enctype *ret_etype)
84 int i;
85 krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
87 for(i = 0; ret != 0 && i < len ; i++) {
88 Key *key = NULL;
90 while (hdb_next_enctype2key(context, princ, etypes[i], &key) == 0) {
91 if (key->key.keyvalue.length == 0) {
92 ret = KRB5KDC_ERR_NULL_KEY;
93 continue;
95 *ret_key = key;
96 *ret_etype = etypes[i];
97 ret = 0;
98 if (key->salt == NULL)
99 return ret;
102 return ret;
105 static krb5_error_code
106 find_keys(hdb_entry *client,
107 hdb_entry *server,
108 Key **ckey,
109 krb5_enctype *cetype,
110 Key **skey,
111 krb5_enctype *setype,
112 krb5_enctype *etypes,
113 unsigned num_etypes)
115 krb5_error_code ret;
117 if(client){
118 /* find client key */
119 ret = find_etype(client, etypes, num_etypes, ckey, cetype);
120 if (ret) {
121 kdc_log(0, "Client has no support for etypes");
122 return ret;
126 if(server){
127 /* find server key */
128 ret = find_etype(server, etypes, num_etypes, skey, setype);
129 if (ret) {
130 kdc_log(0, "Server has no support for etypes");
131 return ret;
134 return 0;
137 static krb5_error_code
138 make_anonymous_principalname (PrincipalName *pn)
140 pn->name_type = KRB5_NT_PRINCIPAL;
141 pn->name_string.len = 1;
142 pn->name_string.val = malloc(sizeof(*pn->name_string.val));
143 if (pn->name_string.val == NULL)
144 return ENOMEM;
145 pn->name_string.val[0] = strdup("anonymous");
146 if (pn->name_string.val[0] == NULL) {
147 free(pn->name_string.val);
148 pn->name_string.val = NULL;
149 return ENOMEM;
151 return 0;
154 static krb5_error_code
155 encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek,
156 krb5_enctype etype,
157 int skvno, EncryptionKey *skey,
158 int ckvno, EncryptionKey *ckey,
159 const char **e_text,
160 krb5_data *reply)
162 unsigned char *buf;
163 size_t buf_size;
164 size_t len;
165 krb5_error_code ret;
166 krb5_crypto crypto;
168 ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret);
169 if(ret) {
170 kdc_log(0, "Failed to encode ticket: %s",
171 krb5_get_err_text(context, ret));
172 return ret;
174 if(buf_size != len) {
175 free(buf);
176 kdc_log(0, "Internal error in ASN.1 encoder");
177 *e_text = "KDC internal error";
178 return KRB5KRB_ERR_GENERIC;
181 ret = krb5_crypto_init(context, skey, etype, &crypto);
182 if (ret) {
183 free(buf);
184 kdc_log(0, "krb5_crypto_init failed: %s",
185 krb5_get_err_text(context, ret));
186 return ret;
189 ret = krb5_encrypt_EncryptedData(context,
190 crypto,
191 KRB5_KU_TICKET,
192 buf,
193 len,
194 skvno,
195 &rep->ticket.enc_part);
196 free(buf);
197 krb5_crypto_destroy(context, crypto);
198 if(ret) {
199 kdc_log(0, "Failed to encrypt data: %s",
200 krb5_get_err_text(context, ret));
201 return ret;
204 if(rep->msg_type == krb_as_rep && !encode_as_rep_as_tgs_rep)
205 ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret);
206 else
207 ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret);
208 if(ret) {
209 kdc_log(0, "Failed to encode KDC-REP: %s",
210 krb5_get_err_text(context, ret));
211 return ret;
213 if(buf_size != len) {
214 free(buf);
215 kdc_log(0, "Internal error in ASN.1 encoder");
216 *e_text = "KDC internal error";
217 return KRB5KRB_ERR_GENERIC;
219 ret = krb5_crypto_init(context, ckey, 0, &crypto);
220 if (ret) {
221 free(buf);
222 kdc_log(0, "krb5_crypto_init failed: %s",
223 krb5_get_err_text(context, ret));
224 return ret;
226 if(rep->msg_type == krb_as_rep) {
227 krb5_encrypt_EncryptedData(context,
228 crypto,
229 KRB5_KU_AS_REP_ENC_PART,
230 buf,
231 len,
232 ckvno,
233 &rep->enc_part);
234 free(buf);
235 ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret);
236 } else {
237 krb5_encrypt_EncryptedData(context,
238 crypto,
239 KRB5_KU_TGS_REP_ENC_PART_SESSION,
240 buf,
241 len,
242 ckvno,
243 &rep->enc_part);
244 free(buf);
245 ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret);
247 krb5_crypto_destroy(context, crypto);
248 if(ret) {
249 kdc_log(0, "Failed to encode KDC-REP: %s",
250 krb5_get_err_text(context, ret));
251 return ret;
253 if(buf_size != len) {
254 free(buf);
255 kdc_log(0, "Internal error in ASN.1 encoder");
256 *e_text = "KDC internal error";
257 return KRB5KRB_ERR_GENERIC;
259 reply->data = buf;
260 reply->length = buf_size;
261 return 0;
264 static int
265 realloc_method_data(METHOD_DATA *md)
267 PA_DATA *pa;
268 pa = realloc(md->val, (md->len + 1) * sizeof(*md->val));
269 if(pa == NULL)
270 return ENOMEM;
271 md->val = pa;
272 md->len++;
273 return 0;
276 static krb5_error_code
277 make_etype_info_entry(ETYPE_INFO_ENTRY *ent, Key *key)
279 ent->etype = key->key.keytype;
280 if(key->salt){
281 ALLOC(ent->salttype);
282 #if 0
283 if(key->salt->type == hdb_pw_salt)
284 *ent->salttype = 0; /* or 1? or NULL? */
285 else if(key->salt->type == hdb_afs3_salt)
286 *ent->salttype = 2;
287 else {
288 kdc_log(0, "unknown salt-type: %d",
289 key->salt->type);
290 return KRB5KRB_ERR_GENERIC;
292 /* according to `the specs', we can't send a salt if
293 we have AFS3 salted key, but that requires that you
294 *know* what cell you are using (e.g by assuming
295 that the cell is the same as the realm in lower
296 case) */
297 #else
298 *ent->salttype = key->salt->type;
299 #endif
300 krb5_copy_data(context, &key->salt->salt,
301 &ent->salt);
302 } else {
303 /* we return no salt type at all, as that should indicate
304 * the default salt type and make everybody happy. some
305 * systems (like w2k) dislike being told the salt type
306 * here. */
308 ent->salttype = NULL;
309 ent->salt = NULL;
311 return 0;
314 static krb5_error_code
315 get_pa_etype_info(METHOD_DATA *md, hdb_entry *client,
316 ENCTYPE *etypes, unsigned int etypes_len)
318 krb5_error_code ret = 0;
319 int i, j;
320 unsigned int n = 0;
321 ETYPE_INFO pa;
322 unsigned char *buf;
323 size_t len;
326 pa.len = client->keys.len;
327 if(pa.len > UINT_MAX/sizeof(*pa.val))
328 return ERANGE;
329 pa.val = malloc(pa.len * sizeof(*pa.val));
330 if(pa.val == NULL)
331 return ENOMEM;
333 for(j = 0; j < etypes_len; j++) {
334 for (i = 0; i < n; i++)
335 if (pa.val[i].etype == etypes[j])
336 goto skip1;
337 for(i = 0; i < client->keys.len; i++) {
338 if(client->keys.val[i].key.keytype == etypes[j])
339 if((ret = make_etype_info_entry(&pa.val[n++],
340 &client->keys.val[i])) != 0) {
341 free_ETYPE_INFO(&pa);
342 return ret;
345 skip1:;
347 for(i = 0; i < client->keys.len; i++) {
348 for(j = 0; j < etypes_len; j++) {
349 if(client->keys.val[i].key.keytype == etypes[j])
350 goto skip2;
352 if((ret = make_etype_info_entry(&pa.val[n++],
353 &client->keys.val[i])) != 0) {
354 free_ETYPE_INFO(&pa);
355 return ret;
357 skip2:;
360 if(n != pa.len) {
361 char *name;
362 krb5_unparse_name(context, client->principal, &name);
363 kdc_log(0, "internal error in get_pa_etype_info(%s): %d != %d",
364 name, n, pa.len);
365 free(name);
366 pa.len = n;
369 ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
370 free_ETYPE_INFO(&pa);
371 if(ret)
372 return ret;
373 ret = realloc_method_data(md);
374 if(ret) {
375 free(buf);
376 return ret;
378 md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO;
379 md->val[md->len - 1].padata_value.length = len;
380 md->val[md->len - 1].padata_value.data = buf;
381 return 0;
385 * verify the flags on `client' and `server', returning 0
386 * if they are OK and generating an error messages and returning
387 * and error code otherwise.
390 krb5_error_code
391 check_flags(hdb_entry *client, const char *client_name,
392 hdb_entry *server, const char *server_name,
393 krb5_boolean is_as_req)
395 if(client != NULL) {
396 /* check client */
397 if (client->flags.invalid) {
398 kdc_log(0, "Client (%s) has invalid bit set", client_name);
399 return KRB5KDC_ERR_POLICY;
402 if(!client->flags.client){
403 kdc_log(0, "Principal may not act as client -- %s",
404 client_name);
405 return KRB5KDC_ERR_POLICY;
408 if (client->valid_start && *client->valid_start > kdc_time) {
409 kdc_log(0, "Client not yet valid -- %s", client_name);
410 return KRB5KDC_ERR_CLIENT_NOTYET;
413 if (client->valid_end && *client->valid_end < kdc_time) {
414 kdc_log(0, "Client expired -- %s", client_name);
415 return KRB5KDC_ERR_NAME_EXP;
418 if (client->pw_end && *client->pw_end < kdc_time
419 && !server->flags.change_pw) {
420 kdc_log(0, "Client's key has expired -- %s", client_name);
421 return KRB5KDC_ERR_KEY_EXPIRED;
425 /* check server */
427 if (server != NULL) {
428 if (server->flags.invalid) {
429 kdc_log(0, "Server has invalid flag set -- %s", server_name);
430 return KRB5KDC_ERR_POLICY;
433 if(!server->flags.server){
434 kdc_log(0, "Principal may not act as server -- %s",
435 server_name);
436 return KRB5KDC_ERR_POLICY;
439 if(!is_as_req && server->flags.initial) {
440 kdc_log(0, "AS-REQ is required for server -- %s", server_name);
441 return KRB5KDC_ERR_POLICY;
444 if (server->valid_start && *server->valid_start > kdc_time) {
445 kdc_log(0, "Server not yet valid -- %s", server_name);
446 return KRB5KDC_ERR_SERVICE_NOTYET;
449 if (server->valid_end && *server->valid_end < kdc_time) {
450 kdc_log(0, "Server expired -- %s", server_name);
451 return KRB5KDC_ERR_SERVICE_EXP;
454 if (server->pw_end && *server->pw_end < kdc_time) {
455 kdc_log(0, "Server's key has expired -- %s", server_name);
456 return KRB5KDC_ERR_KEY_EXPIRED;
459 return 0;
463 * Return TRUE if `from' is part of `addresses' taking into consideration
464 * the configuration variables that tells us how strict we should be about
465 * these checks
468 static krb5_boolean
469 check_addresses(HostAddresses *addresses, const struct sockaddr *from)
471 krb5_error_code ret;
472 krb5_address addr;
473 krb5_boolean result;
475 if(check_ticket_addresses == 0)
476 return TRUE;
478 if(addresses == NULL)
479 return allow_null_ticket_addresses;
481 ret = krb5_sockaddr2address (context, from, &addr);
482 if(ret)
483 return FALSE;
485 result = krb5_address_search(context, &addr, addresses);
486 krb5_free_address (context, &addr);
487 return result;
490 krb5_error_code
491 as_rep(KDC_REQ *req,
492 krb5_data *reply,
493 const char *from,
494 struct sockaddr *from_addr)
496 KDC_REQ_BODY *b = &req->req_body;
497 AS_REP rep;
498 KDCOptions f = b->kdc_options;
499 hdb_entry *client = NULL, *server = NULL;
500 krb5_enctype cetype, setype;
501 EncTicketPart et;
502 EncKDCRepPart ek;
503 krb5_principal client_princ = NULL, server_princ = NULL;
504 char *client_name = NULL, *server_name = NULL;
505 krb5_error_code ret = 0;
506 const char *e_text = NULL;
507 krb5_crypto crypto;
508 Key *ckey, *skey;
510 memset(&rep, 0, sizeof(rep));
512 if(b->sname == NULL){
513 ret = KRB5KRB_ERR_GENERIC;
514 e_text = "No server in request";
515 } else{
516 principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
517 krb5_unparse_name(context, server_princ, &server_name);
519 if (ret) {
520 kdc_log(0, "AS-REQ malformed server name from %s", from);
521 goto out;
524 if(b->cname == NULL){
525 ret = KRB5KRB_ERR_GENERIC;
526 e_text = "No client in request";
527 } else {
528 principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
529 krb5_unparse_name(context, client_princ, &client_name);
531 if (ret) {
532 kdc_log(0, "AS-REQ malformed client name from %s", from);
533 goto out;
536 kdc_log(0, "AS-REQ %s from %s for %s", client_name, from, server_name);
538 ret = db_fetch(client_princ, &client);
539 if(ret){
540 kdc_log(0, "UNKNOWN -- %s: %s", client_name,
541 krb5_get_err_text(context, ret));
542 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
543 goto out;
546 ret = db_fetch(server_princ, &server);
547 if(ret){
548 kdc_log(0, "UNKNOWN -- %s: %s", server_name,
549 krb5_get_err_text(context, ret));
550 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
551 goto out;
554 ret = check_flags(client, client_name, server, server_name, TRUE);
555 if(ret)
556 goto out;
558 memset(&et, 0, sizeof(et));
559 memset(&ek, 0, sizeof(ek));
561 if(req->padata){
562 int i = 0;
563 PA_DATA *pa;
564 int found_pa = 0;
565 kdc_log(5, "Looking for pa-data -- %s", client_name);
566 while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
567 krb5_data ts_data;
568 PA_ENC_TS_ENC p;
569 time_t patime;
570 size_t len;
571 EncryptedData enc_data;
572 Key *pa_key;
574 found_pa = 1;
576 ret = decode_EncryptedData(pa->padata_value.data,
577 pa->padata_value.length,
578 &enc_data,
579 &len);
580 if (ret) {
581 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
582 kdc_log(5, "Failed to decode PA-DATA -- %s",
583 client_name);
584 goto out;
587 ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
588 if(ret){
589 char *estr;
590 e_text = "No key matches pa-data";
591 ret = KRB5KDC_ERR_PREAUTH_FAILED;
592 if(krb5_enctype_to_string(context, enc_data.etype, &estr))
593 estr = NULL;
594 if(estr == NULL)
595 kdc_log(5, "No client key matching pa-data (%d) -- %s",
596 enc_data.etype, client_name);
597 else
598 kdc_log(5, "No client key matching pa-data (%s) -- %s",
599 estr, client_name);
600 free(estr);
602 free_EncryptedData(&enc_data);
603 continue;
606 try_next_key:
607 ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
608 if (ret) {
609 kdc_log(0, "krb5_crypto_init failed: %s",
610 krb5_get_err_text(context, ret));
611 free_EncryptedData(&enc_data);
612 continue;
615 ret = krb5_decrypt_EncryptedData (context,
616 crypto,
617 KRB5_KU_PA_ENC_TIMESTAMP,
618 &enc_data,
619 &ts_data);
620 krb5_crypto_destroy(context, crypto);
621 if(ret){
622 if(hdb_next_enctype2key(context, client,
623 enc_data.etype, &pa_key) == 0)
624 goto try_next_key;
625 free_EncryptedData(&enc_data);
626 e_text = "Failed to decrypt PA-DATA";
627 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
628 client_name);
629 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
630 continue;
632 free_EncryptedData(&enc_data);
633 ret = decode_PA_ENC_TS_ENC(ts_data.data,
634 ts_data.length,
636 &len);
637 krb5_data_free(&ts_data);
638 if(ret){
639 e_text = "Failed to decode PA-ENC-TS-ENC";
640 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
641 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
642 client_name);
643 continue;
645 patime = p.patimestamp;
646 free_PA_ENC_TS_ENC(&p);
647 if (abs(kdc_time - p.patimestamp) > context->max_skew) {
648 ret = KRB5KDC_ERR_PREAUTH_FAILED;
649 e_text = "Too large time skew";
650 kdc_log(0, "Too large time skew -- %s", client_name);
651 goto out;
653 et.flags.pre_authent = 1;
654 kdc_log(2, "Pre-authentication succeded -- %s", client_name);
655 break;
657 if(found_pa == 0 && require_preauth)
658 goto use_pa;
659 /* We come here if we found a pa-enc-timestamp, but if there
660 was some problem with it, other than too large skew */
661 if(found_pa && et.flags.pre_authent == 0){
662 kdc_log(0, "%s -- %s", e_text, client_name);
663 e_text = NULL;
664 goto out;
666 }else if (require_preauth
667 || client->flags.require_preauth
668 || server->flags.require_preauth) {
669 METHOD_DATA method_data;
670 PA_DATA *pa;
671 unsigned char *buf;
672 size_t len;
673 krb5_data foo_data;
675 use_pa:
676 method_data.len = 0;
677 method_data.val = NULL;
679 ret = realloc_method_data(&method_data);
680 pa = &method_data.val[method_data.len-1];
681 pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
682 pa->padata_value.length = 0;
683 pa->padata_value.data = NULL;
685 ret = get_pa_etype_info(&method_data, client,
686 b->etype.val, b->etype.len); /* XXX check ret */
688 ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
689 free_METHOD_DATA(&method_data);
690 foo_data.data = buf;
691 foo_data.length = len;
693 ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
694 krb5_mk_error(context,
695 ret,
696 "Need to use PA-ENC-TIMESTAMP",
697 &foo_data,
698 client_princ,
699 server_princ,
700 NULL,
701 NULL,
702 reply);
703 free(buf);
704 kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
705 ret = 0;
706 goto out2;
709 ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
710 b->etype.val, b->etype.len);
711 if(ret) {
712 kdc_log(0, "Server/client has no support for etypes");
713 goto out;
717 char *cet;
718 char *set;
720 ret = krb5_enctype_to_string(context, cetype, &cet);
721 if(ret == 0) {
722 ret = krb5_enctype_to_string(context, setype, &set);
723 if (ret == 0) {
724 kdc_log(5, "Using %s/%s", cet, set);
725 free(set);
727 free(cet);
729 if (ret != 0)
730 kdc_log(5, "Using e-types %d/%d", cetype, setype);
734 char str[128];
735 unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
736 if(*str)
737 kdc_log(2, "Requested flags: %s", str);
741 if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
742 || (f.request_anonymous && !allow_anonymous)) {
743 ret = KRB5KDC_ERR_BADOPTION;
744 kdc_log(0, "Bad KDC options -- %s", client_name);
745 goto out;
748 rep.pvno = 5;
749 rep.msg_type = krb_as_rep;
750 copy_Realm(&b->realm, &rep.crealm);
751 if (f.request_anonymous)
752 make_anonymous_principalname (&rep.cname);
753 else
754 copy_PrincipalName(b->cname, &rep.cname);
755 rep.ticket.tkt_vno = 5;
756 copy_Realm(&b->realm, &rep.ticket.realm);
757 copy_PrincipalName(b->sname, &rep.ticket.sname);
759 et.flags.initial = 1;
760 if(client->flags.forwardable && server->flags.forwardable)
761 et.flags.forwardable = f.forwardable;
762 else if (f.forwardable) {
763 ret = KRB5KDC_ERR_POLICY;
764 kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
765 goto out;
767 if(client->flags.proxiable && server->flags.proxiable)
768 et.flags.proxiable = f.proxiable;
769 else if (f.proxiable) {
770 ret = KRB5KDC_ERR_POLICY;
771 kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
772 goto out;
774 if(client->flags.postdate && server->flags.postdate)
775 et.flags.may_postdate = f.allow_postdate;
776 else if (f.allow_postdate){
777 ret = KRB5KDC_ERR_POLICY;
778 kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
779 goto out;
782 /* check for valid set of addresses */
783 if(!check_addresses(b->addresses, from_addr)) {
784 ret = KRB5KRB_AP_ERR_BADADDR;
785 kdc_log(0, "Bad address list requested -- %s", client_name);
786 goto out;
789 krb5_generate_random_keyblock(context, setype, &et.key);
790 copy_PrincipalName(&rep.cname, &et.cname);
791 copy_Realm(&b->realm, &et.crealm);
794 time_t start;
795 time_t t;
797 start = et.authtime = kdc_time;
799 if(f.postdated && req->req_body.from){
800 ALLOC(et.starttime);
801 start = *et.starttime = *req->req_body.from;
802 et.flags.invalid = 1;
803 et.flags.postdated = 1; /* XXX ??? */
805 fix_time(&b->till);
806 t = *b->till;
808 /* be careful not overflowing */
810 if(client->max_life)
811 t = start + min(t - start, *client->max_life);
812 if(server->max_life)
813 t = start + min(t - start, *server->max_life);
814 #if 0
815 t = min(t, start + realm->max_life);
816 #endif
817 et.endtime = t;
818 if(f.renewable_ok && et.endtime < *b->till){
819 f.renewable = 1;
820 if(b->rtime == NULL){
821 ALLOC(b->rtime);
822 *b->rtime = 0;
824 if(*b->rtime < *b->till)
825 *b->rtime = *b->till;
827 if(f.renewable && b->rtime){
828 t = *b->rtime;
829 if(t == 0)
830 t = MAX_TIME;
831 if(client->max_renew)
832 t = start + min(t - start, *client->max_renew);
833 if(server->max_renew)
834 t = start + min(t - start, *server->max_renew);
835 #if 0
836 t = min(t, start + realm->max_renew);
837 #endif
838 ALLOC(et.renew_till);
839 *et.renew_till = t;
840 et.flags.renewable = 1;
844 if (f.request_anonymous)
845 et.flags.anonymous = 1;
847 if(b->addresses){
848 ALLOC(et.caddr);
849 copy_HostAddresses(b->addresses, et.caddr);
852 et.transited.tr_type = DOMAIN_X500_COMPRESS;
853 krb5_data_zero(&et.transited.contents);
855 copy_EncryptionKey(&et.key, &ek.key);
857 /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
858 * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
859 * incapable of correctly decoding SEQUENCE OF's of zero length.
861 * To fix this, always send at least one no-op last_req
863 * If there's a pw_end or valid_end we will use that,
864 * otherwise just a dummy lr.
866 ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
867 ek.last_req.len = 0;
868 if (client->pw_end
869 && (kdc_warn_pwexpire == 0
870 || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
871 ek.last_req.val[ek.last_req.len].lr_type = LR_PW_EXPTIME;
872 ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
873 ++ek.last_req.len;
875 if (client->valid_end) {
876 ek.last_req.val[ek.last_req.len].lr_type = LR_ACCT_EXPTIME;
877 ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
878 ++ek.last_req.len;
880 if (ek.last_req.len == 0) {
881 ek.last_req.val[ek.last_req.len].lr_type = LR_NONE;
882 ek.last_req.val[ek.last_req.len].lr_value = 0;
883 ++ek.last_req.len;
885 ek.nonce = b->nonce;
886 if (client->valid_end || client->pw_end) {
887 ALLOC(ek.key_expiration);
888 if (client->valid_end) {
889 if (client->pw_end)
890 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
891 else
892 *ek.key_expiration = *client->valid_end;
893 } else
894 *ek.key_expiration = *client->pw_end;
895 } else
896 ek.key_expiration = NULL;
897 ek.flags = et.flags;
898 ek.authtime = et.authtime;
899 if (et.starttime) {
900 ALLOC(ek.starttime);
901 *ek.starttime = *et.starttime;
903 ek.endtime = et.endtime;
904 if (et.renew_till) {
905 ALLOC(ek.renew_till);
906 *ek.renew_till = *et.renew_till;
908 copy_Realm(&rep.ticket.realm, &ek.srealm);
909 copy_PrincipalName(&rep.ticket.sname, &ek.sname);
910 if(et.caddr){
911 ALLOC(ek.caddr);
912 copy_HostAddresses(et.caddr, ek.caddr);
915 set_salt_padata (&rep.padata, ckey->salt);
916 ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
917 client->kvno, &ckey->key, &e_text, reply);
918 free_EncTicketPart(&et);
919 free_EncKDCRepPart(&ek);
920 out:
921 free_AS_REP(&rep);
922 if(ret){
923 krb5_mk_error(context,
924 ret,
925 e_text,
926 NULL,
927 client_princ,
928 server_princ,
929 NULL,
930 NULL,
931 reply);
932 ret = 0;
934 out2:
935 if (client_princ)
936 krb5_free_principal(context, client_princ);
937 free(client_name);
938 if (server_princ)
939 krb5_free_principal(context, server_princ);
940 free(server_name);
941 if(client)
942 free_ent(client);
943 if(server)
944 free_ent(server);
945 return ret;
949 static krb5_error_code
950 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
952 KDCOptions f = b->kdc_options;
954 if(f.validate){
955 if(!tgt->flags.invalid || tgt->starttime == NULL){
956 kdc_log(0, "Bad request to validate ticket");
957 return KRB5KDC_ERR_BADOPTION;
959 if(*tgt->starttime > kdc_time){
960 kdc_log(0, "Early request to validate ticket");
961 return KRB5KRB_AP_ERR_TKT_NYV;
963 /* XXX tkt = tgt */
964 et->flags.invalid = 0;
965 }else if(tgt->flags.invalid){
966 kdc_log(0, "Ticket-granting ticket has INVALID flag set");
967 return KRB5KRB_AP_ERR_TKT_INVALID;
970 if(f.forwardable){
971 if(!tgt->flags.forwardable){
972 kdc_log(0, "Bad request for forwardable ticket");
973 return KRB5KDC_ERR_BADOPTION;
975 et->flags.forwardable = 1;
977 if(f.forwarded){
978 if(!tgt->flags.forwardable){
979 kdc_log(0, "Request to forward non-forwardable ticket");
980 return KRB5KDC_ERR_BADOPTION;
982 et->flags.forwarded = 1;
983 et->caddr = b->addresses;
985 if(tgt->flags.forwarded)
986 et->flags.forwarded = 1;
988 if(f.proxiable){
989 if(!tgt->flags.proxiable){
990 kdc_log(0, "Bad request for proxiable ticket");
991 return KRB5KDC_ERR_BADOPTION;
993 et->flags.proxiable = 1;
995 if(f.proxy){
996 if(!tgt->flags.proxiable){
997 kdc_log(0, "Request to proxy non-proxiable ticket");
998 return KRB5KDC_ERR_BADOPTION;
1000 et->flags.proxy = 1;
1001 et->caddr = b->addresses;
1003 if(tgt->flags.proxy)
1004 et->flags.proxy = 1;
1006 if(f.allow_postdate){
1007 if(!tgt->flags.may_postdate){
1008 kdc_log(0, "Bad request for post-datable ticket");
1009 return KRB5KDC_ERR_BADOPTION;
1011 et->flags.may_postdate = 1;
1013 if(f.postdated){
1014 if(!tgt->flags.may_postdate){
1015 kdc_log(0, "Bad request for postdated ticket");
1016 return KRB5KDC_ERR_BADOPTION;
1018 if(b->from)
1019 *et->starttime = *b->from;
1020 et->flags.postdated = 1;
1021 et->flags.invalid = 1;
1022 }else if(b->from && *b->from > kdc_time + context->max_skew){
1023 kdc_log(0, "Ticket cannot be postdated");
1024 return KRB5KDC_ERR_CANNOT_POSTDATE;
1027 if(f.renewable){
1028 if(!tgt->flags.renewable){
1029 kdc_log(0, "Bad request for renewable ticket");
1030 return KRB5KDC_ERR_BADOPTION;
1032 et->flags.renewable = 1;
1033 ALLOC(et->renew_till);
1034 fix_time(&b->rtime);
1035 *et->renew_till = *b->rtime;
1037 if(f.renew){
1038 time_t old_life;
1039 if(!tgt->flags.renewable || tgt->renew_till == NULL){
1040 kdc_log(0, "Request to renew non-renewable ticket");
1041 return KRB5KDC_ERR_BADOPTION;
1043 old_life = tgt->endtime;
1044 if(tgt->starttime)
1045 old_life -= *tgt->starttime;
1046 else
1047 old_life -= tgt->authtime;
1048 et->endtime = *et->starttime + old_life;
1049 if (et->renew_till != NULL)
1050 et->endtime = min(*et->renew_till, et->endtime);
1053 /* checks for excess flags */
1054 if(f.request_anonymous && !allow_anonymous){
1055 kdc_log(0, "Request for anonymous ticket");
1056 return KRB5KDC_ERR_BADOPTION;
1058 return 0;
1061 static krb5_error_code
1062 fix_transited_encoding(krb5_boolean check_policy,
1063 TransitedEncoding *tr,
1064 EncTicketPart *et,
1065 const char *client_realm,
1066 const char *server_realm,
1067 const char *tgt_realm)
1069 krb5_error_code ret = 0;
1070 char **realms, **tmp;
1071 int num_realms;
1072 int i;
1074 if(tr->tr_type != DOMAIN_X500_COMPRESS) {
1075 kdc_log(0, "Unknown transited type: %u", tr->tr_type);
1076 return KRB5KDC_ERR_TRTYPE_NOSUPP;
1079 ret = krb5_domain_x500_decode(context,
1080 tr->contents,
1081 &realms,
1082 &num_realms,
1083 client_realm,
1084 server_realm);
1085 if(ret){
1086 krb5_warn(context, ret, "Decoding transited encoding");
1087 return ret;
1089 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
1090 /* not us, so add the previous realm to transited set */
1091 if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
1092 ret = ERANGE;
1093 goto free_realms;
1095 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1096 if(tmp == NULL){
1097 ret = ENOMEM;
1098 goto free_realms;
1100 realms = tmp;
1101 realms[num_realms] = strdup(tgt_realm);
1102 if(realms[num_realms] == NULL){
1103 ret = ENOMEM;
1104 goto free_realms;
1106 num_realms++;
1108 if(num_realms == 0) {
1109 if(strcmp(client_realm, server_realm))
1110 kdc_log(0, "cross-realm %s -> %s", client_realm, server_realm);
1111 } else {
1112 size_t l = 0;
1113 char *rs;
1114 for(i = 0; i < num_realms; i++)
1115 l += strlen(realms[i]) + 2;
1116 rs = malloc(l);
1117 if(rs != NULL) {
1118 *rs = '\0';
1119 for(i = 0; i < num_realms; i++) {
1120 if(i > 0)
1121 strlcat(rs, ", ", l);
1122 strlcat(rs, realms[i], l);
1124 kdc_log(0, "cross-realm %s -> %s via [%s]", client_realm, server_realm, rs);
1125 free(rs);
1128 if(check_policy) {
1129 ret = krb5_check_transited(context, client_realm,
1130 server_realm,
1131 realms, num_realms, NULL);
1132 if(ret) {
1133 krb5_warn(context, ret, "cross-realm %s -> %s",
1134 client_realm, server_realm);
1135 goto free_realms;
1137 et->flags.transited_policy_checked = 1;
1139 et->transited.tr_type = DOMAIN_X500_COMPRESS;
1140 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
1141 if(ret)
1142 krb5_warn(context, ret, "Encoding transited encoding");
1143 free_realms:
1144 for(i = 0; i < num_realms; i++)
1145 free(realms[i]);
1146 free(realms);
1147 return ret;
1151 static krb5_error_code
1152 tgs_make_reply(KDC_REQ_BODY *b,
1153 EncTicketPart *tgt,
1154 EncTicketPart *adtkt,
1155 AuthorizationData *auth_data,
1156 hdb_entry *server,
1157 hdb_entry *client,
1158 krb5_principal client_principal,
1159 hdb_entry *krbtgt,
1160 krb5_enctype cetype,
1161 const char **e_text,
1162 krb5_data *reply)
1164 KDC_REP rep;
1165 EncKDCRepPart ek;
1166 EncTicketPart et;
1167 KDCOptions f = b->kdc_options;
1168 krb5_error_code ret;
1169 krb5_enctype etype;
1170 Key *skey;
1171 EncryptionKey *ekey;
1173 if(adtkt) {
1174 int i;
1175 krb5_keytype kt;
1176 ekey = &adtkt->key;
1177 for(i = 0; i < b->etype.len; i++){
1178 ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
1179 if(ret)
1180 continue;
1181 if(adtkt->key.keytype == kt)
1182 break;
1184 if(i == b->etype.len)
1185 return KRB5KDC_ERR_ETYPE_NOSUPP;
1186 etype = b->etype.val[i];
1187 }else{
1188 ret = find_keys(NULL, server, NULL, NULL, &skey, &etype,
1189 b->etype.val, b->etype.len);
1190 if(ret) {
1191 kdc_log(0, "Server has no support for etypes");
1192 return ret;
1194 ekey = &skey->key;
1197 memset(&rep, 0, sizeof(rep));
1198 memset(&et, 0, sizeof(et));
1199 memset(&ek, 0, sizeof(ek));
1201 rep.pvno = 5;
1202 rep.msg_type = krb_tgs_rep;
1204 et.authtime = tgt->authtime;
1205 fix_time(&b->till);
1206 et.endtime = min(tgt->endtime, *b->till);
1207 ALLOC(et.starttime);
1208 *et.starttime = kdc_time;
1210 ret = check_tgs_flags(b, tgt, &et);
1211 if(ret)
1212 goto out;
1214 /* We should check the transited encoding if:
1215 1) the request doesn't ask not to be checked
1216 2) globally enforcing a check
1217 3) principal requires checking
1218 4) we allow non-check per-principal, but principal isn't marked as allowing this
1219 5) we don't globally allow this
1222 #define GLOBAL_FORCE_TRANSITED_CHECK (trpolicy == TRPOLICY_ALWAYS_CHECK)
1223 #define GLOBAL_ALLOW_PER_PRINCIPAL (trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
1224 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK (trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
1225 /* these will consult the database in future release */
1226 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
1227 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
1229 ret = fix_transited_encoding(!f.disable_transited_check ||
1230 GLOBAL_FORCE_TRANSITED_CHECK ||
1231 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
1232 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
1233 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
1234 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
1235 &tgt->transited, &et,
1236 *krb5_princ_realm(context, client_principal),
1237 *krb5_princ_realm(context, server->principal),
1238 *krb5_princ_realm(context, krbtgt->principal));
1239 if(ret)
1240 goto out;
1242 copy_Realm(krb5_princ_realm(context, server->principal),
1243 &rep.ticket.realm);
1244 krb5_principal2principalname(&rep.ticket.sname, server->principal);
1245 copy_Realm(&tgt->crealm, &rep.crealm);
1246 if (f.request_anonymous)
1247 make_anonymous_principalname (&tgt->cname);
1248 else
1249 copy_PrincipalName(&tgt->cname, &rep.cname);
1250 rep.ticket.tkt_vno = 5;
1252 ek.caddr = et.caddr;
1253 if(et.caddr == NULL)
1254 et.caddr = tgt->caddr;
1257 time_t life;
1258 life = et.endtime - *et.starttime;
1259 if(client && client->max_life)
1260 life = min(life, *client->max_life);
1261 if(server->max_life)
1262 life = min(life, *server->max_life);
1263 et.endtime = *et.starttime + life;
1265 if(f.renewable_ok && tgt->flags.renewable &&
1266 et.renew_till == NULL && et.endtime < *b->till){
1267 et.flags.renewable = 1;
1268 ALLOC(et.renew_till);
1269 *et.renew_till = *b->till;
1271 if(et.renew_till){
1272 time_t renew;
1273 renew = *et.renew_till - et.authtime;
1274 if(client && client->max_renew)
1275 renew = min(renew, *client->max_renew);
1276 if(server->max_renew)
1277 renew = min(renew, *server->max_renew);
1278 *et.renew_till = et.authtime + renew;
1281 if(et.renew_till){
1282 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
1283 *et.starttime = min(*et.starttime, *et.renew_till);
1284 et.endtime = min(et.endtime, *et.renew_till);
1287 *et.starttime = min(*et.starttime, et.endtime);
1289 if(*et.starttime == et.endtime){
1290 ret = KRB5KDC_ERR_NEVER_VALID;
1291 goto out;
1293 if(et.renew_till && et.endtime == *et.renew_till){
1294 free(et.renew_till);
1295 et.renew_till = NULL;
1296 et.flags.renewable = 0;
1299 et.flags.pre_authent = tgt->flags.pre_authent;
1300 et.flags.hw_authent = tgt->flags.hw_authent;
1301 et.flags.anonymous = tgt->flags.anonymous;
1303 /* XXX Check enc-authorization-data */
1304 et.authorization_data = auth_data;
1306 krb5_generate_random_keyblock(context, etype, &et.key);
1307 et.crealm = tgt->crealm;
1308 et.cname = tgt->cname;
1310 ek.key = et.key;
1311 /* MIT must have at least one last_req */
1312 ek.last_req.len = 1;
1313 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1314 ek.nonce = b->nonce;
1315 ek.flags = et.flags;
1316 ek.authtime = et.authtime;
1317 ek.starttime = et.starttime;
1318 ek.endtime = et.endtime;
1319 ek.renew_till = et.renew_till;
1320 ek.srealm = rep.ticket.realm;
1321 ek.sname = rep.ticket.sname;
1323 /* It is somewhat unclear where the etype in the following
1324 encryption should come from. What we have is a session
1325 key in the passed tgt, and a list of preferred etypes
1326 *for the new ticket*. Should we pick the best possible
1327 etype, given the keytype in the tgt, or should we look
1328 at the etype list here as well? What if the tgt
1329 session key is DES3 and we want a ticket with a (say)
1330 CAST session key. Should the DES3 etype be added to the
1331 etype list, even if we don't want a session key with
1332 DES3? */
1333 ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
1334 0, &tgt->key, e_text, reply);
1335 out:
1336 free_TGS_REP(&rep);
1337 free_TransitedEncoding(&et.transited);
1338 if(et.starttime)
1339 free(et.starttime);
1340 if(et.renew_till)
1341 free(et.renew_till);
1342 free_LastReq(&ek.last_req);
1343 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1344 free_EncryptionKey(&et.key);
1345 return ret;
1348 static krb5_error_code
1349 tgs_check_authenticator(krb5_auth_context ac,
1350 KDC_REQ_BODY *b,
1351 const char **e_text,
1352 krb5_keyblock *key)
1354 krb5_authenticator auth;
1355 size_t len;
1356 unsigned char *buf;
1357 size_t buf_size;
1358 krb5_error_code ret;
1359 krb5_crypto crypto;
1361 krb5_auth_con_getauthenticator(context, ac, &auth);
1362 if(auth->cksum == NULL){
1363 kdc_log(0, "No authenticator in request");
1364 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1365 goto out;
1368 * according to RFC1510 it doesn't need to be keyed,
1369 * but according to the latest draft it needs to.
1371 if (
1372 #if 0
1373 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1375 #endif
1376 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1377 kdc_log(0, "Bad checksum type in authenticator: %d",
1378 auth->cksum->cksumtype);
1379 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1380 goto out;
1383 /* XXX should not re-encode this */
1384 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1385 if(ret){
1386 kdc_log(0, "Failed to encode KDC-REQ-BODY: %s",
1387 krb5_get_err_text(context, ret));
1388 goto out;
1390 if(buf_size != len) {
1391 free(buf);
1392 kdc_log(0, "Internal error in ASN.1 encoder");
1393 *e_text = "KDC internal error";
1394 ret = KRB5KRB_ERR_GENERIC;
1395 goto out;
1397 ret = krb5_crypto_init(context, key, 0, &crypto);
1398 if (ret) {
1399 free(buf);
1400 kdc_log(0, "krb5_crypto_init failed: %s",
1401 krb5_get_err_text(context, ret));
1402 goto out;
1404 ret = krb5_verify_checksum(context,
1405 crypto,
1406 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1407 buf,
1408 len,
1409 auth->cksum);
1410 free(buf);
1411 krb5_crypto_destroy(context, crypto);
1412 if(ret){
1413 kdc_log(0, "Failed to verify checksum: %s",
1414 krb5_get_err_text(context, ret));
1416 out:
1417 free_Authenticator(auth);
1418 free(auth);
1419 return ret;
1423 * return the realm of a krbtgt-ticket or NULL
1426 static Realm
1427 get_krbtgt_realm(const PrincipalName *p)
1429 if(p->name_string.len == 2
1430 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
1431 return p->name_string.val[1];
1432 else
1433 return NULL;
1436 static Realm
1437 find_rpath(Realm crealm, Realm srealm)
1439 const char *new_realm = krb5_config_get_string(context,
1440 NULL,
1441 "capaths",
1442 crealm,
1443 srealm,
1444 NULL);
1445 return (Realm)new_realm;
1449 static krb5_boolean
1450 need_referral(krb5_principal server, krb5_realm **realms)
1452 if(server->name.name_type != KRB5_NT_SRV_INST ||
1453 server->name.name_string.len != 2)
1454 return FALSE;
1456 return krb5_get_host_realm_int(context, server->name.name_string.val[1],
1457 FALSE, realms) == 0;
1460 static krb5_error_code
1461 tgs_rep2(KDC_REQ_BODY *b,
1462 PA_DATA *tgs_req,
1463 krb5_data *reply,
1464 const char *from,
1465 const struct sockaddr *from_addr,
1466 time_t **csec,
1467 int **cusec)
1469 krb5_ap_req ap_req;
1470 krb5_error_code ret;
1471 krb5_principal princ;
1472 krb5_auth_context ac = NULL;
1473 krb5_ticket *ticket = NULL;
1474 krb5_flags ap_req_options;
1475 krb5_flags verify_ap_req_flags;
1476 const char *e_text = NULL;
1477 krb5_crypto crypto;
1479 hdb_entry *krbtgt = NULL;
1480 EncTicketPart *tgt;
1481 Key *tkey;
1482 krb5_enctype cetype;
1483 krb5_principal cp = NULL;
1484 krb5_principal sp = NULL;
1485 AuthorizationData *auth_data = NULL;
1487 *csec = NULL;
1488 *cusec = NULL;
1490 memset(&ap_req, 0, sizeof(ap_req));
1491 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1492 if(ret){
1493 kdc_log(0, "Failed to decode AP-REQ: %s",
1494 krb5_get_err_text(context, ret));
1495 goto out2;
1498 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1499 /* XXX check for ticket.sname == req.sname */
1500 kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1501 ret = KRB5KDC_ERR_POLICY; /* ? */
1502 goto out2;
1505 principalname2krb5_principal(&princ,
1506 ap_req.ticket.sname,
1507 ap_req.ticket.realm);
1509 ret = db_fetch(princ, &krbtgt);
1511 if(ret) {
1512 char *p;
1513 krb5_unparse_name(context, princ, &p);
1514 krb5_free_principal(context, princ);
1515 kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
1516 p, krb5_get_err_text(context, ret));
1517 free(p);
1518 ret = KRB5KRB_AP_ERR_NOT_US;
1519 goto out2;
1522 if(ap_req.ticket.enc_part.kvno &&
1523 *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
1524 char *p;
1526 krb5_unparse_name (context, princ, &p);
1527 krb5_free_principal(context, princ);
1528 kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)",
1529 *ap_req.ticket.enc_part.kvno,
1530 krbtgt->kvno,
1532 free (p);
1533 ret = KRB5KRB_AP_ERR_BADKEYVER;
1534 goto out2;
1537 ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
1538 if(ret){
1539 char *str;
1540 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1541 kdc_log(0, "No server key found for %s", str);
1542 free(str);
1543 ret = KRB5KRB_AP_ERR_BADKEYVER;
1544 goto out2;
1547 if (b->kdc_options.validate)
1548 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1549 else
1550 verify_ap_req_flags = 0;
1552 ret = krb5_verify_ap_req2(context,
1553 &ac,
1554 &ap_req,
1555 princ,
1556 &tkey->key,
1557 verify_ap_req_flags,
1558 &ap_req_options,
1559 &ticket,
1560 KRB5_KU_TGS_REQ_AUTH);
1562 krb5_free_principal(context, princ);
1563 if(ret) {
1564 kdc_log(0, "Failed to verify AP-REQ: %s",
1565 krb5_get_err_text(context, ret));
1566 goto out2;
1570 krb5_authenticator auth;
1572 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1573 if (ret == 0) {
1574 *csec = malloc(sizeof(**csec));
1575 if (*csec == NULL) {
1576 krb5_free_authenticator(context, &auth);
1577 kdc_log(0, "malloc failed");
1578 goto out2;
1580 **csec = auth->ctime;
1581 *cusec = malloc(sizeof(**cusec));
1582 if (*cusec == NULL) {
1583 krb5_free_authenticator(context, &auth);
1584 kdc_log(0, "malloc failed");
1585 goto out2;
1587 **csec = auth->cusec;
1588 krb5_free_authenticator(context, &auth);
1592 cetype = ap_req.authenticator.etype;
1594 tgt = &ticket->ticket;
1596 ret = tgs_check_authenticator(ac, b, &e_text, &tgt->key);
1598 if (b->enc_authorization_data) {
1599 krb5_keyblock *subkey;
1600 krb5_data ad;
1601 ret = krb5_auth_con_getremotesubkey(context,
1603 &subkey);
1604 if(ret){
1605 krb5_auth_con_free(context, ac);
1606 kdc_log(0, "Failed to get remote subkey: %s",
1607 krb5_get_err_text(context, ret));
1608 goto out2;
1610 if(subkey == NULL){
1611 ret = krb5_auth_con_getkey(context, ac, &subkey);
1612 if(ret) {
1613 krb5_auth_con_free(context, ac);
1614 kdc_log(0, "Failed to get session key: %s",
1615 krb5_get_err_text(context, ret));
1616 goto out2;
1619 if(subkey == NULL){
1620 krb5_auth_con_free(context, ac);
1621 kdc_log(0, "Failed to get key for enc-authorization-data");
1622 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1623 goto out2;
1625 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1626 if (ret) {
1627 krb5_auth_con_free(context, ac);
1628 kdc_log(0, "krb5_crypto_init failed: %s",
1629 krb5_get_err_text(context, ret));
1630 goto out2;
1632 ret = krb5_decrypt_EncryptedData (context,
1633 crypto,
1634 KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1635 b->enc_authorization_data,
1636 &ad);
1637 krb5_crypto_destroy(context, crypto);
1638 if(ret){
1639 krb5_auth_con_free(context, ac);
1640 kdc_log(0, "Failed to decrypt enc-authorization-data");
1641 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1642 goto out2;
1644 krb5_free_keyblock(context, subkey);
1645 ALLOC(auth_data);
1646 ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1647 if(ret){
1648 krb5_auth_con_free(context, ac);
1649 free(auth_data);
1650 auth_data = NULL;
1651 kdc_log(0, "Failed to decode authorization data");
1652 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1653 goto out2;
1657 krb5_auth_con_free(context, ac);
1659 if(ret){
1660 kdc_log(0, "Failed to verify authenticator: %s",
1661 krb5_get_err_text(context, ret));
1662 goto out2;
1666 PrincipalName *s;
1667 Realm r;
1668 char *spn = NULL, *cpn = NULL;
1669 hdb_entry *server = NULL, *client = NULL;
1670 int loop = 0;
1671 EncTicketPart adtkt;
1672 char opt_str[128];
1674 s = b->sname;
1675 r = b->realm;
1676 if(b->kdc_options.enc_tkt_in_skey){
1677 Ticket *t;
1678 hdb_entry *uu;
1679 krb5_principal p;
1680 Key *tkey;
1682 if(b->additional_tickets == NULL ||
1683 b->additional_tickets->len == 0){
1684 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1685 kdc_log(0, "No second ticket present in request");
1686 goto out;
1688 t = &b->additional_tickets->val[0];
1689 if(!get_krbtgt_realm(&t->sname)){
1690 kdc_log(0, "Additional ticket is not a ticket-granting ticket");
1691 ret = KRB5KDC_ERR_POLICY;
1692 goto out2;
1694 principalname2krb5_principal(&p, t->sname, t->realm);
1695 ret = db_fetch(p, &uu);
1696 krb5_free_principal(context, p);
1697 if(ret){
1698 if (ret == HDB_ERR_NOENTRY)
1699 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1700 goto out;
1702 ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
1703 if(ret){
1704 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1705 goto out;
1707 ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0);
1709 if(ret)
1710 goto out;
1711 s = &adtkt.cname;
1712 r = adtkt.crealm;
1715 principalname2krb5_principal(&sp, *s, r);
1716 krb5_unparse_name(context, sp, &spn);
1717 principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1718 krb5_unparse_name(context, cp, &cpn);
1719 unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
1720 opt_str, sizeof(opt_str));
1721 if(*opt_str)
1722 kdc_log(0, "TGS-REQ %s from %s for %s [%s]",
1723 cpn, from, spn, opt_str);
1724 else
1725 kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1726 server_lookup:
1727 ret = db_fetch(sp, &server);
1729 if(ret){
1730 Realm req_rlm, new_rlm;
1731 krb5_realm *realms;
1733 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1734 if(loop++ < 2) {
1735 new_rlm = find_rpath(tgt->crealm, req_rlm);
1736 if(new_rlm) {
1737 kdc_log(5, "krbtgt for realm %s not found, trying %s",
1738 req_rlm, new_rlm);
1739 krb5_free_principal(context, sp);
1740 free(spn);
1741 krb5_make_principal(context, &sp, r,
1742 KRB5_TGS_NAME, new_rlm, NULL);
1743 krb5_unparse_name(context, sp, &spn);
1744 goto server_lookup;
1747 } else if(need_referral(sp, &realms)) {
1748 if (strcmp(realms[0], sp->realm) != 0) {
1749 kdc_log(5, "returning a referral to realm %s for "
1750 "server %s that was not found",
1751 realms[0], spn);
1752 krb5_free_principal(context, sp);
1753 free(spn);
1754 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1755 realms[0], NULL);
1756 krb5_unparse_name(context, sp, &spn);
1757 krb5_free_host_realm(context, realms);
1758 goto server_lookup;
1760 krb5_free_host_realm(context, realms);
1762 kdc_log(0, "Server not found in database: %s: %s", spn,
1763 krb5_get_err_text(context, ret));
1764 if (ret == HDB_ERR_NOENTRY)
1765 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1766 goto out;
1769 ret = db_fetch(cp, &client);
1770 if(ret)
1771 kdc_log(1, "Client not found in database: %s: %s",
1772 cpn, krb5_get_err_text(context, ret));
1773 #if 0
1774 /* XXX check client only if same realm as krbtgt-instance */
1775 if(ret){
1776 kdc_log(0, "Client not found in database: %s: %s",
1777 cpn, krb5_get_err_text(context, ret));
1778 if (ret == HDB_ERR_NOENTRY)
1779 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1780 goto out;
1782 #endif
1784 if(strcmp(krb5_principal_get_realm(context, sp),
1785 krb5_principal_get_comp_string(context, krbtgt->principal, 1)) != 0) {
1786 char *tpn;
1787 ret = krb5_unparse_name(context, krbtgt->principal, &tpn);
1788 kdc_log(0, "Request with wrong krbtgt: %s", (ret == 0) ? tpn : "<unknown>");
1789 if(ret == 0)
1790 free(tpn);
1791 ret = KRB5KRB_AP_ERR_NOT_US;
1792 goto out;
1796 ret = check_flags(client, cpn, server, spn, FALSE);
1797 if(ret)
1798 goto out;
1800 if((b->kdc_options.validate || b->kdc_options.renew) &&
1801 !krb5_principal_compare(context,
1802 krbtgt->principal,
1803 server->principal)){
1804 kdc_log(0, "Inconsistent request.");
1805 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1806 goto out;
1809 /* check for valid set of addresses */
1810 if(!check_addresses(tgt->caddr, from_addr)) {
1811 ret = KRB5KRB_AP_ERR_BADADDR;
1812 kdc_log(0, "Request from wrong address");
1813 goto out;
1816 ret = tgs_make_reply(b,
1817 tgt,
1818 b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
1819 auth_data,
1820 server,
1821 client,
1822 cp,
1823 krbtgt,
1824 cetype,
1825 &e_text,
1826 reply);
1828 out:
1829 free(spn);
1830 free(cpn);
1832 if(server)
1833 free_ent(server);
1834 if(client)
1835 free_ent(client);
1837 out2:
1838 if(ret) {
1839 krb5_mk_error(context,
1840 ret,
1841 e_text,
1842 NULL,
1845 NULL,
1846 NULL,
1847 reply);
1848 free(*csec);
1849 free(*cusec);
1850 *csec = NULL;
1851 *cusec = NULL;
1853 krb5_free_principal(context, cp);
1854 krb5_free_principal(context, sp);
1855 if (ticket) {
1856 krb5_free_ticket(context, ticket);
1857 free(ticket);
1859 free_AP_REQ(&ap_req);
1860 if(auth_data){
1861 free_AuthorizationData(auth_data);
1862 free(auth_data);
1865 if(krbtgt)
1866 free_ent(krbtgt);
1868 return ret;
1872 krb5_error_code
1873 tgs_rep(KDC_REQ *req,
1874 krb5_data *data,
1875 const char *from,
1876 struct sockaddr *from_addr)
1878 krb5_error_code ret;
1879 int i = 0;
1880 PA_DATA *tgs_req = NULL;
1881 time_t *csec = NULL;
1882 int *cusec = NULL;
1884 if(req->padata == NULL){
1885 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1886 kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1887 goto out;
1890 tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1892 if(tgs_req == NULL){
1893 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1895 kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1896 goto out;
1898 ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr,
1899 &csec, &cusec);
1900 out:
1901 if(ret && data->data == NULL){
1902 krb5_mk_error(context,
1903 ret,
1904 NULL,
1905 NULL,
1906 NULL,
1907 NULL,
1908 csec,
1909 cusec,
1910 data);
1912 free(csec);
1913 free(cusec);
1914 return 0;