From 6ec3976304f444446f8eeace967365128ec3c421 Mon Sep 17 00:00:00 2001 From: Derrick Brashear Date: Wed, 12 Sep 2007 19:19:45 +0000 Subject: [PATCH] STABLE14-aklog-kimpersonate-20070912 inline kimpersonate support, to make testing easier. (cherry picked from commit a6d7cacfdca82815af2cc0fda570340802a73dc3) --- src/aklog/aklog_main.c | 529 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 490 insertions(+), 39 deletions(-) diff --git a/src/aklog/aklog_main.c b/src/aklog/aklog_main.c index 1760b359b..6a6e05467 100644 --- a/src/aklog/aklog_main.c +++ b/src/aklog/aklog_main.c @@ -4,6 +4,35 @@ * Copyright 1990,1991 by the Massachusetts Institute of Technology * For distribution and copying rights, see the file "mit-copyright.h" */ +/* + * Copyright (c) 2005, 2006 + * The Linux Box Corporation + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of the Linux Box + * Corporation is not used in any advertising or publicity + * pertaining to the use or distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * Linux Box Corporation is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * This software is provided as is, without representation + * from the Linux Box Corporation as to its fitness for any + * purpose, and without warranty by the Linux Box Corporation + * of any kind, either express or implied, including + * without limitation the implied warranties of + * merchantability and fitness for a particular purpose. The + * regents of the Linux Box Corporation shall not be liable + * for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising + * out of or in connection with the use of the software, even + * if it has been or is hereafter advised of the possibility of + * such damages. + */ #if !defined(lint) && !defined(SABER) static char *rcsid = @@ -39,27 +68,6 @@ static char *rcsid = #include #endif /* WINDOWS */ -/* on AIX AFS has an unresolved reference to osi_audit. We will define - * it here as extern. It also trys to call the ntohl and htonl routines - * as routines rather then macros. We need a real routine here. - * We do this before the ntohl and htonl macros are defined in net/in.h - */ -int osi_audit() - { return(0);} - -#if 0 -#ifdef _AIX -u_long htonl(u_long x) - { return(x);} - -u_long ntohl(u_long x) - { return(x);} -#endif - -#include -/* #include */ -#endif /* 0 */ - #include #include @@ -90,6 +98,13 @@ u_long ntohl(u_long x) #include "aklog.h" #include "linked_list.h" +#ifdef HAVE_KRB5_CREDS_KEYBLOCK +#define USING_MIT 1 +#endif +#ifdef HAVE_KRB5_CREDS_SESSION +#define USING_HEIMDAL 1 +#endif + #define AFSKEY "afs" #define AFSINST "" @@ -184,6 +199,41 @@ static int get_user_realm(krb5_context, char *); #error "Must have either krb5_princ_size or krb5_principal_get_comp_string" #endif +#if !defined(HAVE_KRB5_ENCRYPT_TKT_PART) +krb5_error_code +krb5_encrypt_tkt_part(krb5_context context, + const krb5_keyblock *key, + krb5_ticket *ticket) +{ + krb5_data *data = 0; + int code; + size_t enclen; + + if ((code = encode_krb5_enc_tkt_part(ticket->enc_part2, &data))) + goto Done; + if ((code = krb5_c_encrypt_length(context, key->enctype, + data->length, &enclen))) + goto Done; + ticket->enc_part.ciphertext.length = enclen; + if (!(ticket->enc_part.ciphertext.data = malloc(enclen))) { + code = ENOMEM; + goto Done; + } + if ((code = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_KDC_REP_TICKET, + 0, data, &ticket->enc_part))) { + free(ticket->enc_part.ciphertext.data); + ticket->enc_part.ciphertext.data = 0; + } +Done: + if (data) { + if (data->data) + free(data->data); + free(data); + } + return code; +} +#endif + #if defined(HAVE_KRB5_CREDS_KEYBLOCK) #define get_cred_keydata(c) c->keyblock.contents @@ -206,6 +256,50 @@ static int get_user_realm(krb5_context, char *); #define HAVE_NO_KRB5_524 #endif +#if USING_HEIMDAL +#define deref_keyblock_enctype(kb) \ + ((kb)->keytype) + +#define deref_entry_keyblock(entry) \ + entry->keyblock + +#define deref_session_key(creds) \ + creds->session + +#define deref_enc_tkt_addrs(tkt) \ + tkt->caddr + +#define deref_enc_length(enc) \ + ((enc)->cipher.length) + +#define deref_enc_data(enc) \ + ((enc)->cipher.data) + +#define krb5_free_keytab_entry_contents krb5_kt_free_entry + +#else +#define deref_keyblock_enctype(kb) \ + ((kb)->enctype) + +#define deref_entry_keyblock(entry) \ + entry->key + +#define deref_session_key(creds) \ + creds->keyblock + +#define deref_enc_tkt_addrs(tkt) \ + tkt->caddrs + +#define deref_enc_length(enc) \ + ((enc)->ciphertext.length) + +#define deref_enc_data(enc) \ + ((enc)->ciphertext.data) + +#endif + +#define deref_entry_enctype(entry) \ + deref_keyblock_enctype(&deref_entry_keyblock(entry)) #endif /* WINDOWS */ /* @@ -223,10 +317,12 @@ static int noauth = FALSE; /* If true, don't try to get tokens */ static int zsubs = FALSE; /* Are we keeping track of zephyr subs? */ static int hosts = FALSE; /* Are we keeping track of hosts? */ static int noprdb = FALSE; /* Skip resolving name to id? */ -static int linked = FALSE; /* try for both AFS nodes */ -static int afssetpag = FALSE; /* setpag for AFS */ +static int linked = FALSE; /* try for both AFS nodes */ +static int afssetpag = FALSE; /* setpag for AFS */ static int force = FALSE; /* Bash identical tokens? */ static int do524 = FALSE; /* Should we do 524 instead of rxkad2b? */ +static char *keytab = NULL; /* keytab for akimpersonate */ +static char *client = NULL; /* client principal for akimpersonate */ static linked_list zsublist; /* List of zephyr subscriptions */ static linked_list hostlist; /* List of host addresses */ static linked_list authedcells; /* List of cells already logged to */ @@ -1321,6 +1417,18 @@ void aklog(int argc, char *argv[]) } else usage(); + else if ((strcmp(argv[i], "-keytab") == 0)) + if (++i < argc) { + keytab = argv[i]; + } + else + usage(); + else if ((strcmp(argv[i], "-principal") == 0)) + if (++i < argc) { + client = argv[i]; + } + else + usage(); else if (((strcmp(argv[i], "-path") == 0) || (strcmp(argv[i], "-p") == 0)) && !cmode) #ifndef WINDOWS @@ -1572,23 +1680,340 @@ static int isdir(char *path, unsigned char *val) } } +static krb5_error_code get_credv5_akimpersonate(krb5_context context, + char* keytab, + krb5_principal service_principal, + krb5_principal client_principal, + time_t starttime, + time_t endtime, + int *allowed_enctypes, + int *paddress, + krb5_creds** out_creds /* out */ ) +{ + krb5_error_code code; + krb5_keytab kt = 0; + krb5_kt_cursor cursor[1]; + krb5_keytab_entry entry[1]; + krb5_ccache cc = 0; + krb5_creds *creds = 0; + krb5_enctype enctype; + krb5_kvno kvno; + krb5_keyblock session_key[1]; +#if USING_HEIMDAL + Ticket ticket_reply[1]; + EncTicketPart enc_tkt_reply[1]; + krb5_address address[30]; + krb5_addresses faddr[1]; + int temp_vno[1]; + time_t temp_time[2]; +#else + krb5_ticket ticket_reply[1]; + krb5_enc_tkt_part enc_tkt_reply[1]; + krb5_address address[30], *faddr[30]; +#endif + krb5_data * temp; + int i; + static int any_enctype[] = {0}; + *out_creds = 0; + if (!(creds = malloc(sizeof *creds))) { + code = ENOMEM; + goto cleanup; + } + if (!allowed_enctypes) + allowed_enctypes = any_enctype; + + cc = 0; + enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */ + kvno = 0; /* AKIMPERSONATE_IGNORE_VNO */ + memset((char*)creds, 0, sizeof *creds); + memset((char*)entry, 0, sizeof *entry); + memset((char*)session_key, 0, sizeof *session_key); + memset((char*)ticket_reply, 0, sizeof *ticket_reply); + memset((char*)enc_tkt_reply, 0, sizeof *enc_tkt_reply); + code = krb5_kt_resolve(context, keytab, &kt); + if (code) { + if (keytab) + com_err(progname, code, "while resolving keytab %s", keytab); + else + com_err(progname, code, "while resolving default keytab"); + goto cleanup; + } + + if (service_principal) { + for (i = 0; (enctype = allowed_enctypes[i]) || !i; ++i) { + code = krb5_kt_get_entry(context, + kt, + service_principal, + kvno, + enctype, + entry); + if (!code) { + if (allowed_enctypes[i]) + deref_keyblock_enctype(session_key) = allowed_enctypes[i]; + break; + } + } + if (code) { + com_err(progname, code,"while scanning keytab entries"); + goto cleanup; + } + } else { + krb5_keytab_entry new[1]; + int best = -1; + memset(new, 0, sizeof *new); + if ((code == krb5_kt_start_seq_get(context, kt, cursor))) { + com_err(progname, code, "while starting keytab scan"); + goto cleanup; + } + while (!(code = krb5_kt_next_entry(context, kt, new, cursor))) { + for (i = 0; + allowed_enctypes[i] && allowed_enctypes[i] + != deref_entry_enctype(new); ++i) + ; + if ((!i || allowed_enctypes[i]) && + (best < 0 || best > i)) { + krb5_free_keytab_entry_contents(context, entry); + *entry = *new; + memset(new, 0, sizeof *new); + } else krb5_free_keytab_entry_contents(context, new); + } + if ((i = krb5_kt_end_seq_get(context, kt, cursor))) { + com_err(progname, i, "while ending keytab scan"); + code = i; + goto cleanup; + } + if (best < 0) { + com_err(progname, code, "while scanning keytab"); + goto cleanup; + } + deref_keyblock_enctype(session_key) = deref_entry_enctype(entry); + } + + /* Make Ticket */ + +#if USING_HEIMDAL + if ((code = krb5_generate_random_keyblock(context, + deref_keyblock_enctype(session_key), session_key))) { + com_err(progname, code, "while making session key"); + goto cleanup; + } + enc_tkt_reply->flags.initial = 1; + enc_tkt_reply->transited.tr_type = DOMAIN_X500_COMPRESS; + enc_tkt_reply->cname = client_principal->name; + enc_tkt_reply->crealm = client_principal->realm; + enc_tkt_reply->key = *session_key; + { + static krb5_data empty_string; + enc_tkt_reply->transited.contents = empty_string; + } + enc_tkt_reply->authtime = starttime; + enc_tkt_reply->starttime = temp_time; + *enc_tkt_reply->starttime = starttime; +#if 0 + enc_tkt_reply->renew_till = temp_time + 1; + *enc_tkt_reply->renew_till = endtime; +#endif + enc_tkt_reply->endtime = endtime; +#else + if ((code = krb5_c_make_random_key(context, + deref_keyblock_enctype(session_key), session_key))) { + com_err(progname, code, "while making session key"); + goto cleanup; + } + enc_tkt_reply->magic = KV5M_ENC_TKT_PART; +#define DATACAST (unsigned char *) + enc_tkt_reply->flags |= TKT_FLG_INITIAL; + enc_tkt_reply->transited.tr_type = KRB5_DOMAIN_X500_COMPRESS; + enc_tkt_reply->session = session_key; + enc_tkt_reply->client = client_principal; + { + static krb5_data empty_string; + enc_tkt_reply->transited.tr_contents = empty_string; + } + enc_tkt_reply->times.authtime = starttime; + enc_tkt_reply->times.starttime = starttime; /* krb524init needs this */ + enc_tkt_reply->times.endtime = endtime; +#endif /* USING_HEIMDAL */ + /* NB: We will discard address for now--ignoring caddr field + in any case. MIT branch does what it always did. */ + + if (paddress && *paddress) { + deref_enc_tkt_addrs(enc_tkt_reply) = faddr; +#if USING_HEIMDAL + faddr->len = 0; + faddr->val = address; +#endif + for (i = 0; paddress[i]; ++i) { +#if USING_HEIMDAL + address[i].addr_type = KRB5_ADDRESS_INET; + address[i].address.data = (void*)(paddress+i); + address[i].address.length = sizeof(paddress[i]); +#else +#if !USING_SSL + address[i].magic = KV5M_ADDRESS; + address[i].addrtype = ADDRTYPE_INET; +#else + address[i].addrtype = AF_INET; +#endif + address[i].contents = (void*)(paddress+i); + address[i].length = sizeof(int); + faddr[i] = address+i; +#endif + } +#if USING_HEIMDAL + faddr->len = i; +#else + faddr[i] = 0; +#endif + } + +#if USING_HEIMDAL + ticket_reply->sname = service_principal->name; + ticket_reply->realm = service_principal->realm; + + { /* crypto block */ + krb5_crypto crypto = 0; + unsigned char *buf = 0; + size_t buf_size, buf_len; + char *what; + + ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, + enc_tkt_reply, &buf_len, code); + if(code) { + com_err(progname, code, "while encoding ticket"); + goto cleanup; + } + + if(buf_len != buf_size) { + com_err(progname, code, + "%d != %d while encoding ticket (internal ASN.1 encoder error", + buf_len, buf_size); + goto cleanup; + } + what = "krb5_crypto_init"; + code = krb5_crypto_init(context, + &deref_entry_keyblock(entry), + deref_entry_enctype(entry), + &crypto); + if(!code) { + what = "krb5_encrypt"; + code = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_TICKET, + buf, buf_len, entry->vno, &(ticket_reply->enc_part)); + } + if (buf) free(buf); + if (crypto) krb5_crypto_destroy(context, crypto); + if(code) { + com_err(progname, code, "while %s", what); + goto cleanup; + } + } /* crypto block */ + ticket_reply->enc_part.etype = deref_entry_enctype(entry); + ticket_reply->enc_part.kvno = temp_vno; + *ticket_reply->enc_part.kvno = entry->vno; + ticket_reply->tkt_vno = 5; +#else + ticket_reply->server = service_principal; + ticket_reply->enc_part2 = enc_tkt_reply; + if ((code = krb5_encrypt_tkt_part(context, &deref_entry_keyblock(entry), ticket_reply))) { + com_err(progname, code, "while making ticket"); + goto cleanup; + } + ticket_reply->enc_part.kvno = entry->vno; +#endif + + /* Construct Creds */ + + if ((code = krb5_copy_principal(context, service_principal, + &creds->server))) { + com_err(progname, code, "while copying service principal"); + goto cleanup; + } + if ((code = krb5_copy_principal(context, client_principal, + &creds->client))) { + com_err(progname, code, "while copying client principal"); + goto cleanup; + } + if ((code = krb5_copy_keyblock_contents(context, session_key, + &deref_session_key(creds)))) { + com_err(progname, code, "while copying session key"); + goto cleanup; + } + +#if USING_HEIMDAL + creds->times.authtime = enc_tkt_reply->authtime; + creds->times.starttime = *(enc_tkt_reply->starttime); + creds->times.endtime = enc_tkt_reply->endtime; + creds->times.renew_till = 0; /* *(enc_tkt_reply->renew_till) */ + creds->flags.b = enc_tkt_reply->flags; +#else + creds->times = enc_tkt_reply->times; + creds->ticket_flags = enc_tkt_reply->flags; +#endif + if (!deref_enc_tkt_addrs(enc_tkt_reply)) + ; + else if ((code = krb5_copy_addresses(context, + deref_enc_tkt_addrs(enc_tkt_reply), &creds->addresses))) { + com_err(progname, code, "while copying addresses"); + goto cleanup; + } + +#if USING_HEIMDAL + { + size_t creds_tkt_len; + ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, + ticket_reply, &creds_tkt_len, code); + if(code) { + com_err(progname, code, "while encoding ticket"); + goto cleanup; + } + } +#else + if ((code = encode_krb5_ticket(ticket_reply, &temp))) { + com_err(progname, code, "while encoding ticket"); + goto cleanup; + } + creds->ticket = *temp; + free(temp); +#endif + /* return creds */ + *out_creds = creds; + creds = 0; +cleanup: + if (deref_enc_data(&ticket_reply->enc_part)) + free(deref_enc_data(&ticket_reply->enc_part)); + krb5_free_keytab_entry_contents(context, entry); + if (client_principal) + krb5_free_principal(context, client_principal); + if (service_principal) + krb5_free_principal(context, service_principal); + if (cc) + krb5_cc_close(context, cc); + if (kt) + krb5_kt_close(context, kt); + if (creds) krb5_free_creds(context, creds); + krb5_free_keyblock_contents(context, session_key); +out: + return code; +} + static krb5_error_code get_credv5(krb5_context context, - char *name, char *inst, char *realm, - krb5_creds **creds) + char *name, char *inst, char *realm, + krb5_creds **creds) { krb5_creds increds; krb5_error_code r; static krb5_principal client_principal = 0; - + memset((char *)&increds, 0, sizeof(increds)); /* ANL - instance may be ptr to a null string. Pass null then */ if ((r = krb5_build_principal(context, &increds.server, - strlen(realm), realm, - name, - (inst && strlen(inst)) ? inst : (void *) NULL, - (void *) NULL))) { + strlen(realm), realm, + name, + (inst && strlen(inst)) ? inst : (void *) NULL, + (void *) NULL))) { return r; } + if (!_krb425_ccache) { r = krb5_cc_default(context, &_krb425_ccache); @@ -1596,18 +2021,36 @@ static krb5_error_code get_credv5(krb5_context context, return r; } if (!client_principal) { - r = krb5_cc_get_principal(context, _krb425_ccache, &client_principal); + if (client) { + r = krb5_parse_name(context, client, &client_principal); + } else { + r = krb5_cc_get_principal(context, _krb425_ccache, &client_principal); + } if (r) return r; } - + increds.client = client_principal; increds.times.endtime = 0; - /* Ask for DES since that is what V4 understands */ + /* Ask for DES since that is what V4 understands */ get_creds_enctype((&increds)) = ENCTYPE_DES_CBC_CRC; - - r = krb5_get_credentials(context, 0, _krb425_ccache, &increds, creds); - + + if (keytab) { + int allowed_enctypes[] = { + ENCTYPE_DES_CBC_CRC, 0 + }; + + r = get_credv5_akimpersonate(context, + keytab, + increds.server, + increds.client, + 300, ((~0U)>>1), + allowed_enctypes, + 0 /* paddress */, + creds /* out */); + } else { + r = krb5_get_credentials(context, 0, _krb425_ccache, &increds, creds); + } return r; } @@ -1616,16 +2059,24 @@ static int get_user_realm(krb5_context context, char *realm) { static krb5_principal client_principal = 0; int i; + krb5_error_code r = 0; if (!_krb425_ccache) krb5_cc_default(context, &_krb425_ccache); - if (!client_principal) - krb5_cc_get_principal(context, _krb425_ccache, &client_principal); + if (!client_principal) { + if (client) { + r = krb5_parse_name(context, client, &client_principal); + } else { + r = krb5_cc_get_principal(context, _krb425_ccache, &client_principal); + } + if (r) + return r; + } i = realm_len(context, client_principal); if (i > REALM_SZ-1) i = REALM_SZ-1; strncpy(realm,realm_data(context, client_principal), i); realm[i] = 0; - return(0); + return(r); } -- 2.39.5