0N/A/*
4102N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * (C) Copyright IBM Corp. 1999 All Rights Reserved.
0N/A * Copyright 1997 The Open Group Research Institute. All rights reserved.
0N/A */
0N/A
0N/Apackage sun.security.krb5.internal.tools;
0N/A
4102N/Aimport java.io.File;
0N/Aimport sun.security.krb5.*;
0N/Aimport sun.security.krb5.internal.*;
0N/Aimport sun.security.krb5.internal.ccache.*;
0N/Aimport java.io.IOException;
0N/Aimport java.util.Arrays;
4102N/Aimport javax.security.auth.kerberos.KerberosPrincipal;
0N/Aimport sun.security.util.Password;
4102N/Aimport javax.security.auth.kerberos.KeyTab;
0N/A
0N/A/**
0N/A * Kinit tool for obtaining Kerberos v5 tickets.
0N/A *
0N/A * @author Yanni Zhang
0N/A * @author Ram Marti
0N/A */
0N/Apublic class Kinit {
0N/A
0N/A private KinitOptions options;
0N/A private static final boolean DEBUG = Krb5.DEBUG;
0N/A
0N/A /**
0N/A * The main method is used to accept user command line input for ticket
0N/A * request.
0N/A * <p>
0N/A * Usage: kinit [-A] [-f] [-p] [-c cachename] [[-k [-t keytab_file_name]]
0N/A * [principal] [password]
0N/A * <ul>
0N/A * <li> -A do not include addresses
0N/A * <li> -f forwardable
0N/A * <li> -p proxiable
0N/A * <li> -c cache name (i.e., FILE://c:\temp\mykrb5cc)
0N/A * <li> -k use keytab
0N/A * <li> -t keytab file name
0N/A * <li> principal the principal name (i.e., duke@java.sun.com)
0N/A * <li> password the principal's Kerberos password
0N/A * </ul>
0N/A * <p>
0N/A * Use java sun.security.krb5.tools.Kinit -help to bring up help menu.
0N/A * <p>
0N/A * We currently support only file-based credentials cache to
0N/A * store the tickets obtained from the KDC.
0N/A * By default, for all Unix platforms a cache file named
0N/A * /tmp/krb5cc_&lt;uid&gt will be generated. The &lt;uid&gt is the
0N/A * numeric user identifier.
0N/A * For all other platforms, a cache file named
0N/A * &lt;USER_HOME&gt/krb5cc_&lt;USER_NAME&gt would be generated.
0N/A * <p>
0N/A * &lt;USER_HOME&gt is obtained from <code>java.lang.System</code>
0N/A * property <i>user.home</i>.
0N/A * &lt;USER_NAME&gt is obtained from <code>java.lang.System</code>
0N/A * property <i>user.name</i>.
0N/A * If &lt;USER_HOME&gt is null the cache file would be stored in
0N/A * the current directory that the program is running from.
0N/A * &lt;USER_NAME&gt is operating system's login username.
0N/A * It could be different from user's principal name.
0N/A *</p>
0N/A *<p>
0N/A * For instance, on Windows NT, it could be
0N/A * c:\winnt\profiles\duke\krb5cc_duke, in
0N/A * which duke is the &lt;USER_NAME&gt, and c:\winnt\profile\duke is the
0N/A * &lt;USER_HOME&gt.
0N/A *<p>
0N/A * A single user could have multiple principal names,
0N/A * but the primary principal of the credentials cache could only be one,
0N/A * which means one cache file could only store tickets for one
0N/A * specific user principal. If the user switches
0N/A * the principal name at the next Kinit, the cache file generated for the
0N/A * new ticket would overwrite the old cache file by default.
0N/A * To avoid overwriting, you need to specify
0N/A * a different cache file name when you request a
0N/A * new ticket.
0N/A *</p>
0N/A *<p>
0N/A * You can specify the location of the cache file by using the -c option
0N/A *
0N/A */
0N/A
0N/A public static void main(String[] args) {
0N/A try {
0N/A Kinit self = new Kinit(args);
0N/A }
0N/A catch (Exception e) {
0N/A String msg = null;
0N/A if (e instanceof KrbException) {
0N/A msg = ((KrbException)e).krbErrorMessage() + " " +
0N/A ((KrbException)e).returnCodeMessage();
0N/A } else {
0N/A msg = e.getMessage();
0N/A }
0N/A if (msg != null) {
0N/A System.err.println("Exception: " + msg);
0N/A } else {
0N/A System.out.println("Exception: " + e);
0N/A }
0N/A e.printStackTrace();
0N/A System.exit(-1);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a new Kinit object.
0N/A * @param args array of ticket request options.
0N/A * Avaiable options are: -f, -p, -c, principal, password.
0N/A * @exception IOException if an I/O error occurs.
0N/A * @exception RealmException if the Realm could not be instantiated.
0N/A * @exception KrbException if error occurs during Kerberos operation.
0N/A */
0N/A private Kinit(String[] args)
0N/A throws IOException, RealmException, KrbException {
0N/A if (args == null || args.length == 0) {
0N/A options = new KinitOptions();
0N/A } else {
0N/A options = new KinitOptions(args);
0N/A }
0N/A String princName = null;
0N/A PrincipalName principal = options.getPrincipal();
0N/A if (principal != null) {
0N/A princName = principal.toString();
0N/A }
3054N/A KrbAsReqBuilder builder;
0N/A if (DEBUG) {
0N/A System.out.println("Principal is " + principal);
0N/A }
0N/A char[] psswd = options.password;
0N/A boolean useKeytab = options.useKeytabFile();
0N/A if (!useKeytab) {
0N/A if (princName == null) {
0N/A throw new IllegalArgumentException
0N/A (" Can not obtain principal name");
0N/A }
0N/A if (psswd == null) {
0N/A System.out.print("Password for " + princName + ":");
0N/A System.out.flush();
0N/A psswd = Password.readPassword(System.in);
0N/A if (DEBUG) {
0N/A System.out.println(">>> Kinit console input " +
0N/A new String(psswd));
0N/A }
0N/A }
3054N/A builder = new KrbAsReqBuilder(principal, psswd);
0N/A } else {
0N/A if (DEBUG) {
0N/A System.out.println(">>> Kinit using keytab");
0N/A }
0N/A if (princName == null) {
0N/A throw new IllegalArgumentException
0N/A ("Principal name must be specified.");
0N/A }
0N/A String ktabName = options.keytabFileName();
0N/A if (ktabName != null) {
0N/A if (DEBUG) {
0N/A System.out.println(
0N/A ">>> Kinit keytab file name: " + ktabName);
0N/A }
0N/A }
0N/A
4102N/A builder = new KrbAsReqBuilder(principal, ktabName == null
4102N/A ? KeyTab.getInstance()
4102N/A : KeyTab.getInstance(new File(ktabName)));
0N/A }
0N/A
0N/A KDCOptions opt = new KDCOptions();
0N/A setOptions(KDCOptions.FORWARDABLE, options.forwardable, opt);
0N/A setOptions(KDCOptions.PROXIABLE, options.proxiable, opt);
3054N/A builder.setOptions(opt);
0N/A String realm = options.getKDCRealm();
0N/A if (realm == null) {
0N/A realm = Config.getInstance().getDefaultRealm();
0N/A }
0N/A
0N/A if (DEBUG) {
0N/A System.out.println(">>> Kinit realm name is " + realm);
0N/A }
0N/A
0N/A PrincipalName sname = new PrincipalName("krbtgt" + "/" + realm,
0N/A PrincipalName.KRB_NT_SRV_INST);
0N/A sname.setRealm(realm);
3054N/A builder.setTarget(sname);
0N/A
0N/A if (DEBUG) {
0N/A System.out.println(">>> Creating KrbAsReq");
0N/A }
0N/A
3054N/A if (options.getAddressOption())
3054N/A builder.setAddresses(HostAddresses.getLocalAddresses());
0N/A
3054N/A builder.action();
0N/A
0N/A sun.security.krb5.internal.ccache.Credentials credentials =
3054N/A builder.getCCreds();
3054N/A builder.destroy();
3054N/A
0N/A // we always create a new cache and store the ticket we get
0N/A CredentialsCache cache =
0N/A CredentialsCache.create(principal, options.cachename);
0N/A if (cache == null) {
0N/A throw new IOException("Unable to create the cache file " +
0N/A options.cachename);
0N/A }
0N/A cache.update(credentials);
0N/A cache.save();
0N/A
0N/A if (options.password == null) {
0N/A // Assume we're running interactively
0N/A System.out.println("New ticket is stored in cache file " +
0N/A options.cachename);
0N/A } else {
0N/A Arrays.fill(options.password, '0');
0N/A }
0N/A
0N/A // clear the password
0N/A if (psswd != null) {
0N/A Arrays.fill(psswd, '0');
0N/A }
0N/A options = null; // release reference to options
0N/A }
0N/A
0N/A private static void setOptions(int flag, int option, KDCOptions opt) {
0N/A switch (option) {
0N/A case 0:
0N/A break;
0N/A case -1:
0N/A opt.set(flag, false);
0N/A break;
0N/A case 1:
0N/A opt.set(flag, true);
0N/A }
0N/A }
0N/A}