1178825Sdfr/*
2233294Sstas * Copyright (c) 2000 - 2007 Kungliga Tekniska H��gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5233294Sstas *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9233294Sstas *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12233294Sstas *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16233294Sstas *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20233294Sstas *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "kuser_locl.h"
35178825Sdfr#include <parse_units.h>
36178825Sdfr
37178825Sdfrstatic char *client_principal_str = NULL;
38178825Sdfrstatic krb5_principal client_principal;
39178825Sdfrstatic char *server_principal_str = NULL;
40178825Sdfrstatic krb5_principal server_principal;
41178825Sdfr
42178825Sdfrstatic char *ccache_str = NULL;
43178825Sdfr
44178825Sdfrstatic char *ticket_flags_str = NULL;
45178825Sdfrstatic TicketFlags ticket_flags;
46178825Sdfrstatic char *keytab_file = NULL;
47233294Sstasstatic char *enctype_string = NULL;
48178825Sdfrstatic int   expiration_time = 3600;
49178825Sdfrstatic struct getarg_strings client_addresses;
50178825Sdfrstatic int   version_flag = 0;
51178825Sdfrstatic int   help_flag = 0;
52178825Sdfrstatic int   use_krb5 = 1;
53178825Sdfr
54233294Sstasstatic const char *enc_type = "des-cbc-md5";
55233294Sstas
56178825Sdfr/*
57178825Sdfr *
58178825Sdfr */
59178825Sdfr
60178825Sdfrstatic void
61233294Sstasencode_ticket (krb5_context context,
62178825Sdfr	       EncryptionKey *skey,
63178825Sdfr	       krb5_enctype etype,
64178825Sdfr	       int skvno,
65178825Sdfr	       krb5_creds *cred)
66178825Sdfr{
67178825Sdfr    size_t len, size;
68178825Sdfr    char *buf;
69178825Sdfr    krb5_error_code ret;
70178825Sdfr    krb5_crypto crypto;
71178825Sdfr    EncryptedData enc_part;
72233294Sstas    EncTicketPart et;
73178825Sdfr    Ticket ticket;
74178825Sdfr
75178825Sdfr    memset (&enc_part, 0, sizeof(enc_part));
76178825Sdfr    memset (&ticket, 0, sizeof(ticket));
77233294Sstas
78178825Sdfr    /*
79178825Sdfr     * Set up `enc_part'
80178825Sdfr     */
81178825Sdfr
82178825Sdfr    et.flags = cred->flags.b;
83178825Sdfr    et.key = cred->session;
84233294Sstas    et.crealm = cred->client->realm;
85178825Sdfr    copy_PrincipalName(&cred->client->name, &et.cname);
86178825Sdfr    {
87178825Sdfr	krb5_data empty_string;
88233294Sstas
89233294Sstas	krb5_data_zero(&empty_string);
90178825Sdfr	et.transited.tr_type = DOMAIN_X500_COMPRESS;
91178825Sdfr	et.transited.contents = empty_string;
92178825Sdfr    }
93178825Sdfr    et.authtime = cred->times.authtime;
94178825Sdfr    et.starttime = NULL;
95178825Sdfr    et.endtime = cred->times.endtime;
96178825Sdfr    et.renew_till = NULL;
97178825Sdfr    et.caddr = &cred->addresses;
98178825Sdfr    et.authorization_data = NULL; /* XXX allow random authorization_data */
99178825Sdfr
100178825Sdfr    /*
101178825Sdfr     * Encrypt `enc_part' of ticket with service key
102178825Sdfr     */
103178825Sdfr
104178825Sdfr    ASN1_MALLOC_ENCODE(EncTicketPart, buf, len, &et, &size, ret);
105178825Sdfr    if (ret)
106178825Sdfr	krb5_err(context, 1, ret, "EncTicketPart");
107178825Sdfr
108233294Sstas    ret = krb5_crypto_init(context, skey, etype, &crypto);
109233294Sstas    if (ret)
110233294Sstas	krb5_err(context, 1, ret, "krb5_crypto_init");
111233294Sstas    ret = krb5_encrypt_EncryptedData (context,
112233294Sstas				      crypto,
113233294Sstas				      KRB5_KU_TICKET,
114233294Sstas				      buf,
115233294Sstas				      len,
116233294Sstas				      skvno,
117233294Sstas				      &ticket.enc_part);
118233294Sstas    if (ret)
119233294Sstas	krb5_err(context, 1, ret, "krb5_encrypt_EncryptedData");
120233294Sstas
121178825Sdfr    free(buf);
122178825Sdfr    krb5_crypto_destroy(context, crypto);
123178825Sdfr
124178825Sdfr    /*
125178825Sdfr     * Encode ticket
126178825Sdfr     */
127178825Sdfr
128178825Sdfr    ticket.tkt_vno = 5;
129233294Sstas    ticket.realm = cred->server->realm;
130178825Sdfr    copy_PrincipalName(&cred->server->name, &ticket.sname);
131233294Sstas
132178825Sdfr    ASN1_MALLOC_ENCODE(Ticket, buf, len, &ticket, &size, ret);
133178825Sdfr    if(ret)
134178825Sdfr	krb5_err (context, 1, ret, "encode_Ticket");
135178825Sdfr
136178825Sdfr    krb5_data_copy(&cred->ticket, buf, len);
137233294Sstas    free(buf);
138178825Sdfr}
139178825Sdfr
140178825Sdfr/*
141178825Sdfr *
142178825Sdfr */
143178825Sdfr
144178825Sdfrstatic int
145178825Sdfrcreate_krb5_tickets (krb5_context context, krb5_keytab kt)
146178825Sdfr{
147178825Sdfr    krb5_error_code ret;
148178825Sdfr    krb5_keytab_entry entry;
149178825Sdfr    krb5_creds cred;
150178825Sdfr    krb5_enctype etype;
151178825Sdfr    krb5_ccache ccache;
152233294Sstas
153178825Sdfr    memset (&cred, 0, sizeof(cred));
154233294Sstas
155178825Sdfr    ret = krb5_string_to_enctype (context, enc_type, &etype);
156178825Sdfr    if (ret)
157178825Sdfr	krb5_err (context, 1, ret, "krb5_string_to_enctype");
158233294Sstas    ret = krb5_kt_get_entry (context, kt, server_principal,
159178825Sdfr			     0, etype, &entry);
160178825Sdfr    if (ret)
161178825Sdfr	krb5_err (context, 1, ret, "krb5_kt_get_entry");
162178825Sdfr
163178825Sdfr    /*
164178825Sdfr     * setup cred
165178825Sdfr     */
166178825Sdfr
167178825Sdfr
168178825Sdfr    ret = krb5_copy_principal (context, client_principal, &cred.client);
169178825Sdfr    if (ret)
170178825Sdfr	krb5_err (context, 1, ret, "krb5_copy_principal");
171178825Sdfr    ret = krb5_copy_principal (context, server_principal, &cred.server);
172233294Sstas    if (ret)
173178825Sdfr	krb5_err (context, 1, ret, "krb5_copy_principal");
174233294Sstas    krb5_generate_random_keyblock(context, etype, &cred.session);
175178825Sdfr
176178825Sdfr    cred.times.authtime = time(NULL);
177178825Sdfr    cred.times.starttime = time(NULL);
178178825Sdfr    cred.times.endtime = time(NULL) + expiration_time;
179178825Sdfr    cred.times.renew_till = 0;
180233294Sstas    krb5_data_zero(&cred.second_ticket);
181178825Sdfr
182178825Sdfr    ret = krb5_get_all_client_addrs (context, &cred.addresses);
183178825Sdfr    if (ret)
184178825Sdfr	krb5_err (context, 1, ret, "krb5_get_all_client_addrs");
185178825Sdfr    cred.flags.b = ticket_flags;
186233294Sstas
187233294Sstas
188178825Sdfr    /*
189178825Sdfr     * Encode encrypted part of ticket
190178825Sdfr     */
191178825Sdfr
192233294Sstas    encode_ticket (context, &entry.keyblock, etype, entry.vno, &cred);
193178825Sdfr
194178825Sdfr    /*
195178825Sdfr     * Write to cc
196178825Sdfr     */
197178825Sdfr
198178825Sdfr    if (ccache_str) {
199178825Sdfr	ret = krb5_cc_resolve(context, ccache_str, &ccache);
200178825Sdfr	if (ret)
201178825Sdfr	    krb5_err (context, 1, ret, "krb5_cc_resolve");
202178825Sdfr    } else {
203178825Sdfr	ret = krb5_cc_default (context, &ccache);
204178825Sdfr	if (ret)
205178825Sdfr	    krb5_err (context, 1, ret, "krb5_cc_default");
206178825Sdfr    }
207178825Sdfr
208178825Sdfr    ret = krb5_cc_initialize (context, ccache, cred.client);
209178825Sdfr    if (ret)
210178825Sdfr	krb5_err (context, 1, ret, "krb5_cc_initialize");
211233294Sstas
212178825Sdfr    ret = krb5_cc_store_cred (context, ccache, &cred);
213178825Sdfr    if (ret)
214178825Sdfr	krb5_err (context, 1, ret, "krb5_cc_store_cred");
215178825Sdfr
216178825Sdfr    krb5_free_cred_contents (context, &cred);
217178825Sdfr    krb5_cc_close (context, ccache);
218233294Sstas
219178825Sdfr    return 0;
220178825Sdfr}
221178825Sdfr
222178825Sdfr/*
223178825Sdfr *
224178825Sdfr */
225178825Sdfr
226178825Sdfrstatic void
227178825Sdfrsetup_env (krb5_context context, krb5_keytab *kt)
228178825Sdfr{
229178825Sdfr    krb5_error_code ret;
230178825Sdfr
231178825Sdfr    if (keytab_file)
232178825Sdfr	ret = krb5_kt_resolve (context, keytab_file, kt);
233178825Sdfr    else
234178825Sdfr	ret = krb5_kt_default (context, kt);
235178825Sdfr    if (ret)
236178825Sdfr	krb5_err (context, 1, ret, "resolving keytab");
237178825Sdfr
238178825Sdfr    if (client_principal_str == NULL)
239178825Sdfr	krb5_errx (context, 1, "missing client principal");
240178825Sdfr    ret = krb5_parse_name (context, client_principal_str, &client_principal);
241178825Sdfr    if (ret)
242178825Sdfr	krb5_err (context, 1, ret, "resolvning client name");
243178825Sdfr
244178825Sdfr    if (server_principal_str == NULL)
245178825Sdfr	krb5_errx (context, 1, "missing server principal");
246178825Sdfr    ret = krb5_parse_name (context, server_principal_str, &server_principal);
247178825Sdfr    if (ret)
248178825Sdfr	krb5_err (context, 1, ret, "resolvning client name");
249178825Sdfr
250178825Sdfr    if (ticket_flags_str) {
251178825Sdfr	int ticket_flags_int;
252178825Sdfr
253233294Sstas	ticket_flags_int = parse_flags(ticket_flags_str,
254178825Sdfr				       asn1_TicketFlags_units(), 0);
255178825Sdfr	if (ticket_flags_int <= 0) {
256178825Sdfr	    krb5_warnx (context, "bad ticket flags: `%s'", ticket_flags_str);
257178825Sdfr	    print_flags_table (asn1_TicketFlags_units(), stderr);
258178825Sdfr	    exit (1);
259178825Sdfr	}
260178825Sdfr	if (ticket_flags_int)
261178825Sdfr	    ticket_flags = int2TicketFlags (ticket_flags_int);
262178825Sdfr    }
263178825Sdfr}
264178825Sdfr
265178825Sdfr/*
266178825Sdfr *
267178825Sdfr */
268178825Sdfr
269178825Sdfrstruct getargs args[] = {
270178825Sdfr    { "ccache", 0, arg_string, &ccache_str,
271178825Sdfr      "name of kerberos 5 credential cache", "cache-name"},
272233294Sstas    { "server", 's', arg_string, &server_principal_str,
273233294Sstas      "name of server principal", NULL },
274233294Sstas    { "client", 'c', arg_string, &client_principal_str,
275233294Sstas      "name of client principal", NULL },
276178825Sdfr    { "keytab", 'k', arg_string, &keytab_file,
277233294Sstas      "name of keytab file", NULL },
278178825Sdfr    { "krb5", '5', arg_flag,	 &use_krb5,
279233294Sstas      "create a kerberos 5 ticket", NULL },
280178825Sdfr    { "expire-time", 'e', arg_integer, &expiration_time,
281233294Sstas      "lifetime of ticket in seconds", NULL },
282178825Sdfr    { "client-addresses", 'a', arg_strings, &client_addresses,
283233294Sstas      "addresses of client", NULL },
284233294Sstas    { "enc-type", 't', arg_string, 	&enctype_string,
285233294Sstas      "encryption type", NULL },
286178825Sdfr    { "ticket-flags", 'f', arg_string,   &ticket_flags_str,
287233294Sstas      "ticket flags for krb5 ticket", NULL },
288178825Sdfr    { "version", 0,  arg_flag,		&version_flag,	"Print version",
289178825Sdfr      NULL },
290178825Sdfr    { "help",	 0,  arg_flag,		&help_flag,	NULL,
291178825Sdfr      NULL }
292178825Sdfr};
293178825Sdfr
294178825Sdfrstatic void
295178825Sdfrusage (int ret)
296178825Sdfr{
297178825Sdfr    arg_printusage (args,
298178825Sdfr		    sizeof(args) / sizeof(args[0]),
299178825Sdfr		    NULL,
300178825Sdfr		    "");
301178825Sdfr    exit (ret);
302178825Sdfr}
303178825Sdfr
304178825Sdfrint
305178825Sdfrmain (int argc, char **argv)
306178825Sdfr{
307233294Sstas    int optidx = 0;
308178825Sdfr    krb5_error_code ret;
309178825Sdfr    krb5_context context;
310178825Sdfr    krb5_keytab kt;
311178825Sdfr
312178825Sdfr    setprogname (argv[0]);
313178825Sdfr
314178825Sdfr    ret = krb5_init_context (&context);
315178825Sdfr    if (ret)
316178825Sdfr	errx(1, "krb5_init_context failed: %u", ret);
317178825Sdfr
318233294Sstas    if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
319233294Sstas	usage(1);
320178825Sdfr
321178825Sdfr    if (help_flag)
322233294Sstas	usage(0);
323178825Sdfr
324178825Sdfr    if (version_flag) {
325178825Sdfr	print_version(NULL);
326178825Sdfr	return 0;
327178825Sdfr    }
328178825Sdfr
329233294Sstas    if (enctype_string)
330233294Sstas	enc_type = enctype_string;
331178825Sdfr
332233294Sstas    setup_env(context, &kt);
333233294Sstas
334178825Sdfr    if (use_krb5)
335233294Sstas	create_krb5_tickets(context, kt);
336178825Sdfr
337233294Sstas    krb5_kt_close(context, kt);
338233294Sstas
339178825Sdfr    return 0;
340178825Sdfr}
341