1/*
2 * Copyright (C) 1998 by the FundsXpress, INC.
3 *
4 * All rights reserved.
5 *
6 * Export of this software from the United States of America may require
7 * a specific license from the United States Government.  It is the
8 * responsibility of any person or organization contemplating export to
9 * obtain such a license before exporting.
10 *
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of FundsXpress. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission.  FundsXpress makes no representations about the suitability of
19 * this software for any purpose.  It is provided "as is" without express
20 * or implied warranty.
21 *
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 */
26
27#include "kuser_locl.h"
28
29static char *etype_str = NULL;
30static char *ccache_name = NULL;
31static char *keytab_name = NULL;
32static char *sname = NULL;
33
34static int  version_flag = 0;
35static int  help_flag = 0;
36static int  quiet_flag = 0;
37
38static void do_v5_kvno (int argc, char *argv[],
39                        char *ccache_name, char *etype_str, char *keytab_name,
40			char *sname);
41
42struct getargs args[] = {
43    { "enctype",        'e', arg_string, &etype_str,
44      NP_("Encryption type to use", ""), "enctype" },
45    { "cache",          'c', arg_string, &ccache_name,
46      NP_("Credentials cache", ""), "cachename" },
47    { "keytab",         'k', arg_string, &keytab_name,
48      NP_("Keytab to use", ""), "keytabname" },
49    { "server",         'S', arg_string, &sname,
50      NP_("Server to get ticket for", ""), "principal" },
51    { "quiet",          'q', arg_flag, &quiet_flag,
52      NP_("Quiet", "") },
53    { "version",        0, arg_flag, &version_flag },
54    { "help",           0, arg_flag, &help_flag }
55};
56
57static void
58usage(int ret)
59{
60    arg_printusage_i18n (args, sizeof(args)/sizeof(*args),
61                         N_("Usage: ", ""), NULL,
62                         "principal1 [principal2 ...]",
63                         getarg_i18n);
64    exit (ret);
65}
66
67int main(int argc, char *argv[])
68{
69    int optidx = 0;
70
71    setprogname (argv[0]);
72
73    setlocale(LC_ALL, "");
74    bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR);
75    textdomain("heimdal_kuser");
76
77    if (getarg(args, sizeof(args)/sizeof(args[0]), argc, argv, &optidx))
78        usage(1);
79
80    if (help_flag)
81        usage (0);
82
83    if (version_flag) {
84        print_version(NULL);
85        exit (0);
86    }
87
88    argc -= optidx;
89    argv += optidx;
90
91    do_v5_kvno(argc, argv, ccache_name, etype_str, keytab_name, sname);
92
93    return 0;
94}
95
96static void do_v5_kvno (int count, char *names[],
97                        char * ccache_name, char *etype_str, char *keytab_name,
98			char *sname)
99{
100    krb5_error_code ret;
101    krb5_context context = 0;
102    int i, errors;
103    krb5_enctype etype;
104    krb5_ccache ccache;
105    krb5_principal me;
106    krb5_creds in_creds, *out_creds = NULL;
107    Ticket ticket;
108    size_t len;
109    char *princ = NULL;
110    krb5_keytab keytab = NULL;
111
112    ret = krb5_init_context(&context);
113    if (ret)
114	errx(1, "krb5_init_context failed: %d", ret);
115
116    if (etype_str) {
117        ret = krb5_string_to_enctype(context, etype_str, &etype);
118	if (ret)
119	    krb5_err(context, 1, ret, "Failed to convert encryption type %s", etype_str);
120    } else {
121	etype = 0;
122    }
123
124    if (ccache_name)
125        ret = krb5_cc_resolve(context, ccache_name, &ccache);
126    else
127        ret = krb5_cc_default(context, &ccache);
128    if (ret)
129        krb5_err(context, 1, ret, "Failed to open credentials cache %s",
130                 (ccache_name) ? ccache_name : "(Default)");
131
132    if (keytab_name) {
133	ret = krb5_kt_resolve(context, keytab_name, &keytab);
134	if (ret)
135            krb5_err(context, 1, ret, "Can't resolve keytab %s", keytab_name);
136    }
137
138    ret = krb5_cc_get_principal(context, ccache, &me);
139    if (ret)
140        krb5_err(context, 1, ret, "krb5_cc_get_principal");
141
142    errors = 0;
143
144    for (i = 0; i < count; i++) {
145	memset(&in_creds, 0, sizeof(in_creds));
146        memset(&ticket, 0, sizeof(ticket));
147
148	in_creds.client = me;
149
150	if (sname != NULL) {
151	    ret = krb5_sname_to_principal(context, names[i],
152					  sname, KRB5_NT_SRV_HST,
153					  &in_creds.server);
154	} else {
155	    ret = krb5_parse_name(context, names[i], &in_creds.server);
156	}
157	if (ret) {
158	    if (!quiet_flag)
159                krb5_warn(context, ret, "Couldn't parse principal name %s", names[i]);
160            errors++;
161	    continue;
162	}
163
164	ret = krb5_unparse_name(context, in_creds.server, &princ);
165	if (ret) {
166            krb5_warn(context, ret, "Couldn't format parsed principal name for '%s'",
167                      names[i]);
168	    errors++;
169            goto next;
170	}
171
172	in_creds.session.keytype = etype;
173
174	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
175
176	if (ret) {
177            krb5_warn(context, ret, "Couldn't get credentials for %s", princ);
178	    errors++;
179	    goto next;
180	}
181
182	ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length,
183                            &ticket, &len);
184	if (ret) {
185	    krb5_err(context, 1, ret, "Can't decode ticket for %s", princ);
186	    errors++;
187            goto next;
188	    continue;
189	}
190
191	if (keytab) {
192            krb5_keytab_entry   kte;
193            krb5_crypto         crypto;
194            krb5_data           dec_data;
195            EncTicketPart       decr_part;
196
197            ret = krb5_kt_get_entry(context, keytab, in_creds.server,
198                                    (ticket.enc_part.kvno != NULL)?
199                                    *ticket.enc_part.kvno : 0,
200                                    ticket.enc_part.etype,
201                                    &kte);
202            if (ret) {
203                krb5_warn(context, ret, "Can't decrypt ticket for %s", princ);
204                if (!quiet_flag)
205                    printf("%s: kvno = %d, keytab entry invalid", princ,
206                           (ticket.enc_part.kvno != NULL)?
207                           *ticket.enc_part.kvno : 0);
208                errors ++;
209                goto next;
210            }
211
212            ret = krb5_crypto_init(context, &kte.keyblock, 0, &crypto);
213            if (ret) {
214                krb5_warn(context, ret, "krb5_crypto_init");
215                errors ++;
216                krb5_kt_free_entry(context, &kte);
217                goto next;
218            }
219
220            ret = krb5_decrypt_EncryptedData (context, crypto, KRB5_KU_TICKET,
221                                              &ticket.enc_part, &dec_data);
222            krb5_crypto_destroy(context, crypto);
223            krb5_kt_free_entry(context, &kte);
224
225            if (ret) {
226                krb5_warn(context, ret, "krb5_decrypt_EncryptedData");
227                errors ++;
228                goto next;
229            }
230
231            ret = decode_EncTicketPart(dec_data.data, dec_data.length,
232                                       &decr_part, &len);
233            krb5_data_free(&dec_data);
234            if (ret) {
235                krb5_warn(context, ret, "decode_EncTicketPart");
236                errors ++;
237                goto next;
238            }
239
240            if (!quiet_flag)
241		printf("%s: kvno = %d, keytab entry valid\n", princ,
242                       (ticket.enc_part.kvno != NULL)?
243                       *ticket.enc_part.kvno : 0);
244
245            free_EncTicketPart(&decr_part);
246	} else {
247	    if (!quiet_flag)
248		printf("%s: kvno = %d\n", princ,
249                       (ticket.enc_part.kvno != NULL)? *ticket.enc_part.kvno : 0);
250	}
251
252    next:
253        if (out_creds) {
254            krb5_free_creds(context, out_creds);
255            out_creds = NULL;
256        }
257
258        if (princ) {
259            krb5_free_unparsed_name(context, princ);
260            princ = NULL;
261        }
262
263	krb5_free_principal(context, in_creds.server);
264
265        free_Ticket(&ticket);
266    }
267
268    if (keytab)
269	krb5_kt_close(context, keytab);
270    krb5_free_principal(context, me);
271    krb5_cc_close(context, ccache);
272    krb5_free_context(context);
273
274    if (errors)
275	exit(1);
276
277    exit(0);
278}
279