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].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 }