524.c revision 102644
155682Smarkm/* 2102644Snectar * Copyright (c) 1997-2002 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kdc_locl.h" 3555682Smarkm 36102644SnectarRCSID("$Id: 524.c,v 1.25 2002/07/31 09:43:20 joda Exp $"); 3755682Smarkm 3855682Smarkm#ifdef KRB4 3955682Smarkm 4072445Sassar/* 4172445Sassar * fetch the server from `t', returning the name in malloced memory in 4272445Sassar * `spn' and the entry itself in `server' 4372445Sassar */ 4472445Sassar 4572445Sassarstatic krb5_error_code 4672445Sassarfetch_server (const Ticket *t, 4772445Sassar char **spn, 4872445Sassar hdb_entry **server, 4972445Sassar const char *from) 5072445Sassar{ 5172445Sassar krb5_error_code ret; 5272445Sassar krb5_principal sprinc; 5372445Sassar 5472445Sassar ret = principalname2krb5_principal(&sprinc, t->sname, t->realm); 5572445Sassar if (ret) { 5672445Sassar kdc_log(0, "principalname2krb5_principal: %s", 5772445Sassar krb5_get_err_text(context, ret)); 5872445Sassar return ret; 5972445Sassar } 6072445Sassar ret = krb5_unparse_name(context, sprinc, spn); 6172445Sassar if (ret) { 6272445Sassar krb5_free_principal(context, sprinc); 6372445Sassar kdc_log(0, "krb5_unparse_name: %s", krb5_get_err_text(context, ret)); 6472445Sassar return ret; 6572445Sassar } 6672445Sassar ret = db_fetch(sprinc, server); 6772445Sassar krb5_free_principal(context, sprinc); 6872445Sassar if (ret) { 6972445Sassar kdc_log(0, 7072445Sassar "Request to convert ticket from %s for unknown principal %s: %s", 7172445Sassar from, *spn, krb5_get_err_text(context, ret)); 72102644Snectar if (ret == HDB_ERR_NOENTRY) 7372445Sassar ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 7472445Sassar return ret; 7572445Sassar } 7672445Sassar return 0; 7772445Sassar} 7872445Sassar 7972445Sassarstatic krb5_error_code 8072445Sassarlog_524 (const EncTicketPart *et, 8172445Sassar const char *from, 8272445Sassar const char *spn) 8372445Sassar{ 8472445Sassar krb5_principal client; 8572445Sassar char *cpn; 8672445Sassar krb5_error_code ret; 8772445Sassar 8872445Sassar ret = principalname2krb5_principal(&client, et->cname, et->crealm); 8972445Sassar if (ret) { 9072445Sassar kdc_log(0, "principalname2krb5_principal: %s", 9172445Sassar krb5_get_err_text (context, ret)); 9272445Sassar return ret; 9372445Sassar } 9472445Sassar ret = krb5_unparse_name(context, client, &cpn); 9572445Sassar if (ret) { 9672445Sassar krb5_free_principal(context, client); 9772445Sassar kdc_log(0, "krb5_unparse_name: %s", 9872445Sassar krb5_get_err_text (context, ret)); 9972445Sassar return ret; 10072445Sassar } 10172445Sassar kdc_log(1, "524-REQ %s from %s for %s", cpn, from, spn); 10272445Sassar free(cpn); 10372445Sassar krb5_free_principal(context, client); 10472445Sassar return 0; 10572445Sassar} 10672445Sassar 10772445Sassarstatic krb5_error_code 10872445Sassarverify_flags (const EncTicketPart *et, 10972445Sassar const char *spn) 11072445Sassar{ 11172445Sassar if(et->endtime < kdc_time){ 11272445Sassar kdc_log(0, "Ticket expired (%s)", spn); 11372445Sassar return KRB5KRB_AP_ERR_TKT_EXPIRED; 11472445Sassar } 11572445Sassar if(et->flags.invalid){ 11672445Sassar kdc_log(0, "Ticket not valid (%s)", spn); 11772445Sassar return KRB5KRB_AP_ERR_TKT_NYV; 11872445Sassar } 11972445Sassar return 0; 12072445Sassar} 12172445Sassar 12272445Sassar/* 12372445Sassar * set the `et->caddr' to the most appropriate address to use, where 12472445Sassar * `addr' is the address the request was received from. 12572445Sassar */ 12672445Sassar 12772445Sassarstatic krb5_error_code 12872445Sassarset_address (EncTicketPart *et, 12972445Sassar struct sockaddr *addr, 13072445Sassar const char *from) 13172445Sassar{ 13272445Sassar krb5_error_code ret; 13372445Sassar krb5_address *v4_addr; 13472445Sassar 13572445Sassar v4_addr = malloc (sizeof(*v4_addr)); 13672445Sassar if (v4_addr == NULL) 13772445Sassar return ENOMEM; 13872445Sassar 13978527Sassar ret = krb5_sockaddr2address(context, addr, v4_addr); 14072445Sassar if(ret) { 14172445Sassar free (v4_addr); 14272445Sassar kdc_log(0, "Failed to convert address (%s)", from); 14372445Sassar return ret; 14472445Sassar } 14572445Sassar 14672445Sassar if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) { 14772445Sassar kdc_log(0, "Incorrect network address (%s)", from); 14872445Sassar krb5_free_address(context, v4_addr); 14972445Sassar free (v4_addr); 15072445Sassar return KRB5KRB_AP_ERR_BADADDR; 15172445Sassar } 15272445Sassar if(v4_addr->addr_type == KRB5_ADDRESS_INET) { 15372445Sassar /* we need to collapse the addresses in the ticket to a 15472445Sassar single address; best guess is to use the address the 15572445Sassar connection came from */ 15672445Sassar 15772445Sassar if (et->caddr != NULL) { 15872445Sassar free_HostAddresses(et->caddr); 15972445Sassar } else { 16072445Sassar et->caddr = malloc (sizeof (*et->caddr)); 16172445Sassar if (et->caddr == NULL) { 16272445Sassar krb5_free_address(context, v4_addr); 16372445Sassar free(v4_addr); 16472445Sassar return ENOMEM; 16572445Sassar } 16672445Sassar } 16772445Sassar et->caddr->val = v4_addr; 16872445Sassar et->caddr->len = 1; 16972445Sassar } else { 17072445Sassar krb5_free_address(context, v4_addr); 17172445Sassar free(v4_addr); 17272445Sassar } 17372445Sassar return 0; 17472445Sassar} 17572445Sassar 17672445Sassar/* 17772445Sassar * process a 5->4 request, based on `t', and received `from, addr', 17872445Sassar * returning the reply in `reply' 17972445Sassar */ 18072445Sassar 18155682Smarkmkrb5_error_code 18272445Sassardo_524(const Ticket *t, krb5_data *reply, 18372445Sassar const char *from, struct sockaddr *addr) 18455682Smarkm{ 18555682Smarkm krb5_error_code ret = 0; 18655682Smarkm krb5_crypto crypto; 18772445Sassar hdb_entry *server = NULL; 18855682Smarkm Key *skey; 18955682Smarkm krb5_data et_data; 19055682Smarkm EncTicketPart et; 19155682Smarkm EncryptedData ticket; 19255682Smarkm krb5_storage *sp; 19355682Smarkm char *spn = NULL; 19455682Smarkm unsigned char buf[MAX_KTXT_LEN + 4 * 4]; 19555682Smarkm size_t len; 19655682Smarkm 19772445Sassar if(!enable_524) { 19872445Sassar ret = KRB5KDC_ERR_POLICY; 19972445Sassar kdc_log(0, "Rejected ticket conversion request from %s", from); 20055682Smarkm goto out; 20155682Smarkm } 20272445Sassar 20372445Sassar ret = fetch_server (t, &spn, &server, from); 20472445Sassar if (ret) { 20572445Sassar goto out; 20672445Sassar } 20772445Sassar 20855682Smarkm ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey); 20955682Smarkm if(ret){ 21072445Sassar kdc_log(0, "No suitable key found for server (%s) from %s", spn, from); 21155682Smarkm goto out; 21255682Smarkm } 21372445Sassar ret = krb5_crypto_init(context, &skey->key, 0, &crypto); 21472445Sassar if (ret) { 21572445Sassar kdc_log(0, "krb5_crypto_init failed: %s", 21672445Sassar krb5_get_err_text(context, ret)); 21772445Sassar goto out; 21872445Sassar } 21955682Smarkm ret = krb5_decrypt_EncryptedData (context, 22055682Smarkm crypto, 22155682Smarkm KRB5_KU_TICKET, 22255682Smarkm &t->enc_part, 22355682Smarkm &et_data); 22455682Smarkm krb5_crypto_destroy(context, crypto); 22555682Smarkm if(ret){ 22655682Smarkm kdc_log(0, "Failed to decrypt ticket from %s for %s", from, spn); 22755682Smarkm goto out; 22855682Smarkm } 22955682Smarkm ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length, 23055682Smarkm &et, &len); 23155682Smarkm krb5_data_free(&et_data); 23255682Smarkm if(ret){ 23355682Smarkm kdc_log(0, "Failed to decode ticket from %s for %s", from, spn); 23455682Smarkm goto out; 23555682Smarkm } 23655682Smarkm 23772445Sassar ret = log_524 (&et, from, spn); 23872445Sassar if (ret) { 23955682Smarkm free_EncTicketPart(&et); 24055682Smarkm goto out; 24155682Smarkm } 24272445Sassar 24372445Sassar ret = verify_flags (&et, spn); 24472445Sassar if (ret) { 24555682Smarkm free_EncTicketPart(&et); 24655682Smarkm goto out; 24755682Smarkm } 24855682Smarkm 24972445Sassar ret = set_address (&et, addr, from); 25072445Sassar if (ret) { 25172445Sassar free_EncTicketPart(&et); 25272445Sassar goto out; 25355682Smarkm } 25472445Sassar ret = encode_v4_ticket(buf + sizeof(buf) - 1, sizeof(buf), 25572445Sassar &et, &t->sname, &len); 25655682Smarkm free_EncTicketPart(&et); 25755682Smarkm if(ret){ 25855682Smarkm kdc_log(0, "Failed to encode v4 ticket (%s)", spn); 25955682Smarkm goto out; 26055682Smarkm } 26190926Snectar ret = get_des_key(server, TRUE, FALSE, &skey); 26255682Smarkm if(ret){ 26390926Snectar kdc_log(0, "no suitable DES key for server (%s)", spn); 26455682Smarkm goto out; 26555682Smarkm } 26655682Smarkm ret = encrypt_v4_ticket(buf + sizeof(buf) - len, len, 26755682Smarkm skey->key.keyvalue.data, &ticket); 26855682Smarkm if(ret){ 26955682Smarkm kdc_log(0, "Failed to encrypt v4 ticket (%s)", spn); 27055682Smarkm goto out; 27155682Smarkm } 27255682Smarkmout: 27355682Smarkm /* make reply */ 27455682Smarkm memset(buf, 0, sizeof(buf)); 27555682Smarkm sp = krb5_storage_from_mem(buf, sizeof(buf)); 27655682Smarkm krb5_store_int32(sp, ret); 27755682Smarkm if(ret == 0){ 27855682Smarkm krb5_store_int32(sp, server->kvno); /* is this right? */ 27955682Smarkm krb5_store_data(sp, ticket.cipher); 28055682Smarkm /* Aargh! This is coded as a KTEXT_ST. */ 281102644Snectar krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); 28255682Smarkm krb5_store_int32(sp, 0); /* mbz */ 28355682Smarkm free_EncryptedData(&ticket); 28455682Smarkm } 28555682Smarkm ret = krb5_storage_to_data(sp, reply); 286102644Snectar reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); 28755682Smarkm krb5_storage_free(sp); 28855682Smarkm 28955682Smarkm if(spn) 29055682Smarkm free(spn); 29172445Sassar if(server) 29272445Sassar free_ent (server); 29355682Smarkm return ret; 29455682Smarkm} 29555682Smarkm 29672445Sassar#endif /* KRB4 */ 297