1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
28 *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
29 */
30
31package sun.security.krb5.internal.tools;
32
33import java.net.InetAddress;
34import sun.security.krb5.*;
35import sun.security.krb5.internal.*;
36import sun.security.krb5.internal.ccache.*;
37import sun.security.krb5.internal.ktab.*;
38import sun.security.krb5.internal.crypto.EType;
39
40/**
41 * This class can execute as a command-line tool to list entries in
42 * credential cache and key tab.
43 *
44 * @author Yanni Zhang
45 * @author Ram Marti
46 */
47public class Klist {
48    Object target;
49    // for credentials cache, options are 'f', 'e', 'a' and 'n';
50    // for  keytab, optionsare 't' and 'K' and 'e'
51    char[] options = new char[4];
52    String name;       // the name of credentials cache and keytable.
53    char action;       // actions would be 'c' for credentials cache
54    // and 'k' for keytable.
55    private static boolean DEBUG = Krb5.DEBUG;
56
57    /**
58     * The main program that can be invoked at command line.
59     * <br>Usage: klist
60     * [[-c] [-f] [-e] [-a [-n]]] [-k [-t] [-K]] [name]
61     * -c specifies that credential cache is to be listed
62     * -k specifies that key tab is to be listed
63     * name name of the credentials cache or keytab
64     * <br>available options for credential caches:
65     * <ul>
66     * <li><b>-f</b>  shows credentials flags
67     * <li><b>-e</b>  shows the encryption type
68     * <li><b>-a</b>  shows addresses
69     * <li><b>-n</b>  do not reverse-resolve addresses
70     * </ul>
71     * available options for keytabs:
72     * <ul>
73     * <li><b>-t</b> shows keytab entry timestamps
74     * <li><b>-K</b> shows keytab entry DES keys
75     * </ul>
76     */
77    public static void main(String[] args) {
78        Klist klist = new Klist();
79        if ((args == null) || (args.length == 0)) {
80            klist.action = 'c'; // default will list default credentials cache.
81        } else {
82            klist.processArgs(args);
83        }
84        switch (klist.action) {
85        case 'c':
86            if (klist.name == null) {
87                klist.target = CredentialsCache.getInstance();
88                klist.name = CredentialsCache.cacheName();
89            } else
90                klist.target = CredentialsCache.getInstance(klist.name);
91
92            if (klist.target != null)  {
93                klist.displayCache();
94            } else {
95                klist.displayMessage("Credentials cache");
96                System.exit(-1);
97            }
98            break;
99        case 'k':
100            KeyTab ktab = KeyTab.getInstance(klist.name);
101            if (ktab.isMissing()) {
102                System.out.println("KeyTab " + klist.name + " not found.");
103                System.exit(-1);
104            } else if (!ktab.isValid()) {
105                System.out.println("KeyTab " + klist.name
106                        + " format not supported.");
107                System.exit(-1);
108            }
109            klist.target = ktab;
110            klist.name = ktab.tabName();
111            klist.displayTab();
112            break;
113        default:
114            if (klist.name != null) {
115                klist.printHelp();
116                System.exit(-1);
117            } else {
118                klist.target = CredentialsCache.getInstance();
119                klist.name = CredentialsCache.cacheName();
120                if (klist.target != null) {
121                    klist.displayCache();
122                } else {
123                    klist.displayMessage("Credentials cache");
124                    System.exit(-1);
125                }
126            }
127        }
128    }
129
130    /**
131     * Parses the command line arguments.
132     */
133    void processArgs(String[] args) {
134        Character arg;
135        for (int i = 0; i < args.length; i++) {
136            if ((args[i].length() >= 2) && (args[i].startsWith("-"))) {
137                arg = Character.valueOf(args[i].charAt(1));
138                switch (arg.charValue()) {
139                case 'c':
140                    action = 'c';
141                    break;
142                case 'k':
143                    action = 'k';
144                    break;
145                case 'a':
146                    options[2] = 'a';
147                    break;
148                case 'n':
149                    options[3] = 'n';
150                    break;
151                case 'f':
152                    options[1] = 'f';
153                    break;
154                case 'e':
155                    options[0] = 'e';
156                    break;
157                case 'K':
158                    options[1] = 'K';
159                    break;
160                case 't':
161                    options[2] = 't';
162                    break;
163                default:
164                    printHelp();
165                    System.exit(-1);
166                }
167
168            } else {
169                if (!args[i].startsWith("-") && (i == args.length - 1)) {
170                    // the argument is the last one.
171                    name = args[i];
172                    arg = null;
173                } else {
174                    printHelp(); // incorrect input format.
175                    System.exit(-1);
176                }
177            }
178        }
179    }
180
181    void displayTab() {
182        KeyTab table = (KeyTab)target;
183        KeyTabEntry[] entries = table.getEntries();
184        if (entries.length == 0) {
185            System.out.println("\nKey tab: " + name +
186                               ", " + " 0 entries found.\n");
187        } else {
188            if (entries.length == 1)
189                System.out.println("\nKey tab: " + name +
190                                   ", " + entries.length + " entry found.\n");
191            else
192                System.out.println("\nKey tab: " + name + ", " +
193                                   entries.length + " entries found.\n");
194            for (int i = 0; i < entries.length; i++) {
195                System.out.println("[" + (i + 1) + "] " +
196                                   "Service principal: "  +
197                                   entries[i].getService().toString());
198                System.out.println("\t KVNO: " +
199                                   entries[i].getKey().getKeyVersionNumber());
200                if (options[0] == 'e') {
201                    EncryptionKey key = entries[i].getKey();
202                    System.out.println("\t Key type: " +
203                                       key.getEType());
204                }
205                if (options[1] == 'K') {
206                    EncryptionKey key = entries[i].getKey();
207                    System.out.println("\t Key: " +
208                                       entries[i].getKeyString());
209                }
210                if (options[2] == 't') {
211                    System.out.println("\t Time stamp: " +
212                            format(entries[i].getTimeStamp()));
213                }
214            }
215        }
216    }
217
218    void displayCache() {
219        CredentialsCache cache = (CredentialsCache)target;
220        sun.security.krb5.internal.ccache.Credentials[] creds =
221            cache.getCredsList();
222        if (creds == null) {
223            System.out.println ("No credentials available in the cache " +
224                                name);
225            System.exit(-1);
226        }
227        System.out.println("\nCredentials cache: " +  name);
228        String defaultPrincipal = cache.getPrimaryPrincipal().toString();
229        int num = creds.length;
230
231        if (num == 1)
232            System.out.println("\nDefault principal: " +
233                               defaultPrincipal + ", " +
234                               creds.length + " entry found.\n");
235        else
236            System.out.println("\nDefault principal: " +
237                               defaultPrincipal + ", " +
238                               creds.length + " entries found.\n");
239        if (creds != null) {
240            for (int i = 0; i < creds.length; i++) {
241                try {
242                    String starttime;
243                    String endtime;
244                    String renewTill;
245                    String servicePrincipal;
246                    if (creds[i].getStartTime() != null) {
247                        starttime = format(creds[i].getStartTime());
248                    } else {
249                        starttime = format(creds[i].getAuthTime());
250                    }
251                    endtime = format(creds[i].getEndTime());
252                    servicePrincipal =
253                        creds[i].getServicePrincipal().toString();
254                    System.out.println("[" + (i + 1) + "] " +
255                                       " Service Principal:  " +
256                                       servicePrincipal);
257                    System.out.println("     Valid starting:     " + starttime);
258                    System.out.println("     Expires:            " + endtime);
259                    if (creds[i].getRenewTill() != null) {
260                        renewTill = format(creds[i].getRenewTill());
261                        System.out.println(
262                                "     Renew until:        " + renewTill);
263                    }
264                    if (options[0] == 'e') {
265                        String eskey = EType.toString(creds[i].getEType());
266                        String etkt = EType.toString(creds[i].getTktEType());
267                        System.out.println("     EType (skey, tkt):  "
268                                + eskey + ", " + etkt);
269                    }
270                    if (options[1] == 'f') {
271                        System.out.println("     Flags:              " +
272                                           creds[i].getTicketFlags().toString());
273                    }
274                    if (options[2] == 'a') {
275                        boolean first = true;
276                        InetAddress[] caddr
277                                = creds[i].setKrbCreds().getClientAddresses();
278                        if (caddr != null) {
279                            for (InetAddress ia: caddr) {
280                                String out;
281                                if (options[3] == 'n') {
282                                    out = ia.getHostAddress();
283                                } else {
284                                    out = ia.getCanonicalHostName();
285                                }
286                                System.out.println("     " +
287                                        (first?"Addresses:":"          ") +
288                                        "       " + out);
289                                first = false;
290                            }
291                        } else {
292                            System.out.println("     [No host addresses info]");
293                        }
294                    }
295                } catch (RealmException e) {
296                    System.out.println("Error reading principal from "+
297                                       "the entry.");
298                    if (DEBUG) {
299                        e.printStackTrace();
300                    }
301                    System.exit(-1);
302                }
303            }
304        } else {
305            System.out.println("\nNo entries found.");
306        }
307    }
308
309    void displayMessage(String target) {
310        if (name == null) {
311            System.out.println("Default " + target + " not found.");
312        } else {
313            System.out.println(target + " " + name + " not found.");
314        }
315    }
316    /**
317     * Reformats the date from the form -
318     *     dow mon dd hh:mm:ss zzz yyyy to mon/dd/yyyy hh:mm
319     * where dow is the day of the week, mon is the month,
320     * dd is the day of the month, hh is the hour of
321     * the day, mm is the minute within the hour,
322     * ss is the second within the minute, zzz is the time zone,
323     * and yyyy is the year.
324     * @param date the string form of Date object.
325     */
326    private String format(KerberosTime kt) {
327        String date = kt.toDate().toString();
328        return (date.substring(4, 7) + " " + date.substring(8, 10) +
329                ", " + date.substring(24)
330                + " " + date.substring(11, 19));
331    }
332    /**
333     * Prints out the help information.
334     */
335    void printHelp() {
336        System.out.println("\nUsage: klist " +
337                           "[[-c] [-f] [-e] [-a [-n]]] [-k [-t] [-K]] [name]");
338        System.out.println("   name\t name of credentials cache or " +
339                           " keytab with the prefix. File-based cache or "
340                           + "keytab's prefix is FILE:.");
341        System.out.println("   -c specifies that credential cache is to be " +
342                           "listed");
343        System.out.println("   -k specifies that key tab is to be listed");
344        System.out.println("   options for credentials caches:");
345        System.out.println("\t-f \t shows credentials flags");
346        System.out.println("\t-e \t shows the encryption type");
347        System.out.println("\t-a \t shows addresses");
348        System.out.println("\t  -n \t   do not reverse-resolve addresses");
349        System.out.println("   options for keytabs:");
350        System.out.println("\t-t \t shows keytab entry timestamps");
351        System.out.println("\t-K \t shows keytab entry key value");
352        System.out.println("\t-e \t shows keytab entry key type");
353        System.out.println("\nUsage: java sun.security.krb5.tools.Klist " +
354                           "-help for help.");
355    }
356}
357