1 /*
   2  * Copyright (c) 2003, 2017, 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 
  31 package sun.security.krb5.internal.tools;
  32 
  33 import java.net.InetAddress;
  34 import sun.security.krb5.*;
  35 import sun.security.krb5.internal.*;
  36 import sun.security.krb5.internal.ccache.*;
  37 import sun.security.krb5.internal.ktab.*;
  38 import 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  */
  47 public 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].equals("-?") ||
 137                 args[i].equals("-h") ||
 138                 args[i].equals("--help")) {
 139                 printHelp();
 140                 System.exit(0);
 141             }
 142             if ((args[i].length() >= 2) && (args[i].startsWith("-"))) {
 143                 arg = Character.valueOf(args[i].charAt(1));
 144                 switch (arg.charValue()) {
 145                 case 'c':
 146                     action = 'c';
 147                     break;
 148                 case 'k':
 149                     action = 'k';
 150                     break;
 151                 case 'a':
 152                     options[2] = 'a';
 153                     break;
 154                 case 'n':
 155                     options[3] = 'n';
 156                     break;
 157                 case 'f':
 158                     options[1] = 'f';
 159                     break;
 160                 case 'e':
 161                     options[0] = 'e';
 162                     break;
 163                 case 'K':
 164                     options[1] = 'K';
 165                     break;
 166                 case 't':
 167                     options[2] = 't';
 168                     break;
 169                 default:
 170                     printHelp();
 171                     System.exit(-1);
 172                 }
 173 
 174             } else {
 175                 if (!args[i].startsWith("-") && (i == args.length - 1)) {
 176                     // the argument is the last one.
 177                     name = args[i];
 178                     arg = null;
 179                 } else {
 180                     printHelp(); // incorrect input format.
 181                     System.exit(-1);
 182                 }
 183             }
 184         }
 185     }
 186 
 187     void displayTab() {
 188         KeyTab table = (KeyTab)target;
 189         KeyTabEntry[] entries = table.getEntries();
 190         if (entries.length == 0) {
 191             System.out.println("\nKey tab: " + name +
 192                                ", " + " 0 entries found.\n");
 193         } else {
 194             if (entries.length == 1)
 195                 System.out.println("\nKey tab: " + name +
 196                                    ", " + entries.length + " entry found.\n");
 197             else
 198                 System.out.println("\nKey tab: " + name + ", " +
 199                                    entries.length + " entries found.\n");
 200             for (int i = 0; i < entries.length; i++) {
 201                 System.out.println("[" + (i + 1) + "] " +
 202                                    "Service principal: "  +
 203                                    entries[i].getService().toString());
 204                 System.out.println("\t KVNO: " +
 205                                    entries[i].getKey().getKeyVersionNumber());
 206                 if (options[0] == 'e') {
 207                     EncryptionKey key = entries[i].getKey();
 208                     System.out.println("\t Key type: " +
 209                                        key.getEType());
 210                 }
 211                 if (options[1] == 'K') {
 212                     EncryptionKey key = entries[i].getKey();
 213                     System.out.println("\t Key: " +
 214                                        entries[i].getKeyString());
 215                 }
 216                 if (options[2] == 't') {
 217                     System.out.println("\t Time stamp: " +
 218                             format(entries[i].getTimeStamp()));
 219                 }
 220             }
 221         }
 222     }
 223 
 224     void displayCache() {
 225         CredentialsCache cache = (CredentialsCache)target;
 226         sun.security.krb5.internal.ccache.Credentials[] creds =
 227             cache.getCredsList();
 228         if (creds == null) {
 229             System.out.println ("No credentials available in the cache " +
 230                                 name);
 231             System.exit(-1);
 232         }
 233         System.out.println("\nCredentials cache: " +  name);
 234         String defaultPrincipal = cache.getPrimaryPrincipal().toString();
 235         int num = creds.length;
 236 
 237         if (num == 1)
 238             System.out.println("\nDefault principal: " +
 239                                defaultPrincipal + ", " +
 240                                creds.length + " entry found.\n");
 241         else
 242             System.out.println("\nDefault principal: " +
 243                                defaultPrincipal + ", " +
 244                                creds.length + " entries found.\n");
 245         if (creds != null) {
 246             for (int i = 0; i < creds.length; i++) {
 247                 try {
 248                     String starttime;
 249                     String endtime;
 250                     String renewTill;
 251                     String servicePrincipal;
 252                     if (creds[i].getStartTime() != null) {
 253                         starttime = format(creds[i].getStartTime());
 254                     } else {
 255                         starttime = format(creds[i].getAuthTime());
 256                     }
 257                     endtime = format(creds[i].getEndTime());
 258                     servicePrincipal =
 259                         creds[i].getServicePrincipal().toString();
 260                     System.out.println("[" + (i + 1) + "] " +
 261                                        " Service Principal:  " +
 262                                        servicePrincipal);
 263                     System.out.println("     Valid starting:     " + starttime);
 264                     System.out.println("     Expires:            " + endtime);
 265                     if (creds[i].getRenewTill() != null) {
 266                         renewTill = format(creds[i].getRenewTill());
 267                         System.out.println(
 268                                 "     Renew until:        " + renewTill);
 269                     }
 270                     if (options[0] == 'e') {
 271                         String eskey = EType.toString(creds[i].getEType());
 272                         String etkt = EType.toString(creds[i].getTktEType());
 273                         System.out.println("     EType (skey, tkt):  "
 274                                 + eskey + ", " + etkt);
 275                     }
 276                     if (options[1] == 'f') {
 277                         System.out.println("     Flags:              " +
 278                                            creds[i].getTicketFlags().toString());
 279                     }
 280                     if (options[2] == 'a') {
 281                         boolean first = true;
 282                         InetAddress[] caddr
 283                                 = creds[i].setKrbCreds().getClientAddresses();
 284                         if (caddr != null) {
 285                             for (InetAddress ia: caddr) {
 286                                 String out;
 287                                 if (options[3] == 'n') {
 288                                     out = ia.getHostAddress();
 289                                 } else {
 290                                     out = ia.getCanonicalHostName();
 291                                 }
 292                                 System.out.println("     " +
 293                                         (first?"Addresses:":"          ") +
 294                                         "       " + out);
 295                                 first = false;
 296                             }
 297                         } else {
 298                             System.out.println("     [No host addresses info]");
 299                         }
 300                     }
 301                 } catch (RealmException e) {
 302                     System.out.println("Error reading principal from "+
 303                                        "the entry.");
 304                     if (DEBUG) {
 305                         e.printStackTrace();
 306                     }
 307                     System.exit(-1);
 308                 }
 309             }
 310         } else {
 311             System.out.println("\nNo entries found.");
 312         }
 313     }
 314 
 315     void displayMessage(String target) {
 316         if (name == null) {
 317             System.out.println("Default " + target + " not found.");
 318         } else {
 319             System.out.println(target + " " + name + " not found.");
 320         }
 321     }
 322     /**
 323      * Reformats the date from the form -
 324      *     dow mon dd hh:mm:ss zzz yyyy to mon/dd/yyyy hh:mm
 325      * where dow is the day of the week, mon is the month,
 326      * dd is the day of the month, hh is the hour of
 327      * the day, mm is the minute within the hour,
 328      * ss is the second within the minute, zzz is the time zone,
 329      * and yyyy is the year.
 330      * @param date the string form of Date object.
 331      */
 332     private String format(KerberosTime kt) {
 333         String date = kt.toDate().toString();
 334         return (date.substring(4, 7) + " " + date.substring(8, 10) +
 335                 ", " + date.substring(24)
 336                 + " " + date.substring(11, 19));
 337     }
 338     /**
 339      * Prints out the help information.
 340      */
 341     void printHelp() {
 342         System.out.println("\nUsage: klist " +
 343                            "[[-c] [-f] [-e] [-a [-n]]] [-k [-t] [-K]] [name]");
 344         System.out.println("   name\t name of credentials cache or " +
 345                            " keytab with the prefix. File-based cache or "
 346                            + "keytab's prefix is FILE:.");
 347         System.out.println("   -c specifies that credential cache is to be " +
 348                            "listed");
 349         System.out.println("   -k specifies that key tab is to be listed");
 350         System.out.println("   options for credentials caches:");
 351         System.out.println("\t-f \t shows credentials flags");
 352         System.out.println("\t-e \t shows the encryption type");
 353         System.out.println("\t-a \t shows addresses");
 354         System.out.println("\t  -n \t   do not reverse-resolve addresses");
 355         System.out.println("   options for keytabs:");
 356         System.out.println("\t-t \t shows keytab entry timestamps");
 357         System.out.println("\t-K \t shows keytab entry key value");
 358         System.out.println("\t-e \t shows keytab entry key type");
 359     }
 360 }