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