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