diff --git a/kuser/Makefile.am b/kuser/Makefile.am index d0fd2f52d..7701a2fd3 100644 --- a/kuser/Makefile.am +++ b/kuser/Makefile.am @@ -4,12 +4,12 @@ include $(top_srcdir)/Makefile.am.common AM_CPPFLAGS += $(INCLUDE_krb4) $(INCLUDE_des) -I$(srcdir)/../lib/krb5 -man_MANS = kinit.1 klist.1 kdestroy.1 kgetcred.1 +man_MANS = kinit.1 klist.1 kdestroy.1 kgetcred.1 kimpersonate.1 SLC = $(top_builddir)/lib/sl/slc bin_PROGRAMS = kinit klist kdestroy kgetcred -libexec_PROGRAMS = kdigest +libexec_PROGRAMS = kdigest kimpersonate noinst_PROGRAMS = kverify kdecode_ticket generate-requests copy_cred_cache noinst_MANS = copy_cred_cache.1 @@ -26,6 +26,8 @@ kdestroy_LDADD = $(kinit_LDADD) klist_LDADD = $(kinit_LDADD) +kimpersonate_LDADD = $(kinit_LDADD) + kdigest_SOURCES = \ kdigest.c \ kdigest-commands.c diff --git a/kuser/kimpersonate.1 b/kuser/kimpersonate.1 new file mode 100644 index 000000000..14f25e1f4 --- /dev/null +++ b/kuser/kimpersonate.1 @@ -0,0 +1,152 @@ +.\" Copyright (c) 2002 - 2004, 2006 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd September 18, 2006 +.Dt KERBEROS SECTION +.Os Heimdal +.Sh NAME +.Nm kimpersonate +.Nd +impersonate a user when there exist a srvtab, keyfile or KeyFile +.Sh SYNOPSIS +.Nm +.Oo Fl s Ar string \*(Ba Xo +.Fl -server= Ns Ar string Oc +.Xc +.Oo Fl c Ar string \*(Ba Xo +.Fl -client= Ns Ar string Oc +.Xc +.Oo Fl k Ar string \*(Ba Xo +.Fl -keytab= Ns Ar string Oc +.Xc +.Op Fl 5 | Fl -krb5 +.Oo Fl e Ar integer \*(Ba Xo +.Fl -expire-time= Ns Ar integer Oc +.Xc +.Oo Fl a Ar string \*(Ba Xo +.Fl -client-address= Ns Ar string Oc +.Xc +.Oo Fl t Ar string \*(Ba Xo +.Fl -enc-type= Ns Ar string Oc +.Xc +.Oo Fl f Ar string \*(Ba Xo +.Fl -ticket-flags= Ns Ar string Oc +.Xc +.Op Fl -verbose +.Op Fl -version +.Op Fl -help +.Sh DESCRIPTION +The +.Nm +program create a "fake" ticket using the service-key of the service, +the service key can be read from a Kerberos 5 keytab, AFS KeyFile or +(if compiled with support for Kerberos 4) a Kerberos 4 srvtab. +Supported options: +.Bl -tag -width Ds +.It Xo +.Fl s Ar string Ns , +.Fl -server= Ns Ar string +.Xc +name of server principal +.It Xo +.Fl c Ar string Ns , +.Fl -client= Ns Ar string +.Xc +name of client principal +.It Xo +.Fl k Ar string Ns , +.Fl -keytab= Ns Ar string +.Xc +name of keytab file +.It Xo +.Fl 5 Ns , +.Fl -krb5 +.Xc +create a kerberos 5 ticket +.It Xo +.Fl e Ar integer Ns , +.Fl -expire-time= Ns Ar integer +.Xc +lifetime of ticket in seconds +.It Xo +.Fl a Ar string Ns , +.Fl -client-address= Ns Ar string +.Xc +address of client +.It Xo +.Fl t Ar string Ns , +.Fl -enc-type= Ns Ar string +.Xc +encryption type +.It Xo +.Fl f Ar string Ns , +.Fl -ticket-flags= Ns Ar string +.Xc +ticket flags for krb5 ticket +.It Xo +.Fl -verbose +.Xc +Verbose output +.It Xo +.Fl -version +.Xc +Print version +.It Xo +.Fl -help +.Xc +.El +.Sh FILES +Uses +.Pa /etc/krb5.keytab, +.Pa /etc/srvtab +and +.Pa /usr/afs/etc/KeyFile +when avalible and the the +.Fl k +is used with appropriate prefix. +.Sh EXAMPLES +.Nm +can be used in +.Nm samba +root preexec option +or for debugging. +.Nm +-s host/hummel.e.kth.se@E.KTH.SE -c lha@E.KTH.SE -5 +will create a Kerberos 5 ticket for lha@E.KTH.SE for the host +hummel.e.kth.se if there exist a keytab entry for it in +.Pa /etc/krb5.keytab +.Sh SEE ALSO +.Xr kinit 1 , +.Xr klist 1 +.Sh AUTHORS +Love Hörnquist Åstrand diff --git a/kuser/kimpersonate.c b/kuser/kimpersonate.c new file mode 100644 index 000000000..dd41733cb --- /dev/null +++ b/kuser/kimpersonate.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2000 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kuser_locl.h" +RCSID("$Id$"); +#include + +static char *client_principal_str = NULL; +static krb5_principal client_principal; +static char *server_principal_str = NULL; +static krb5_principal server_principal; + +static char *ccache_str = NULL; + +static char *ticket_flags_str = NULL; +static TicketFlags ticket_flags; +static char *keytab_file = NULL; +static char *enc_type = "des-cbc-md5"; +static int expiration_time = 3600; +static struct getarg_strings client_addresses; +static int version_flag = 0; +static int help_flag = 0; +static int use_krb5 = 1; + +/* + * + */ + +static void +encode_ticket (krb5_context context, + EncryptionKey *skey, + krb5_enctype etype, + int skvno, + krb5_creds *cred) +{ + size_t len, size; + char *buf; + krb5_error_code ret; + krb5_crypto crypto; + EncryptedData enc_part; + EncTicketPart et; + Ticket ticket; + + memset (&enc_part, 0, sizeof(enc_part)); + memset (&ticket, 0, sizeof(ticket)); + + /* + * Set up `enc_part' + */ + + et.flags = cred->flags.b; + et.key = cred->session; + et.crealm = *krb5_princ_realm (context, cred->client); + copy_PrincipalName(&cred->client->name, &et.cname); + { + krb5_data empty_string; + + krb5_data_zero(&empty_string); + et.transited.tr_type = DOMAIN_X500_COMPRESS; + et.transited.contents = empty_string; + } + et.authtime = cred->times.authtime; + et.starttime = NULL; + et.endtime = cred->times.endtime; + et.renew_till = NULL; + et.caddr = &cred->addresses; + et.authorization_data = NULL; /* XXX allow random authorization_data */ + + /* + * Encrypt `enc_part' of ticket with service key + */ + + ASN1_MALLOC_ENCODE(EncTicketPart, buf, len, &et, &size, ret); + if (ret) + krb5_err(context, 1, ret, "EncTicketPart"); + + krb5_crypto_init(context, skey, etype, &crypto); + krb5_encrypt_EncryptedData (context, + crypto, + KRB5_KU_TICKET, + buf, + len, + skvno, + &ticket.enc_part); + free(buf); + krb5_crypto_destroy(context, crypto); + + /* + * Encode ticket + */ + + ticket.tkt_vno = 5; + ticket.tkt_vno = skvno; + ticket.realm = *krb5_princ_realm (context, cred->server); + copy_PrincipalName(&cred->server->name, &ticket.sname); + + ASN1_MALLOC_ENCODE(Ticket, buf, len, &ticket, &size, ret); + if(ret) + krb5_err (context, 1, ret, "encode_Ticket"); + + krb5_data_copy(&cred->ticket, buf, len); +} + +/* + * + */ + +static int +create_krb5_tickets (krb5_context context, krb5_keytab kt) +{ + krb5_error_code ret; + krb5_keytab_entry entry; + krb5_creds cred; + krb5_enctype etype; + krb5_ccache ccache; + + memset (&cred, 0, sizeof(cred)); + + ret = krb5_string_to_enctype (context, enc_type, &etype); + if (ret) + krb5_err (context, 1, ret, "krb5_string_to_enctype"); + ret = krb5_kt_get_entry (context, kt, server_principal, + 0, etype, &entry); + if (ret) + krb5_err (context, 1, ret, "krb5_kt_get_entry"); + + /* + * setup cred + */ + + + ret = krb5_copy_principal (context, client_principal, &cred.client); + if (ret) + krb5_err (context, 1, ret, "krb5_copy_principal"); + ret = krb5_copy_principal (context, server_principal, &cred.server); + if (ret) + krb5_err (context, 1, ret, "krb5_copy_principal"); + krb5_generate_random_keyblock(context, etype, &cred.session); + + cred.times.authtime = time(NULL); + cred.times.starttime = time(NULL); + cred.times.endtime = time(NULL) + expiration_time; + cred.times.renew_till = 0; + krb5_data_zero(&cred.second_ticket); + + ret = krb5_get_all_client_addrs (context, &cred.addresses); + if (ret) + krb5_err (context, 1, ret, "krb5_get_all_client_addrs"); + cred.flags.b = ticket_flags; + + + /* + * Encode encrypted part of ticket + */ + + encode_ticket (context, &entry.keyblock, etype, entry.vno, &cred); + + /* + * Write to cc + */ + + if (ccache_str) { + ret = krb5_cc_resolve(context, ccache_str, &ccache); + if (ret) + krb5_err (context, 1, ret, "krb5_cc_resolve"); + } else { + ret = krb5_cc_default (context, &ccache); + if (ret) + krb5_err (context, 1, ret, "krb5_cc_default"); + } + + ret = krb5_cc_initialize (context, ccache, cred.client); + if (ret) + krb5_err (context, 1, ret, "krb5_cc_initialize"); + + ret = krb5_cc_store_cred (context, ccache, &cred); + if (ret) + krb5_err (context, 1, ret, "krb5_cc_store_cred"); + + krb5_free_creds_contents (context, &cred); + krb5_cc_close (context, ccache); + + return 0; +} + +/* + * + */ + +static void +setup_env (krb5_context context, krb5_keytab *kt) +{ + krb5_error_code ret; + + if (keytab_file) + ret = krb5_kt_resolve (context, keytab_file, kt); + else + ret = krb5_kt_default (context, kt); + if (ret) + krb5_err (context, 1, ret, "resolving keytab"); + + if (client_principal_str == NULL) + krb5_errx (context, 1, "missing client principal"); + ret = krb5_parse_name (context, client_principal_str, &client_principal); + if (ret) + krb5_err (context, 1, ret, "resolvning client name"); + + if (server_principal_str == NULL) + krb5_errx (context, 1, "missing server principal"); + ret = krb5_parse_name (context, server_principal_str, &server_principal); + if (ret) + krb5_err (context, 1, ret, "resolvning client name"); + + if (ticket_flags_str) { + int ticket_flags_int; + + ticket_flags_int = parse_flags(ticket_flags_str, + asn1_TicketFlags_units(), 0); + if (ticket_flags_int <= 0) { + krb5_warnx (context, "bad ticket flags: `%s'", ticket_flags_str); + print_flags_table (asn1_TicketFlags_units(), stderr); + exit (1); + } + if (ticket_flags_int) + ticket_flags = int2TicketFlags (ticket_flags_int); + } +} + +/* + * + */ + +struct getargs args[] = { + { "ccache", 0, arg_string, &ccache_str, + "name of kerberos 5 credential cache", "cache-name"}, + { "server", 's', arg_string, &server_principal_str, + "name of server principal" }, + { "client", 'c', arg_string, &client_principal_str, + "name of client principal" }, + { "keytab", 'k', arg_string, &keytab_file, + "name of keytab file" }, + { "krb5", '5', arg_flag, &use_krb5, + "create a kerberos 5 ticket"}, + { "expire-time", 'e', arg_integer, &expiration_time, + "lifetime of ticket in seconds" }, + { "client-addresses", 'a', arg_strings, &client_addresses, + "addresses of client" }, + { "enc-type", 't', arg_string, &enc_type, + "encryption type" }, + { "ticket-flags", 'f', arg_string, &ticket_flags_str, + "ticket flags for krb5 ticket" }, + { "version", 0, arg_flag, &version_flag, "Print version", + NULL }, + { "help", 0, arg_flag, &help_flag, NULL, + NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, + sizeof(args) / sizeof(args[0]), + NULL, + ""); + exit (ret); +} + +int +main (int argc, char **argv) +{ + int optind = 0; + krb5_error_code ret; + krb5_context context; + krb5_keytab kt; + + setprogname (argv[0]); + + ret = krb5_init_context (&context); + if (ret) + errx(1, "krb5_init_context failed: %u", ret); + + if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, + &optind)) + usage (1); + + if (help_flag) + usage (0); + + if (version_flag) { + print_version(NULL); + return 0; + } + + setup_env (context, &kt); + + if (use_krb5) + create_krb5_tickets (context, kt); + + krb5_kt_close (context, kt); + return 0; +}