--- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java Wed Oct 27 22:10:37 2010 -0700
+++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java Thu Oct 28 21:14:44 2010 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,10 +39,11 @@
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
+import java.util.Locale;
import sun.security.krb5.internal.crypto.EType;
/**
* This class can execute as a command-line tool to help the user manage
- * entires in the key table.
+ * entries in the key table.
* Available functions include list/add/update/delete service key(s).
*
* @author Yanni Zhang
@@ -60,30 +61,20 @@
int etype = -1;
char[] password = null;
+ boolean forced = false; // true if delete without prompt. Default false
+ boolean append = false; // true if new keys are appended. Default false
+ int vDel = -1; // kvno to delete, -1 all, -2 old. Default -1
+ int vAdd = -1; // kvno to add. Default -1, means auto incremented
+
/**
* The main program that can be invoked at command line.
- * <br>Usage: ktab <options>
- * <br>available options to Ktab:
- * <ul>
- * <li><b>-l [-e] [-t]</b> list the keytab name and entries, -e show
- * encryption etypes, -t show timestamps.
- * <li><b>-a</b> <<i>principal name</i>>
- * (<<i>password</i>>) add an entry to the keytab.
- * The entry is added only to the keytab. No changes are made to the
- * Kerberos database.
- * <li><b>-d</b> <<i>principal name</i>> [<<i>etype</i>>]
- * delete an entry from the keytab.
- * The entry is deleted only from the keytab. No changes are made to the
- * Kerberos database.
- * <li><b>-k</b> <<i>keytab name</i> >
- * specify keytab name and path with prefix FILE:
- * <li><b>-help</b> display instructions.
+ * See {@link #printHelp} for usages.
*/
public static void main(String[] args) {
Ktab ktab = new Ktab();
if ((args.length == 1) && (args[0].equalsIgnoreCase("-help"))) {
ktab.printHelp();
- System.exit(0);
+ return;
} else if ((args == null) || (args.length == 0)) {
ktab.action = 'l';
} else {
@@ -139,7 +130,6 @@
break;
default:
ktab.printHelp();
- System.exit(-1);
}
}
@@ -147,84 +137,129 @@
* Parses the command line arguments.
*/
void processArgs(String[] args) {
- Character arg = null;
+
+ // Commands (should appear before options):
+ // -l
+ // -a <princ>
+ // -d <princ>
+ // Options:
+ // -e <etype> (for -d)
+ // -e (for -l)
+ // -n <kvno>
+ // -k <keytab>
+ // -t
+ // -f
+ // -append
+ // Optional extra arguments:
+ // password for -a
+ // [kvno|all|old] for -d
+
+ boolean argAlreadyAppeared = false;
for (int i = 0; i < args.length; i++) {
- if ((args[i].length() == 2) && (args[i].startsWith("-"))) {
- arg = new Character(args[i].charAt(1));
- } else {
- printHelp();
- System.exit(-1);
- }
- switch (arg.charValue()) {
- case 'l':
- case 'L':
- action = 'l'; // list keytab location, name and entries
- break;
- case 'a':
- case 'A':
- action = 'a'; // add a new entry to keytab.
- i++;
- if ((i < args.length) && (!args[i].startsWith("-"))) {
- principal = args[i];
- } else {
- System.out.println("Please specify the principal name"+
- " after -a option.");
- printHelp();
- System.exit(-1);
+ if (args[i].startsWith("-")) {
+ switch (args[i].toLowerCase(Locale.US)) {
+
+ // Commands
+ case "-l": // list
+ action = 'l';
+ break;
+ case "-a": // add a new entry to keytab.
+ action = 'a';
+ if (++i >= args.length || args[i].startsWith("-")) {
+ error("A principal name must be specified after -a");
+ }
+ principal = args[i];
+ break;
+ case "-d": // delete entries
+ action = 'd';
+ if (++i >= args.length || args[i].startsWith("-")) {
+ error("A principal name must be specified after -d");
+ }
+ principal = args[i];
+ break;
+
+ // Options
+ case "-e":
+ if (action == 'l') { // list etypes
+ showEType = true;
+ } else if (action == 'd') { // delete etypes
+ if (++i >= args.length || args[i].startsWith("-")) {
+ error("An etype must be specified after -e");
+ }
+ try {
+ etype = Integer.parseInt(args[i]);
+ if (etype <= 0) {
+ throw new NumberFormatException();
+ }
+ } catch (NumberFormatException nfe) {
+ error(args[i] + " is not a valid etype");
+ }
+ } else {
+ error(args[i] + " is not valid after -" + action);
+ }
+ break;
+ case "-n": // kvno for -a
+ if (++i >= args.length || args[i].startsWith("-")) {
+ error("A KVNO must be specified after -n");
+ }
+ try {
+ vAdd = Integer.parseInt(args[i]);
+ if (vAdd < 0) {
+ throw new NumberFormatException();
+ }
+ } catch (NumberFormatException nfe) {
+ error(args[i] + " is not a valid KVNO");
+ }
+ break;
+ case "-k": // specify keytab to use
+ if (++i >= args.length || args[i].startsWith("-")) {
+ error("A keytab name must be specified after -k");
+ }
+ if (args[i].length() >= 5 &&
+ args[i].substring(0, 5).equalsIgnoreCase("FILE:")) {
+ name = args[i].substring(5);
+ } else {
+ name = args[i];
+ }
+ break;
+ case "-t": // list timestamps
+ showTime = true;
+ break;
+ case "-f": // force delete, no prompt
+ forced = true;
+ break;
+ case "-append": // -a, new keys append to file
+ append = true;
+ break;
+ default:
+ printHelp();
+ break;
}
- if ((i + 1 < args.length) &&
- (!args[i + 1].startsWith("-"))) {
- password = args[i + 1].toCharArray();
- i++;
- } else {
- password = null; // prompt user for password later.
+ } else { // optional standalone arguments
+ if (argAlreadyAppeared) {
+ error("Useless extra argument " + args[i]);
}
- break;
- case 'd':
- case 'D':
- action = 'd'; // delete an entry.
- i++;
- if ((i < args.length) && (!args[i].startsWith("-"))) {
- principal = args[i];
- int j = i + 1;
- if ((j < args.length) && (!args[j].startsWith("-"))) {
- etype = Integer.parseInt(args[j]);
- i = j;
+ if (action == 'a') {
+ password = args[i].toCharArray();
+ } else if (action == 'd') {
+ switch (args[i]) {
+ case "all": vDel = -1; break;
+ case "old": vDel = -2; break;
+ default: {
+ try {
+ vDel = Integer.parseInt(args[i]);
+ if (vDel < 0) {
+ throw new NumberFormatException();
+ }
+ } catch (NumberFormatException nfe) {
+ error(args[i] + " is not a valid KVNO");
+ }
+ }
}
} else {
- System.out.println("Please specify the principal" +
- "name of the entry you want to " +
- " delete after -d option.");
- printHelp();
- System.exit(-1);
+ error("Useless extra argument " + args[i]);
}
- break;
- case 'k':
- case 'K':
- i++;
- if ((i < args.length) && (!args[i].startsWith("-"))) {
- if (args[i].length() >= 5 &&
- args[i].substring(0, 5).equalsIgnoreCase("FILE:")) {
- name = args[i].substring(5);
- } else
- name = args[i];
- } else {
- System.out.println("Please specify the keytab "+
- "file name and location " +
- "after -k option");
- printHelp();
- System.exit(-1);
- }
- break;
- case 'e':
- showEType = true;
- break;
- case 't':
- showTime = true;
- break;
- default:
- printHelp();
- System.exit(-1);
+ argAlreadyAppeared = true;
}
}
}
@@ -263,7 +298,7 @@
}
try {
// admin.addEntry(pname, password);
- table.addEntry(pname, password);
+ table.addEntry(pname, password, vAdd, append);
Arrays.fill(password, '0'); // clear password
// admin.save();
table.save();
@@ -350,23 +385,25 @@
if (pname.getRealm() == null) {
pname.setRealm(Config.getInstance().getDefaultRealm());
}
- String answer;
- BufferedReader cis =
- new BufferedReader(new InputStreamReader(System.in));
- System.out.print("Are you sure you want to"+
- " delete service key for " + pname.toString() +
- " (" + (etype==-1?"all etypes":("etype = "+etype)) +
- ") in " + table.tabName() + "?(Y/N): ");
+ if (!forced) {
+ String answer;
+ BufferedReader cis =
+ new BufferedReader(new InputStreamReader(System.in));
+ System.out.print("Are you sure you want to delete "+
+ "service key(s) for " + pname.toString() +
+ " (" + (etype==-1?"all etypes":("etype="+etype)) + ", " +
+ (vDel==-1?"all kvno":(vDel==-2?"old kvno":("kvno=" + vDel))) +
+ ") in " + table.tabName() + "? (Y/[N]): ");
- System.out.flush();
- answer = cis.readLine();
- if (answer.equalsIgnoreCase("Y") ||
- answer.equalsIgnoreCase("Yes"));
- else {
- // no error, the user did not want to delete the entry
- System.exit(0);
+ System.out.flush();
+ answer = cis.readLine();
+ if (answer.equalsIgnoreCase("Y") ||
+ answer.equalsIgnoreCase("Yes"));
+ else {
+ // no error, the user did not want to delete the entry
+ System.exit(0);
+ }
}
-
} catch (KrbException e) {
System.err.println("Error occured while deleting the entry. "+
"Deletion failed.");
@@ -379,9 +416,7 @@
System.exit(-1);
}
- int count;
- if (etype == -1) count = table.deleteEntry(pname);
- else count = table.deleteEntry(pname, etype);
+ int count = table.deleteEntries(pname, etype, vDel);
if (count == 0) {
System.err.println("No matched entry in the keytab. " +
@@ -396,23 +431,47 @@
e.printStackTrace();
System.exit(-1);
}
- System.out.println("Done!");
+ System.out.println("Done! " + count + " entries removed.");
}
}
+ void error(String... errors) {
+ for (String error: errors) {
+ System.out.println("Error: " + error + ".");
+ }
+ printHelp();
+ System.exit(-1);
+ }
/**
* Prints out the help information.
*/
void printHelp() {
- System.out.println("\nUsage: ktab " +
- "<options>");
- System.out.println("available options to Ktab:");
- System.out.println("-l [-e] [-t]\t\t\tlist the keytab name and entries,\n\t\t\t\t-e with etype, -t with timestamp");
- System.out.println("-a <principal name> (<password>)add an entry " +
- "to the keytab");
- System.out.println("-d <principal name> [<etype>]\tdelete an "+
- "entry from the keytab");
- System.out.println("-k <keytab name>\t\tspecify keytab name and "+
- "path with prefix FILE:");
+ System.out.println("\nUsage: ktab <commands> <options>");
+ System.out.println();
+ System.out.println("Available commands:");
+ System.out.println();
+ System.out.println("-l [-e] [-t]\n"
+ + " list the keytab name and entries. -e with etype, -t with timestamp.");
+ System.out.println("-a <principal name> [<password>] [-n <kvno>] [-append]\n"
+ + " add new key entries to the keytab for the given principal name with\n"
+ + " optional <password>. If a <kvno> is specified, new keys' Key Version\n"
+ + " Numbers equal to the value, otherwise, automatically incrementing\n"
+ + " the Key Version Numbers. If -append is specified, new keys are\n"
+ + " appended to the keytab, otherwise, old keys for the\n"
+ + " same principal are removed.");
+ System.out.println("-d <principal name> [-f] [-e <etype>] [<kvno> | all | old]\n"
+ + " delete key entries from the keytab for the specified principal. If\n"
+ + " <kvno> is specified, delete keys whose Key Version Numbers match\n"
+ + " kvno. If \"all\" is specified, delete all keys. If \"old\" is specified,\n"
+ + " delete all keys except those with the highest kvno. Default action\n"
+ + " is \"all\". If <etype> is specified, only keys of this encryption type\n"
+ + " are deleted. <etype> should be specified as the numberic value etype\n"
+ + " defined in RFC 3961, section 8. A prompt to confirm the deletion is\n"
+ + " displayed unless -f is specified.");
+ System.out.println();
+ System.out.println("Common option(s):");
+ System.out.println();
+ System.out.println("-k <keytab name>\n"
+ + " specify keytab name and path with prefix FILE:");
}
}