From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001
From: upstream source tree <ports@midipix.org>
Date: Sun, 15 Mar 2015 20:14:05 -0400
Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified
 gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream
 tarball.

downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.

if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
---
 .../gnu/javax/security/auth/Password.java          | 283 ++++++++++
 .../security/auth/callback/AWTCallbackHandler.java | 454 ++++++++++++++++
 .../auth/callback/AbstractCallbackHandler.java     | 295 +++++++++++
 .../auth/callback/CertificateCallback.java         |  64 +++
 .../auth/callback/ConsoleCallbackHandler.java      | 299 +++++++++++
 .../auth/callback/DefaultCallbackHandler.java      | 109 ++++
 .../javax/security/auth/callback/GnuCallbacks.java |  64 +++
 .../auth/callback/SwingCallbackHandler.java        | 587 +++++++++++++++++++++
 .../security/auth/login/ConfigFileParser.java      | 346 ++++++++++++
 .../security/auth/login/ConfigFileTokenizer.java   | 246 +++++++++
 .../security/auth/login/GnuConfiguration.java      | 466 ++++++++++++++++
 11 files changed, 3213 insertions(+)
 create mode 100644 libjava/classpath/gnu/javax/security/auth/Password.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java
 create mode 100644 libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java

(limited to 'libjava/classpath/gnu/javax/security/auth')

diff --git a/libjava/classpath/gnu/javax/security/auth/Password.java b/libjava/classpath/gnu/javax/security/auth/Password.java
new file mode 100644
index 000000000..8fb07ee6b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/Password.java
@@ -0,0 +1,283 @@
+/* Password.java -- opaque wrapper around a password.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth;
+
+import gnu.java.security.util.ExpirableObject;
+
+/**
+ * Immutible, though destroyable, password class.
+ *
+ * <p>Extends {@link ExpirableObject}, implementing {@link doDestroy()}
+ * in which encapsulated {@link char[]}, and {@link byte[]} password fields
+ * are cleared (elements set to zero) in order to thwart memory heap
+ * snooping.
+ */
+public final class Password extends ExpirableObject
+{
+
+  // Constants and variables
+  // -------------------------------------------------------------------------
+
+  /**
+   * Password stored in {@link char[]} format.
+   */
+  private final char[] password;
+
+  /**
+   * Password stored in {@link byte[]} format.
+   */
+  private final byte[] bPassword;
+
+  /**
+   * Indicates whether this Password object's {@link doDestroy()} method has
+   * been called.  See also, {@link ExpirableObject#Destroy()}.
+   */
+  private boolean mIsDestroyed = false;
+
+  // Constructor(s)
+  // -------------------------------------------------------------------------
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   */
+  public Password (char[] password)
+  {
+    this (password, 0, password.length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (char[] password, long delay)
+  {
+    this (password, 0, password.length, delay);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> character array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of characters, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   */
+  public Password (char[] password, int offset, int length)
+  {
+    this (password, offset, length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The character array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> character array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of characters, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (char[] password, int offset, int length, long delay)
+  {
+    super (delay);
+
+    if (offset < 0 || length < 0 || offset + length > password.length)
+      throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" +
+                                                length + " array.length=" +
+                                                password.length);
+
+    int i, j;
+    this.password = new char[length];
+    bPassword = new byte[length];
+
+    for(i = 0, j = offset; i < length; i++, j++)
+      {
+        this.password[i] = password[j];
+        // XXX this should use character encodings, other than ASCII.
+        bPassword[i] = (byte) (password[j] & 0x7F);
+      }
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   */
+  public Password (byte[] password)
+  {
+    this (password, 0, password.length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (byte[] password, long delay)
+  {
+    this (password, 0, password.length, delay);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> byte array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of bytes, beginning at <i>offset</i>,
+   * to be copied into this object's {@link password} field.
+   */
+  public Password (byte[] password, int offset, int length)
+  {
+    this (password, offset, length, DEFAULT_TIMEOUT);
+  }
+
+  /**
+   * Create a new expirable Password object that will expire after the
+   * timeout denoted by constructor parameter, <i>delay</i>.
+   *
+   * @param password The byte array password to associate with this
+   * Password object.
+   * @param offset The <i>password</i> byte array parameter element
+   * marking the beginning of the contained password string.
+   * @param length The number of bytes, beginning at <i>offset</i>,
+   * to be copied into this object's {@link bPassword} field.
+   * @param delay The number of miliseconds before this Password object
+   * will be automatically destroyed.
+   */
+  public Password (byte[] password, int offset, int length, long delay)
+  {
+    super (delay);
+
+    if (offset < 0 || length < 0 || offset + length > password.length)
+      throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" +
+                                                length + " array.length=" +
+                                                password.length);
+
+    int i, j;
+    this.password = new char[length];
+    bPassword = new byte[length];
+
+    for (i = 0, j = offset; i < length; i++, j++)
+      {
+        this.password[i] = (char) password[j];
+        bPassword[i] = password[j];
+      }
+  }
+
+  // Instance methods
+  // -------------------------------------------------------------------------
+
+  /**
+   * Returns a reference to the {@link char[]} password storage field,
+   * {@link password}.
+   */
+  public synchronized char[] getPassword()
+  {
+    if (mIsDestroyed)
+      throw new IllegalStateException ("Attempted destroyed password access.");
+
+    return password;
+  }
+
+  /**
+   * Returns a reference to the {@link byte[]} password storage field,
+   * {@link bPassword}.
+   */
+  public synchronized byte[] getBytes()
+  {
+    if (mIsDestroyed)
+      throw new IllegalStateException ("Attempted destroyed password access.");
+
+    return bPassword;
+  }
+
+  /**
+   * Sets password field char[], and byte[] array elements to zero.
+   * This method implements base class {@link ExpirableObject} abstract
+   * method, {@link ExpirableObject#doDestroy()}.  See also,
+   * {@link ExpirableObject#destroy()}.
+   */
+  protected synchronized void doDestroy()
+  {
+    if (isDestroyed())
+      return;
+    else
+      {
+        for (int i = 0; i < password.length; i++)
+          password[i] = 0;
+        for (int i = 0; i < bPassword.length; i++)
+          bPassword[i] = 0;
+        mIsDestroyed = true;
+      }
+  }
+
+  /**
+   * Returns true, or false relative to whether, or not this object's
+   * {@link doDestroy()} method has been called.  See also,
+   * {@ExpirableObject#destroy()}.
+   */
+  public synchronized boolean isDestroyed()
+  {
+    return (mIsDestroyed);
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java
new file mode 100644
index 000000000..f241157ee
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java
@@ -0,0 +1,454 @@
+/* AWTCallbackHandler.java --
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Dialog;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.awt.List;
+import java.awt.Panel;
+import java.awt.TextArea;
+import java.awt.TextField;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+
+import java.util.Locale;
+
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+public class AWTCallbackHandler extends AbstractCallbackHandler
+  implements ActionListener, WindowListener
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  protected String actionCommand;
+
+  private static final String ACTION_CANCEL  = "CANCEL";
+  private static final String ACTION_NO      = "NO";
+  private static final String ACTION_NONE    = "NONE";
+  private static final String ACTION_OK      = "OK";
+  private static final String ACTION_YES     = "YES";
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public AWTCallbackHandler()
+  {
+    super ("AWT");
+    actionCommand = ACTION_NONE;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected synchronized void handleChoice(ChoiceCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    String[] choices = c.getChoices();
+    dialog.setTitle(c.getPrompt());
+    Label label = new Label(c.getPrompt());
+    List list = new List(Math.min(5, choices.length),
+                         c.allowMultipleSelections());
+    Panel buttons = new Panel();
+    Button ok = new Button(messages.getString("callback.ok"));
+    ok.setActionCommand(ACTION_OK);
+    ok.addActionListener(this);
+    Button cancel = new Button(messages.getString("callback.cancel"));
+    cancel.setActionCommand(ACTION_CANCEL);
+    cancel.addActionListener(this);
+    for (int i = 0; i < choices.length; i++)
+      {
+        list.add(choices[i]);
+      }
+    if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length)
+      {
+        list.select(c.getDefaultChoice());
+      }
+    dialog.setLayout(new BorderLayout());
+    dialog.add(label, BorderLayout.NORTH);
+    dialog.add(list, BorderLayout.CENTER);
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    buttons.add(cancel);
+    buttons.add(ok);
+    dialog.add(buttons, BorderLayout.SOUTH);
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    if (actionCommand.equals(ACTION_OK))
+      {
+        if (c.allowMultipleSelections())
+          {
+            c.setSelectedIndexes(list.getSelectedIndexes());
+          }
+        else
+          {
+            c.setSelectedIndex(list.getSelectedIndex());
+          }
+      }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  protected synchronized void handleConfirmation(ConfirmationCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    switch (c.getMessageType())
+      {
+      case ConfirmationCallback.ERROR:
+        dialog.setTitle(messages.getString("callback.error"));
+        break;
+      case ConfirmationCallback.INFORMATION:
+        dialog.setTitle(messages.getString("callback.information"));
+        break;
+      case ConfirmationCallback.WARNING:
+        dialog.setTitle(messages.getString("callback.warning"));
+        break;
+      default:
+        dialog.setTitle("");
+      }
+    dialog.setLayout(new GridLayout(2, 1));
+    dialog.add(new Label(c.getPrompt()));
+    Panel buttons = new Panel();
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    dialog.add(buttons);
+    String[] choices = null;
+    int[] values = null;
+    switch (c.getOptionType())
+      {
+      case ConfirmationCallback.OK_CANCEL_OPTION:
+        choices = new String[] {
+          messages.getString("callback.cancel"),
+          messages.getString("callback.ok")
+        };
+        values = new int[] {
+          ConfirmationCallback.CANCEL, ConfirmationCallback.OK
+        };
+        break;
+      case ConfirmationCallback.YES_NO_CANCEL_OPTION:
+        choices = new String[] {
+          messages.getString("callback.cancel"),
+          messages.getString("callback.no"),
+          messages.getString("callback.yes")
+        };
+        values = new int[] {
+          ConfirmationCallback.CANCEL, ConfirmationCallback.NO,
+          ConfirmationCallback.YES
+        };
+        break;
+      case ConfirmationCallback.YES_NO_OPTION:
+        choices = new String[] {
+          messages.getString("callback.no"),
+          messages.getString("callback.yes")
+        };
+        values = new int[] {
+          ConfirmationCallback.NO, ConfirmationCallback.YES
+        };
+        break;
+      case ConfirmationCallback.UNSPECIFIED_OPTION:
+        choices = c.getOptions();
+        values = new int[choices.length];
+        for (int i = 0; i < values.length; i++)
+          values[i] = i;
+        break;
+      default:
+        throw new IllegalArgumentException();
+      }
+    for (int i = 0; i < choices.length; i++)
+      {
+        Button b = new Button(choices[i]);
+        b.setActionCommand(choices[i]);
+        b.addActionListener(this);
+        buttons.add(b);
+      }
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    for (int i = 0; i < choices.length; i++)
+      {
+        if (actionCommand.equals(choices[i]))
+          {
+            c.setSelectedIndex(values[i]);
+            break;
+          }
+      }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  protected synchronized void handleLanguage(LanguageCallback c)
+  {
+    Locale[] locales = Locale.getAvailableLocales();
+    String[] languages = new String[locales.length];
+    Locale def = Locale.getDefault();
+    int defind = 0;
+    for (int i = 0; i < locales.length; i++)
+      {
+        CPStringBuilder lang =
+          new CPStringBuilder(locales[i].getDisplayLanguage(locales[i]));
+        String country = locales[i].getDisplayCountry(locales[i]);
+        String variant = locales[i].getDisplayVariant(locales[i]);
+        if (country.length() > 0 && variant.length() > 0)
+          {
+            lang.append(" (");
+            lang.append(country);
+            lang.append(", ");
+            lang.append(variant);
+            lang.append(")");
+          }
+        else if (country.length() > 0)
+          {
+            lang.append(" (");
+            lang.append(country);
+            lang.append(")");
+          }
+        else if (variant.length() > 0)
+          {
+            lang.append(" (");
+            lang.append(variant);
+            lang.append(")");
+          }
+        languages[i] = lang.toString();
+        if (locales[i].equals(def))
+          defind = i;
+      }
+    ChoiceCallback c2 =
+      new ChoiceCallback(messages.getString("callback.language"), languages,
+                         defind, false);
+    handleChoice(c2);
+    c.setLocale(def);
+    if (c2.getSelectedIndexes() != null && c2.getSelectedIndexes().length > 0)
+      {
+        int index = c2.getSelectedIndexes()[0];
+        if (index >= 0 && index < locales.length)
+          c.setLocale(locales[index]);
+      }
+  }
+
+  protected synchronized void handleName(NameCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    dialog.setTitle(c.getPrompt());
+    dialog.setLayout(new GridLayout(3, 1));
+    Label label = new Label(c.getPrompt());
+    TextField input = new TextField();
+    if (c.getDefaultName() != null)
+      {
+        input.setText(c.getDefaultName());
+      }
+    Panel buttons = new Panel();
+    Button ok = new Button(messages.getString("callback.ok"));
+    ok.setActionCommand(ACTION_OK);
+    ok.addActionListener(this);
+    Button cancel = new Button(messages.getString("callback.cancel"));
+    cancel.setActionCommand(ACTION_CANCEL);
+    cancel.addActionListener(this);
+    dialog.add(label);
+    dialog.add(input);
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    buttons.add(ok);
+    buttons.add(cancel);
+    dialog.add(buttons);
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    if (actionCommand.equals(ACTION_OK))
+      {
+        c.setName(input.getText());
+      }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  protected synchronized void handlePassword(PasswordCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    dialog.setTitle(c.getPrompt());
+    dialog.setLayout(new GridLayout(3, 1));
+    Label label = new Label(c.getPrompt());
+    TextField input = new TextField();
+    if (!c.isEchoOn())
+      {
+        input.setEchoChar('*');
+      }
+    Panel buttons = new Panel();
+    Button ok = new Button(messages.getString("callback.ok"));
+    ok.setActionCommand(ACTION_OK);
+    ok.addActionListener(this);
+    Button cancel = new Button(messages.getString("callback.cancel"));
+    cancel.setActionCommand(ACTION_CANCEL);
+    cancel.addActionListener(this);
+    dialog.add(label);
+    dialog.add(input);
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    buttons.add(ok);
+    buttons.add(cancel);
+    dialog.add(buttons);
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    if (actionCommand.equals(ACTION_OK))
+      {
+        c.setPassword(input.getText().toCharArray());
+      }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  protected synchronized void handleTextInput(TextInputCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    dialog.setTitle(c.getPrompt());
+    dialog.setLayout(new BorderLayout());
+    Label label = new Label(c.getPrompt());
+    TextArea text = new TextArea(10, 40);
+    if (c.getDefaultText() != null)
+      {
+        text.setText(c.getDefaultText());
+      }
+    Panel buttons = new Panel();
+    Button ok = new Button(messages.getString("callback.ok"));
+    ok.setActionCommand(ACTION_OK);
+    ok.addActionListener(this);
+    Button cancel = new Button(messages.getString("callback.cancel"));
+    cancel.setActionCommand(ACTION_CANCEL);
+    cancel.addActionListener(this);
+    dialog.add(label, BorderLayout.NORTH);
+    dialog.add(text, BorderLayout.CENTER);
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    buttons.add(ok);
+    buttons.add(cancel);
+    dialog.add(buttons, BorderLayout.SOUTH);
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    if (actionCommand.equals(ACTION_OK))
+      {
+        c.setText(text.getText());
+      }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  protected synchronized void handleTextOutput(TextOutputCallback c)
+  {
+    Frame ownerFrame = new Frame();
+    Dialog dialog = new Dialog(ownerFrame);
+    dialog.setLayout(new GridLayout(2, 1));
+    switch (c.getMessageType() /*c.getStyle()*/)
+      {
+      case ConfirmationCallback.ERROR:
+        dialog.setTitle(messages.getString("callback.error"));
+        break;
+      case ConfirmationCallback.INFORMATION:
+        dialog.setTitle(messages.getString("callback.information"));
+        break;
+      case ConfirmationCallback.WARNING:
+        dialog.setTitle(messages.getString("callback.warning"));
+        break;
+      default:
+        dialog.setTitle("");
+      }
+    Label label = new Label(c.getMessage());
+    Panel buttons = new Panel();
+    Button ok = new Button(messages.getString("callback.ok"));
+    buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    buttons.add(ok);
+    ok.addActionListener(this);
+    dialog.add(label);
+    dialog.add(buttons);
+    dialog.pack();
+    dialog.show();
+    try { wait(); }
+    catch (InterruptedException ie) { }
+    dialog.dispose();
+    ownerFrame.dispose();
+  }
+
+  // ActionListener interface implementation.
+  // -------------------------------------------------------------------------
+
+  public synchronized void actionPerformed(ActionEvent ae)
+  {
+    actionCommand = ae.getActionCommand();
+    notifyAll();
+  }
+
+  // WindowListener interface implementation.
+  // -------------------------------------------------------------------------
+
+  public synchronized void windowClosing(WindowEvent we)
+  {
+    actionCommand = ACTION_NONE;
+    notifyAll();
+  }
+
+  public void windowOpened(WindowEvent we) { }
+  public void windowClosed(WindowEvent we) { }
+  public void windowIconified(WindowEvent we) { }
+  public void windowDeiconified(WindowEvent we) { }
+  public void windowActivated(WindowEvent we) { }
+  public void windowDeactivated(WindowEvent we) { }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
new file mode 100644
index 000000000..31a7f5aca
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
@@ -0,0 +1,295 @@
+/* AbstractCallbackHandler.java --
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import gnu.java.security.Engine;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public abstract class AbstractCallbackHandler implements CallbackHandler
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private static final String SERVICE = "CallbackHandler";
+
+  protected final ResourceBundle messages;
+
+  private final String name;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  protected AbstractCallbackHandler (final String name)
+  {
+    super();
+    messages = PropertyResourceBundle.getBundle("gnu/javax/security/auth/callback/MessagesBundle");
+    this.name = name;
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the first Security Provider which offers it.
+   *
+   * @param type the type of callback handler to create.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   */
+  public static CallbackHandler getInstance(String type)
+      throws NoSuchAlgorithmException
+  {
+    Provider[] p = Security.getProviders();
+    NoSuchAlgorithmException lastException = null;
+    for (int i = 0; i < p.length; i++)
+      try
+        {
+          return getInstance(type, p[i]);
+        }
+      catch (NoSuchAlgorithmException x)
+        {
+          lastException = x;
+        }
+    if (lastException != null)
+      throw lastException;
+    throw new NoSuchAlgorithmException(type);
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the named security <code>provider</code>.
+   *
+   * @param type the type of callback handler to create.
+   * @param provider a named security provider to use.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   * @throws IllegalArgumentException if either <code>type</code> or
+   *           <code>provider</code> is <code>null</code>, or if
+   *           <code>type</code> is an empty string.
+   */
+  public static CallbackHandler getInstance(String type, String provider)
+      throws NoSuchAlgorithmException, NoSuchProviderException
+  {
+    if (provider == null)
+      throw new IllegalArgumentException("provider MUST NOT be null");
+    Provider p = Security.getProvider(provider);
+    if (p == null)
+      throw new NoSuchProviderException(provider);
+    return getInstance(type, p);
+  }
+
+  /**
+   * Create an instance of <code>CallbackHandler</code> of the designated
+   * <code>type</code> from the designated security <code>provider</code>.
+   *
+   * @param type the type of callback handler to create.
+   * @param provider a security provider to use.
+   * @return a newly created instance of <code>ClassbackHandler</code>.
+   * @throws NoSuchAlgorithmException if no security provider is found to offer
+   *           an implementation of <code>CallbackHandler</code> of the
+   *           designated <code>type</code>.
+   * @throws IllegalArgumentException if either <code>type</code> or
+   *           <code>provider</code> is <code>null</code>, or if
+   *           <code>type</code> is an empty string.
+   */
+  public static CallbackHandler getInstance(String type, Provider provider)
+    throws NoSuchAlgorithmException
+  {
+    StringBuilder sb = new StringBuilder("CallbackHandler of type [")
+        .append(type).append("] from provider[")
+        .append(provider).append("] could not be created");
+    Throwable cause;
+    try
+      {
+        return (CallbackHandler) Engine.getInstance(SERVICE, type, provider);
+      }
+    catch (InvocationTargetException x)
+      {
+        cause = x.getCause();
+        if (cause instanceof NoSuchAlgorithmException)
+          throw (NoSuchAlgorithmException) cause;
+        if (cause == null)
+          cause = x;
+      }
+    catch (ClassCastException x)
+      {
+        cause = x;
+      }
+    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+    x.initCause(cause);
+    throw x;
+  }
+
+  public void handle(Callback[] callbacks)
+    throws IOException, UnsupportedCallbackException
+  {
+    if (callbacks == null)
+      throw new NullPointerException();
+    for (int i = 0; i < callbacks.length; i++)
+      {
+        if (callbacks[i] == null)
+          continue;
+        if (callbacks[i] instanceof ChoiceCallback)
+          handleChoice((ChoiceCallback) callbacks[i]);
+        else if (callbacks[i] instanceof ConfirmationCallback)
+          handleConfirmation((ConfirmationCallback) callbacks[i]);
+        else if (callbacks[i] instanceof LanguageCallback)
+          handleLanguage((LanguageCallback) callbacks[i]);
+        else if (callbacks[i] instanceof NameCallback)
+          handleName((NameCallback) callbacks[i]);
+        else if (callbacks[i] instanceof PasswordCallback)
+          handlePassword((PasswordCallback) callbacks[i]);
+        else if (callbacks[i] instanceof TextInputCallback)
+          handleTextInput((TextInputCallback) callbacks[i]);
+        else if (callbacks[i] instanceof TextOutputCallback)
+          handleTextOutput((TextOutputCallback) callbacks[i]);
+        else
+          handleOther(callbacks[i]);
+      }
+  }
+
+  public final String getName ()
+  {
+    return name;
+  }
+
+  // Abstract methods.
+  // -------------------------------------------------------------------------
+
+  /**
+   * Handles a {@link ChoiceCallback}.
+   *
+   * @param callback The choice callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleChoice(ChoiceCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link ConfirmationCallback}.
+   *
+   * @param callback The confirmation callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleConfirmation(ConfirmationCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link LanguageCallback}.
+   *
+   * @param callback The language callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleLanguage(LanguageCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link NameCallback}.
+   *
+   * @param callback The name callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleName(NameCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link PasswordCallback}.
+   *
+   * @param callback The password callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handlePassword(PasswordCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link TextInputCallback}.
+   *
+   * @param callback The text input callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleTextInput(TextInputCallback callback)
+    throws IOException;
+
+  /**
+   * Handles a {@link TextOutputCallback}.
+   *
+   * @param callback The text output callback.
+   * @throws IOException If an I/O error occurs.
+   */
+  protected abstract void handleTextOutput(TextOutputCallback callback)
+    throws IOException;
+
+  /**
+   * Handles an unknown callback. The default implementation simply throws
+   * an {@link UnsupportedCallbackException}.
+   *
+   * @param callback The callback to handle.
+   * @throws IOException If an I/O error occurs.
+   * @throws UnsupportedCallbackException If the specified callback is not
+   *   supported.
+   */
+  protected void handleOther(Callback callback)
+    throws IOException, UnsupportedCallbackException
+  {
+    throw new UnsupportedCallbackException(callback);
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java
new file mode 100644
index 000000000..74885ed21
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java
@@ -0,0 +1,64 @@
+/* CertificateCallback.java --
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.security.cert.Certificate;
+
+import javax.security.auth.callback.ConfirmationCallback;
+
+/**
+ * A {@link javax.security.auth.callback.Callback} for confirming whether or
+ * not a certificate may be used. This works similarly to
+ * {@link ConfirmationCallback}, but additionally contains the certificate
+ * being verified. Thus, handlers may present the certificate to the user, when
+ * handling this callback.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateCallback extends ConfirmationCallback
+{
+  static final long serialVersionUID = 8343869651419225634L;
+  public final Certificate certificate;
+
+  public CertificateCallback(Certificate cert, String prompt)
+  {
+    super(prompt, ERROR, YES_NO_OPTION, NO);
+    this.certificate = cert;
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java
new file mode 100644
index 000000000..4c24ab808
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java
@@ -0,0 +1,299 @@
+/* ConsoleCallbackHandler.java --
+   Copyright (C) 2005, 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+/**
+ * An implementation of {@link CallbackHandler} that reads and writes
+ * information to and from <code>System.in</code> and <code>System.out</code>.
+ */
+public class ConsoleCallbackHandler extends AbstractCallbackHandler
+{
+
+  // Fields.
+  // -------------------------------------------------------------------------
+
+  private final PrintStream out;
+
+  // Constructors.
+  // -------------------------------------------------------------------------
+
+  public ConsoleCallbackHandler()
+  {
+    this (System.out);
+  }
+
+  public ConsoleCallbackHandler (final PrintStream out)
+  {
+    super ("CONSOLE");
+    this.out = out;
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected void handleChoice(ChoiceCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.println(c.getPrompt());
+    out.print('(');
+    String[] choices = c.getChoices();
+    for (int i = 0; i < choices.length; i++)
+      {
+        out.print(choices[i]);
+        if (i != choices.length - 1)
+          out.print(", ");
+      }
+    out.print(") ");
+    if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length)
+      {
+        out.print('[');
+        out.print(choices[c.getDefaultChoice()]);
+        out.print("] ");
+      }
+    String reply = in.readLine();
+    if (reply == null || reply.length() == 0)
+      {
+        c.setSelectedIndex(c.getDefaultChoice());
+        return;
+      }
+    if (!c.allowMultipleSelections())
+      {
+        for (int i = 0; i < choices.length; i++)
+          {
+            if (reply.trim().equals(choices[i]))
+              {
+                c.setSelectedIndex(i);
+                return;
+              }
+          }
+        c.setSelectedIndex(c.getDefaultChoice());
+      }
+    else
+      {
+        TreeSet indices = new TreeSet();
+        StringTokenizer tok = new StringTokenizer(reply, ",");
+        String[] replies = new String[tok.countTokens()];
+        int idx = 0;
+        while (tok.hasMoreTokens())
+          {
+            replies[idx++] = tok.nextToken().trim();
+          }
+        for (int i = 0; i < choices.length; i++)
+          for (int j = 0; j < replies.length; i++)
+            {
+              if (choices[i].equals(replies[j]))
+                {
+                  indices.add(Integer.valueOf(i));
+                }
+            }
+        if (indices.size() == 0)
+          c.setSelectedIndex(c.getDefaultChoice());
+        else
+          {
+            int[] ii = new int[indices.size()];
+            int i = 0;
+            for (Iterator it = indices.iterator(); it.hasNext(); )
+              ii[i++] = ((Integer) it.next()).intValue();
+            c.setSelectedIndexes(ii);
+          }
+      }
+  }
+
+  protected void handleConfirmation(ConfirmationCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    if (c.getPrompt() != null)
+      out.print(c.getPrompt());
+
+    String[] choices = null;
+    int[] values = null;
+    switch (c.getOptionType())
+      {
+      case ConfirmationCallback.OK_CANCEL_OPTION:
+        out.print(messages.getString("callback.okCancel"));
+        choices = new String[] {
+          messages.getString("callback.ok"),
+          messages.getString("callback.cancel"),
+          messages.getString("callback.shortOk"),
+          messages.getString("callback.shortCancel")
+        };
+        values = new int[] {
+          ConfirmationCallback.OK, ConfirmationCallback.CANCEL,
+          ConfirmationCallback.OK, ConfirmationCallback.CANCEL
+        };
+        break;
+
+      case ConfirmationCallback.YES_NO_CANCEL_OPTION:
+        out.print(messages.getString("callback.yesNoCancel"));
+        choices = new String[] {
+          messages.getString("callback.yes"),
+          messages.getString("callback.no"),
+          messages.getString("callback.cancel"),
+          messages.getString("callback.shortYes"),
+          messages.getString("callback.shortNo"),
+          messages.getString("callback.shortCancel")
+        };
+        values = new int[] {
+          ConfirmationCallback.YES, ConfirmationCallback.NO,
+          ConfirmationCallback.CANCEL, ConfirmationCallback.YES,
+          ConfirmationCallback.NO, ConfirmationCallback.CANCEL
+        };
+        break;
+
+      case ConfirmationCallback.YES_NO_OPTION:
+        out.print(messages.getString("callback.yesNo"));
+        choices = new String[] { messages.getString("callback.yes"),
+                                 messages.getString("callback.no"),
+                                 messages.getString("callback.shortYes"),
+                                 messages.getString("callback.shortNo") };
+        values = new int[] { ConfirmationCallback.YES,
+                             ConfirmationCallback.NO,
+                             ConfirmationCallback.YES,
+                             ConfirmationCallback.NO };
+        int defaultOption = c.getDefaultOption();
+        if (defaultOption > -1 && defaultOption < choices.length)
+          {
+            out.print("[");
+            out.print(choices[defaultOption]);
+            out.print("] ");
+          }
+        break;
+
+      case ConfirmationCallback.UNSPECIFIED_OPTION:
+        choices = c.getOptions();
+        values = new int[choices.length];
+        for (int i = 0; i < values.length; i++)
+          values[i] = i;
+        out.print('(');
+        for (int i = 0; i < choices.length; i++)
+          {
+            out.print(choices[i]);
+            if (i != choices.length - 1)
+              out.print(", ");
+          }
+        out.print(") [");
+        out.print(choices[c.getDefaultOption()]);
+        out.print("] ");
+        break;
+
+      default:
+        throw new IllegalArgumentException();
+      }
+    String reply = in.readLine();
+    if (reply == null)
+      {
+        c.setSelectedIndex(c.getDefaultOption());
+        return;
+      }
+    reply = reply.trim();
+    for (int i = 0; i < choices.length; i++)
+      if (reply.equalsIgnoreCase(choices[i]))
+        {
+          c.setSelectedIndex(values[i]);
+          return;
+        }
+    c.setSelectedIndex(c.getDefaultOption());
+  }
+
+  protected void handleLanguage(LanguageCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(messages.getString("callback.language"));
+    String reply = null;
+    reply = in.readLine();
+    if (reply == null)
+      {
+        c.setLocale(Locale.getDefault());
+      }
+    else
+      {
+        c.setLocale(new Locale(reply.trim()));
+      }
+  }
+
+  protected void handleName(NameCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(c.getPrompt());
+    String name = in.readLine();
+    if (name != null)
+      c.setName(name.trim());
+  }
+
+  protected void handlePassword(PasswordCallback c) throws IOException
+  {
+    out.print(c.getPrompt());
+    BufferedReader in =
+      new BufferedReader(new InputStreamReader(System.in));
+    String pass = in.readLine();
+    c.setPassword(pass.toCharArray());
+  }
+
+  protected void handleTextInput(TextInputCallback c) throws IOException
+  {
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    out.print(c.getPrompt());
+    String text = in.readLine();
+    if (text != null)
+      c.setText(text);
+  }
+
+  protected void handleTextOutput(TextOutputCallback c)
+  {
+    out.print(c.getMessage());
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java
new file mode 100644
index 000000000..df0360b2e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java
@@ -0,0 +1,109 @@
+/* DefaultCallbackHandler.java --
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.util.Locale;
+
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+/**
+ * This trivial implementation of {@link CallbackHandler} sets its
+ * {@link Callback} arguments to default values, with no user interaction.
+ */
+public class DefaultCallbackHandler extends AbstractCallbackHandler
+{
+
+  // Constructor.
+  // -------------------------------------------------------------------------
+
+  public DefaultCallbackHandler()
+  {
+    super("DEFAULT");
+  }
+
+  // Instance methods.
+  // -------------------------------------------------------------------------
+
+  protected void handleChoice(ChoiceCallback c)
+  {
+    c.setSelectedIndex(c.getDefaultChoice());
+  }
+
+  protected void handleConfirmation(ConfirmationCallback c)
+  {
+    if (c.getOptionType() == ConfirmationCallback.YES_NO_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.NO);
+    else if (c.getOptionType() == ConfirmationCallback.YES_NO_CANCEL_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.NO);
+    else if (c.getOptionType() == ConfirmationCallback.OK_CANCEL_OPTION)
+      c.setSelectedIndex(ConfirmationCallback.OK);
+    else
+      c.setSelectedIndex(c.getDefaultOption());
+  }
+
+  protected void handleLanguage(LanguageCallback c)
+  {
+    c.setLocale(Locale.getDefault());
+  }
+
+  protected void handleName(NameCallback c)
+  {
+    c.setName(System.getProperty("user.name"));
+  }
+
+  protected void handlePassword(PasswordCallback c)
+  {
+    c.setPassword(new char[0]);
+  }
+
+  protected void handleTextInput(TextInputCallback c)
+  {
+    c.setText("");
+  }
+
+  protected void handleTextOutput(TextOutputCallback c)
+  {
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java b/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java
new file mode 100644
index 000000000..9fd72f926
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java
@@ -0,0 +1,64 @@
+/* GnuCallbacks.java -- Provider for callback implementations.
+   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+public final class GnuCallbacks extends Provider
+{
+  public GnuCallbacks()
+  {
+    super("GNU-CALLBACKS", 2.1, "Implementations of various callback handlers.");
+
+    AccessController.doPrivileged(new PrivilegedAction()
+      {
+        public Object run()
+        {
+          put("CallbackHandler.Default", DefaultCallbackHandler.class.getName());
+          put("CallbackHandler.Console", ConsoleCallbackHandler.class.getName());
+          put("CallbackHandler.AWT", AWTCallbackHandler.class.getName());
+          put("CallbackHandler.Swing", SwingCallbackHandler.class.getName());
+
+          return null;
+        }
+      });
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java
new file mode 100644
index 000000000..c9d5b3eb5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java
@@ -0,0 +1,587 @@
+ /* SwingCallbackHandler.java --
+    Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.security.auth.callback;
+
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import java.io.IOException;
+
+import java.util.Locale;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+
+public class SwingCallbackHandler extends AbstractCallbackHandler
+{
+  public SwingCallbackHandler ()
+  {
+    super ("SWING");
+  }
+
+  protected void handleChoice (final ChoiceCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    dialog.setResizable (false);
+    Container content = dialog.getContentPane ();
+    GridBagLayout layout = new GridBagLayout ();
+    content.setLayout (layout);
+    JLabel prompt = new JLabel (callback.getPrompt (), JLabel.LEFT);
+    content.add (prompt, new GridBagConstraints (0, 0, 1, 1, 0, 0,
+                                                 GridBagConstraints.WEST,
+                                                 GridBagConstraints.NONE,
+                                                 new Insets (5, 5, 5, 5), 5, 5));
+
+    String[] choices = callback.getChoices ();
+    final JList choicesList = new JList (choices);
+    JScrollPane choicesPane = new JScrollPane (choicesList,
+                                               JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                                               JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+    final int defaultChoice = callback.getDefaultChoice ();
+    choicesList.setSelectedIndex (defaultChoice);
+    choicesList.setSelectionMode (callback.allowMultipleSelections ()
+                                  ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
+                                  : ListSelectionModel.SINGLE_SELECTION);
+    content.add (choicesPane, new GridBagConstraints (0, 1, 1, 1, 1.0, 1.0,
+                                                      GridBagConstraints.CENTER,
+                                                      GridBagConstraints.BOTH,
+                                                      new Insets (0, 10, 0, 10), 5, 5));
+
+    JPanel confirmButtons = new JPanel ();
+    confirmButtons.setLayout (new FlowLayout (FlowLayout.RIGHT));
+    JButton cancel = new JButton (messages.getString ("callback.cancel"));
+    JButton ok = new JButton (messages.getString ("callback.ok"));
+    confirmButtons.add (cancel);
+    confirmButtons.add (ok);
+    content.add (confirmButtons, new GridBagConstraints (0, 2, 1, 1, 0, 0,
+                                                         GridBagConstraints.EAST,
+                                                         GridBagConstraints.NONE,
+                                                         new Insets (5, 5, 5, 5),
+                                                         0, 0));
+    dialog.getRootPane ().setDefaultButton (ok);
+
+    cancel.addActionListener (new ActionListener ()
+      {
+        public void actionPerformed (final ActionEvent ae)
+        {
+          callback.setSelectedIndex (defaultChoice);
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      });
+    ok.addActionListener (new ActionListener ()
+      {
+        public void actionPerformed (final ActionEvent ae)
+        {
+          if (callback.allowMultipleSelections ())
+            {
+              int[] indices = choicesList.getSelectedIndices ();
+              if (indices != null && indices.length > 0)
+                callback.setSelectedIndexes (indices);
+              else
+                callback.setSelectedIndex (defaultChoice);
+            }
+          else
+            {
+              int selected = choicesList.getSelectedIndex ();
+              if (selected != -1)
+                callback.setSelectedIndex (selected);
+              else
+                callback.setSelectedIndex (defaultChoice);
+            }
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      });
+
+    dialog.pack ();
+    dialog.setSize (new Dimension (400, 400));
+    dialog.setVisible (true);
+    waitForInput (dialog, callback);
+  }
+
+  protected void handleConfirmation (final ConfirmationCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    switch (callback.getMessageType ())
+      {
+      case ConfirmationCallback.ERROR:
+        dialog.setTitle (messages.getString ("callback.error"));
+        break;
+      case ConfirmationCallback.WARNING:
+        dialog.setTitle (messages.getString ("callback.warning"));
+        break;
+      case ConfirmationCallback.INFORMATION:
+        dialog.setTitle (messages.getString ("callback.information"));
+        break;
+      }
+    Container content = dialog.getContentPane ();
+    content.setLayout (new GridBagLayout ());
+
+    String prompt = callback.getPrompt ();
+    if (prompt != null)
+      {
+        content.add (new JLabel (prompt),
+                     new GridBagConstraints (0, 0, 1, 1, 0, 0,
+                                             GridBagConstraints.WEST,
+                                             GridBagConstraints.NONE,
+                                             new Insets (5, 5, 5, 25), 0, 0));
+      }
+
+    final String[] options = callback.getOptions ();
+    ActionListener listener = new ActionListener ()
+      {
+        public void actionPerformed (ActionEvent ae)
+        {
+          String cmd = ae.getActionCommand ();
+          if (options != null)
+            {
+              for (int i = 0; i < options.length; i++)
+                {
+                  if (cmd.equals (options[i]))
+                    {
+                      callback.setSelectedIndex (i);
+                      break;
+                    }
+                }
+            }
+          else
+            {
+              if (cmd.equals ("cancel"))
+                callback.setSelectedIndex (ConfirmationCallback.CANCEL);
+              else if (cmd.equals ("okay"))
+                callback.setSelectedIndex (ConfirmationCallback.OK);
+              else if (cmd.equals ("yes"))
+                callback.setSelectedIndex (ConfirmationCallback.YES);
+              else if (cmd.equals ("no"))
+                callback.setSelectedIndex (ConfirmationCallback.NO);
+            }
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      };
+
+    JPanel buttons = new JPanel ();
+    buttons.setLayout (new FlowLayout (FlowLayout.RIGHT));
+    switch (callback.getOptionType ())
+      {
+      case ConfirmationCallback.YES_NO_CANCEL_OPTION:
+        {
+          JButton cancel = new JButton (messages.getString ("callback.cancel"));
+          buttons.add (cancel);
+          cancel.setActionCommand ("cancel");
+          cancel.addActionListener (listener);
+        }
+        /* Fall-through. */
+      case ConfirmationCallback.YES_NO_OPTION:
+        {
+          JButton yes = new JButton (messages.getString ("callback.yes"));
+          JButton no = new JButton (messages.getString ("callback.no"));
+          buttons.add (no);
+          buttons.add (yes);
+          yes.setActionCommand ("yes");
+          yes.addActionListener (listener);
+          no.setActionCommand ("no");
+          no.addActionListener (listener);
+          dialog.getRootPane ().setDefaultButton (yes);
+        }
+        break;
+      case ConfirmationCallback.OK_CANCEL_OPTION:
+        {
+          JButton okay = new JButton (messages.getString ("callback.ok"));
+          JButton cancel = new JButton (messages.getString ("callback.cancel"));
+          buttons.add (cancel);
+          buttons.add (okay);
+          okay.setActionCommand ("okay");
+          okay.addActionListener (listener);
+          cancel.setActionCommand ("cancel");
+          cancel.addActionListener (listener);
+          dialog.getRootPane ().setDefaultButton (okay);
+        }
+        break;
+      case ConfirmationCallback.UNSPECIFIED_OPTION:
+        for (int i = 0; i < options.length; i++)
+          {
+            JButton button = new JButton (options[i]);
+            buttons.add (button);
+            button.setActionCommand (options[i]);
+            button.addActionListener (listener);
+            if (i == options.length - 1)
+              dialog.getRootPane ().setDefaultButton (button);
+          }
+      }
+    content.add (buttons,
+                 new GridBagConstraints (0, GridBagConstraints.RELATIVE,
+                                         1, 1, 1, 1,
+                                         GridBagConstraints.SOUTHEAST,
+                                         GridBagConstraints.BOTH,
+                                         new Insets (5, 5, 5, 5), 0, 0));
+    dialog.setResizable (false);
+    dialog.pack ();
+    dialog.setVisible (true);
+    waitForInput (dialog, callback);
+  }
+
+  protected void handleLanguage (final LanguageCallback callback)
+    throws IOException
+  {
+    Locale locale = Locale.getDefault ();
+    Locale[] locales = Locale.getAvailableLocales ();
+    String[] localeNames = new String[locales.length+1];
+    int defaultIndex = 0;
+    for (int i = 0; i < locales.length; i++)
+      {
+        localeNames[i+1] = locales[i].getDisplayLanguage (locales[i]);
+        String country = locales[i].getDisplayCountry (locales[i]);
+        if (country.length () > 0)
+          localeNames[i+1] += " (" + country + ")";
+        if (locales[i].equals (locale))
+          defaultIndex = i;
+      }
+    locales[0] = locale;
+    localeNames[0] = locale.getDisplayLanguage (locale);
+    String country = locale.getDisplayCountry (locale);
+    if (country.length () > 0)
+      localeNames[0] += " (" + country + ")";
+    ChoiceCallback cb = new ChoiceCallback (messages.getString ("callback.language"),
+                                                                localeNames, 0,
+                                                                false);
+    handleChoice (cb);
+    int selected = cb.getSelectedIndexes ()[0];
+    if (selected > 0)
+      callback.setLocale (locales[selected - 1]);
+    else
+      callback.setLocale (locale);
+  }
+
+  protected void handleName (final NameCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    Container content = dialog.getContentPane ();
+    content.setLayout (new GridBagLayout ());
+
+    content.add (new JLabel (callback.getPrompt ()),
+                             new GridBagConstraints (0, 0, 1, 1, 0, 0,
+                                                     GridBagConstraints.NORTHEAST,
+                                                     GridBagConstraints.VERTICAL,
+                                                     new Insets (10, 10, 15, 5), 0, 0));
+
+    final JTextField name = new JTextField ();
+    name.setColumns (20);
+    String _name;
+    if ((_name = callback.getDefaultName ()) != null)
+      name.setText (_name);
+    content.add (name, new GridBagConstraints (1, 0, 1, 1, 1, 1,
+                                               GridBagConstraints.NORTHWEST,
+                                               GridBagConstraints.BOTH,
+                                               new Insets (10, 5, 15, 10), 0, 0));
+
+    ActionListener listener = new ActionListener ()
+      {
+        public void actionPerformed (ActionEvent ae)
+        {
+          String cmd = ae.getActionCommand ();
+          if (cmd.equals ("okay"))
+            callback.setName (name.getText ());
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      };
+
+    JPanel buttons = new JPanel ();
+    buttons.setLayout (new FlowLayout (FlowLayout.RIGHT));
+    JButton cancel = new JButton (messages.getString ("callback.cancel"));
+    JButton okay = new JButton (messages.getString ("callback.ok"));
+    cancel.setActionCommand ("cancel");
+    cancel.addActionListener (listener);
+    buttons.add (cancel);
+    okay.setActionCommand ("okay");
+    okay.addActionListener (listener);
+    buttons.add (okay);
+    content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0,
+                                                  GridBagConstraints.SOUTHEAST,
+                                                  GridBagConstraints.NONE,
+                                                  new Insets (0, 10, 10, 10), 0, 0));
+
+    dialog.setResizable (false);
+    dialog.pack ();
+    dialog.setVisible (true);
+    dialog.getRootPane ().setDefaultButton (okay);
+    waitForInput (dialog, callback);
+  }
+
+  protected void handlePassword (final PasswordCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    Container content = dialog.getContentPane ();
+    content.setLayout (new GridBagLayout ());
+
+    content.add (new JLabel (callback.getPrompt ()),
+                             new GridBagConstraints (0, 0, 1, 1, 0, 0,
+                                                     GridBagConstraints.NORTHEAST,
+                                                     GridBagConstraints.VERTICAL,
+                                                     new Insets (10, 10, 15, 5), 0, 0));
+
+    final JPasswordField password = new JPasswordField ();
+    password.setColumns (20);
+    password.setEchoChar (callback.isEchoOn () ? '\u0000' : '\u2022');
+    content.add (password, new GridBagConstraints (1, 0, 1, 1, 1, 1,
+                                                   GridBagConstraints.NORTHWEST,
+                                                   GridBagConstraints.BOTH,
+                                                   new Insets (10, 5, 15, 10), 0, 0));
+
+    ActionListener listener = new ActionListener ()
+      {
+        public void actionPerformed (ActionEvent ae)
+        {
+          String cmd = ae.getActionCommand ();
+          if (cmd.equals ("okay"))
+            callback.setPassword (password.getPassword ());
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      };
+
+    JPanel buttons = new JPanel ();
+    buttons.setLayout (new FlowLayout (FlowLayout.RIGHT));
+    JButton cancel = new JButton (messages.getString ("callback.cancel"));
+    JButton okay = new JButton (messages.getString ("callback.ok"));
+    cancel.setActionCommand ("cancel");
+    cancel.addActionListener (listener);
+    buttons.add (cancel);
+    okay.setActionCommand ("okay");
+    okay.addActionListener (listener);
+    buttons.add (okay);
+    content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0,
+                                                  GridBagConstraints.SOUTHEAST,
+                                                  GridBagConstraints.NONE,
+                                                  new Insets (0, 10, 10, 10), 0, 0));
+
+    dialog.setResizable (false);
+    dialog.pack ();
+    dialog.setVisible (true);
+    dialog.getRootPane ().setDefaultButton (okay);
+    waitForInput (dialog, callback);
+  }
+
+  protected void handleTextInput (final TextInputCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    Container content = dialog.getContentPane ();
+    content.setLayout (new GridBagLayout ());
+
+    content.add (new JLabel (callback.getPrompt ()),
+                             new GridBagConstraints (0, 0, 1, 1, 0, 0,
+                                                     GridBagConstraints.NORTHWEST,
+                                                     GridBagConstraints.NONE,
+                                                     new Insets (10, 10, 15, 5), 0, 0));
+
+    final JTextArea text = new JTextArea (24, 80);
+    text.setEditable (true);
+    String _text;
+    if ((_text = callback.getDefaultText ()) != null)
+      text.setText (_text);
+    text.setFont (new Font ("Monospaced", Font.PLAIN, 12));
+    JScrollPane textPane = new JScrollPane (text,
+                                            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                                            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+    content.add (textPane,
+                 new GridBagConstraints (0, 1, 1, 1, 1, 1,
+                                         GridBagConstraints.CENTER,
+                                         GridBagConstraints.BOTH,
+                                         new Insets (5, 10, 5, 10), 0, 0));
+
+    ActionListener listener = new ActionListener ()
+      {
+        public void actionPerformed (ActionEvent ae)
+        {
+          String cmd = ae.getActionCommand ();
+          if (cmd.equals ("okay"))
+            callback.setText (text.getText ());
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      };
+
+    JPanel buttons = new JPanel ();
+    buttons.setLayout (new FlowLayout (FlowLayout.RIGHT));
+    JButton cancel = new JButton (messages.getString ("callback.cancel"));
+    JButton okay = new JButton (messages.getString ("callback.ok"));
+    cancel.setActionCommand ("cancel");
+    cancel.addActionListener (listener);
+    buttons.add (cancel);
+    okay.setActionCommand ("okay");
+    okay.addActionListener (listener);
+    buttons.add (okay);
+    content.add (buttons, new GridBagConstraints (0, 2, 1, 1, 0, 0,
+                                                  GridBagConstraints.SOUTHEAST,
+                                                  GridBagConstraints.NONE,
+                                                  new Insets (0, 10, 10, 10), 0, 0));
+
+    dialog.setResizable (true);
+    dialog.pack ();
+    dialog.setVisible (true);
+    dialog.getRootPane ().setDefaultButton (okay);
+    waitForInput (dialog, callback);
+  }
+
+  protected void handleTextOutput (final TextOutputCallback callback)
+    throws IOException
+  {
+    final JDialog dialog = new JDialog ();
+    switch (callback.getMessageType ())
+      {
+      case TextOutputCallback.ERROR:
+        dialog.setTitle (messages.getString ("callback.error"));
+        break;
+      case TextOutputCallback.WARNING:
+        dialog.setTitle (messages.getString ("callback.warning"));
+        break;
+      case TextOutputCallback.INFORMATION:
+        dialog.setTitle (messages.getString ("callback.information"));
+        break;
+      }
+    Container content = dialog.getContentPane ();
+    content.setLayout (new GridBagLayout ());
+
+    final JTextArea text = new JTextArea (24, 80);
+    text.setEditable (false);
+    text.setText (callback.getMessage ());
+    text.setFont (new Font ("Monospaced", Font.PLAIN, 12));
+    JScrollPane textPane = new JScrollPane (text,
+                                            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                                            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+    content.add (textPane,
+                 new GridBagConstraints (0, 0, 1, 1, 1, 1,
+                                         GridBagConstraints.CENTER,
+                                         GridBagConstraints.BOTH,
+                                         new Insets (10, 10, 5, 10), 0, 0));
+
+    ActionListener listener = new ActionListener ()
+      {
+        public void actionPerformed (ActionEvent ae)
+        {
+          dialog.setVisible (false);
+          synchronized (callback)
+            {
+              callback.notify ();
+            }
+        }
+      };
+
+    JButton okay = new JButton (messages.getString ("callback.ok"));
+    okay.setActionCommand ("okay");
+    okay.addActionListener (listener);
+    content.add (okay, new GridBagConstraints (0, 1, 1, 1, 0, 0,
+                                               GridBagConstraints.SOUTHEAST,
+                                               GridBagConstraints.NONE,
+                                               new Insets (0, 10, 10, 10), 0, 0));
+
+    dialog.setResizable (true);
+    dialog.pack ();
+    dialog.setVisible (true);
+    dialog.getRootPane ().setDefaultButton (okay);
+    waitForInput (dialog, callback);
+  }
+
+  private void waitForInput (JDialog dialog, Callback callback)
+  {
+    synchronized (callback)
+      {
+        while (dialog.isVisible ())
+          {
+            try
+              {
+                callback.wait (1000);
+              }
+            catch (InterruptedException ignored)
+              {
+              }
+          }
+      }
+    dialog.dispose ();
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java
new file mode 100644
index 000000000..5c4c4261f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java
@@ -0,0 +1,346 @@
+/* ConfigFileParser.java -- JAAS Login Configuration default syntax parser
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import gnu.java.security.Configuration;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+/**
+ * A parser that knows how to interpret JAAS Login Module Configuration files
+ * written in the <i>default syntax</i> which is interpreted as adhering to
+ * the following grammar:
+ *
+ * <pre>
+ *   CONFIG              ::= APP_OR_OTHER_ENTRY+
+ *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
+ *   APP_NAME_OR_OTHER   ::= APP_NAME
+ *                         | 'other'
+ *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
+ *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
+ *   FLAG                ::= 'required'
+ *                         | 'requisite'
+ *                         | 'sufficient'
+ *                         | 'optional'
+ *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
+ *
+ *   APP_NAME     ::= JAVA_IDENTIFIER
+ *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
+ *   PARAM_NAME   ::= STRING
+ *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
+ * </pre>
+ *
+ * <p>This parser handles UTF-8 entities when used as APP_NAME and PARAM_VALUE.
+ * It also checks for the use of Java identifiers used in MODULE_CLASS, thus
+ * minimizing the risks of having {@link java.lang.ClassCastException}s thrown
+ * at runtime due to syntactically invalid names.</p>
+ *
+ * <p>In the above context, a JAVA_IDENTIFIER is a sequence of tokens,
+ * separated by the character '.'. Each of these tokens obeys the following:</p>
+ *
+ * <ol>
+ *   <li>its first character yields <code>true</code> when used as an input to
+ *   the {@link java.lang.Character#isJavaIdentifierStart(char)}, and</li>
+ *   <li>all remaining characters, yield <code>true</code> when used as an
+ *   input to {@link java.lang.Character#isJavaIdentifierPart(char)}.</li>
+ * </ol>
+ */
+public final class ConfigFileParser
+{
+  private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+  private ConfigFileTokenizer cft;
+  private Map map = new HashMap();
+
+  // default 0-arguments constructor
+
+  /**
+   * Returns the parse result as a {@link Map} where the keys are application
+   * names, and the entries are {@link List}s of {@link AppConfigurationEntry}
+   * entries, one for each login module entry, in the order they were
+   * encountered, for that application name in the just parsed configuration
+   * file.
+   */
+  public Map getLoginModulesMap()
+  {
+    return map;
+  }
+
+  /**
+   * Parses the {@link Reader}'s contents assuming it is in the <i>default
+   * syntax</i>.
+   *
+   * @param r the {@link Reader} whose contents are assumed to be a JAAS Login
+   * Configuration Module file written in the <i>default syntax</i>.
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  public void parse(Reader r) throws IOException
+  {
+    initParser(r);
+
+    while (parseAppOrOtherEntry())
+      {
+        /* do nothing */
+      }
+  }
+
+  private void initParser(Reader r) throws IOException
+  {
+    map.clear();
+
+    cft = new ConfigFileTokenizer(r);
+  }
+
+  /**
+   * @return <code>true</code> if an APP_OR_OTHER_ENTRY was correctly parsed.
+   * Returns <code>false</code> otherwise.
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  private boolean parseAppOrOtherEntry() throws IOException
+  {
+    int c = cft.nextToken();
+    if (c == ConfigFileTokenizer.TT_EOF)
+      return false;
+
+    if (c != ConfigFileTokenizer.TT_WORD)
+      {
+        cft.pushBack();
+        return false;
+      }
+
+    String appName = cft.sval;
+    if (Configuration.DEBUG)
+      log.fine("APP_NAME_OR_OTHER = " + appName);
+    if (cft.nextToken() != '{')
+      abort("Missing '{' after APP_NAME_OR_OTHER");
+
+    List lmis = new ArrayList();
+    while (parseACE(lmis))
+      {
+        /* do nothing */
+      }
+
+    c = cft.nextToken();
+    if (c != '}')
+      abort("Was expecting '}' but found " + (char) c);
+
+    c = cft.nextToken();
+    if (c != ';')
+      abort("Was expecting ';' but found " + (char) c);
+
+    List listOfACEs = (List) map.get(appName);
+    if (listOfACEs == null)
+      {
+        listOfACEs = new ArrayList();
+        map.put(appName, listOfACEs);
+      }
+    listOfACEs.addAll(lmis);
+    return !appName.equalsIgnoreCase("other");
+  }
+
+  /**
+   * @return <code>true</code> if a LOGIN_MODULE_ENTRY was correctly parsed.
+   * Returns <code>false</code> otherwise.
+   * @throws IOException if an exception occurs while parsing the input.
+   */
+  private boolean parseACE(List listOfACEs) throws IOException
+  {
+    int c = cft.nextToken();
+    if (c != ConfigFileTokenizer.TT_WORD)
+      {
+        cft.pushBack();
+        return false;
+      }
+
+    String clazz = validateClassName(cft.sval);
+    if (Configuration.DEBUG)
+      log.fine("MODULE_CLASS = " + clazz);
+
+    if (cft.nextToken() != ConfigFileTokenizer.TT_WORD)
+      abort("Was expecting FLAG but found none");
+
+    String flag = cft.sval;
+    if (Configuration.DEBUG)
+      log.fine("DEBUG: FLAG = " + flag);
+    AppConfigurationEntry.LoginModuleControlFlag f = null;
+    if (flag.equalsIgnoreCase("required"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+    else if (flag.equalsIgnoreCase("requisite"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+    else if (flag.equalsIgnoreCase("sufficient"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+    else if (flag.equalsIgnoreCase("optional"))
+      f = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+    else
+      abort("Unknown Flag: " + flag);
+
+    Map options = new HashMap();
+    String paramName, paramValue;
+    c = cft.nextToken();
+    while (c != ';')
+      {
+        if (c != ConfigFileTokenizer.TT_WORD)
+          abort("Was expecting PARAM_NAME but got '" + ((char) c) + "'");
+
+        paramName = cft.sval;
+        if (Configuration.DEBUG)
+          log.fine("PARAM_NAME = " + paramName);
+        if (cft.nextToken() != '=')
+          abort("Missing '=' after PARAM_NAME");
+
+        c = cft.nextToken();
+        if (c != '"' && c != '\'')
+          {
+          if (Configuration.DEBUG)
+            log.fine("Was expecting a quoted string but got no quote character."
+                     + " Assume unquoted string");
+          }
+        paramValue = expandParamValue(cft.sval);
+        if (Configuration.DEBUG)
+          log.fine("PARAM_VALUE = " + paramValue);
+        options.put(paramName, paramValue);
+
+        c = cft.nextToken();
+      }
+    AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options);
+    if (Configuration.DEBUG)
+      log.fine("LOGIN_MODULE_ENTRY = " + ace);
+    listOfACEs.add(ace);
+    return true;
+  }
+
+  private void abort(String m) throws IOException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.fine(m);
+        log.fine("Map (so far) = " + String.valueOf(map));
+      }
+    throw new IOException(m);
+  }
+
+  private String validateClassName(String cn) throws IOException
+  {
+    if (cn.startsWith(".") || cn.endsWith("."))
+      abort("MODULE_CLASS MUST NOT start or end with a '.'");
+
+    String[] tokens = cn.split("\\.");
+    for (int i = 0; i < tokens.length; i++)
+      {
+        String t = tokens[i];
+        if (! Character.isJavaIdentifierStart(t.charAt(0)))
+          abort("Class name [" + cn
+                + "] contains an invalid sub-package identifier: " + t);
+
+        // we dont check the rest of the characters for isJavaIdentifierPart()
+        // because that's what the tokenizer does.
+      }
+
+    return cn;
+  }
+
+  /**
+   * The documentation of the {@link javax.security.auth.login.Configuration}
+   * states that: <i>"...If a String in the form, ${system.property}, occurs in
+   * the value, it will be expanded to the value of the system property."</i>.
+   * This method ensures this is the case. If such a string can not be expanded
+   * then it is left AS IS, assuming the LoginModule knows what to do with it.
+   *
+   * <p><b>IMPORTANT</b>: This implementation DOES NOT handle embedded ${}
+   * constructs.
+   *
+   * @param s the raw parameter value, incl. eventually strings of the form
+   * <code>${system.property}</code>.
+   * @return the input string with every occurence of
+   * <code>${system.property}</code> replaced with the value of the
+   * corresponding System property at the time of this method invocation. If
+   * the string is not a known System property name, then the complete sequence
+   * (incl. the ${} characters are passed AS IS.
+   */
+  private String expandParamValue(String s)
+  {
+    String result = s;
+    try
+      {
+        int searchNdx = 0;
+        while (searchNdx < result.length())
+          {
+            int i = s.indexOf("${", searchNdx);
+            if (i == -1)
+              break;
+
+            int j = s.indexOf("}", i + 2);
+            if (j == -1)
+              {
+                if (Configuration.DEBUG)
+                  log.fine("Found a ${ prefix with no } suffix. Ignore");
+                break;
+              }
+
+            String sysPropName = s.substring(i + 2, j);
+            if (Configuration.DEBUG)
+              log.fine("Found a reference to System property " + sysPropName);
+            String sysPropValue = System.getProperty(sysPropName);
+            if (Configuration.DEBUG)
+              log.fine("Resolved " + sysPropName + " to '" + sysPropValue + "'");
+            if (sysPropValue != null)
+              {
+                result = s.substring(0, i) + sysPropValue + s.substring(j + 1);
+                searchNdx = i + sysPropValue.length();
+              }
+            else
+              searchNdx = j + 1;
+          }
+      }
+    catch (Exception x)
+      {
+        if (Configuration.DEBUG)
+          log.fine("Exception (ignored) while expanding " + s + ": " + x);
+      }
+
+    return result;
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java
new file mode 100644
index 000000000..fc35bf772
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java
@@ -0,0 +1,246 @@
+/* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Configuration;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.logging.Logger;
+
+/**
+ * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in
+ * the deault syntax. This class emulates, to a certain extent, the behavior of
+ * a {@link java.io.StreamTokenizer} instance <code>st</code>, when set as
+ * follows:
+ *
+ *  <pre>
+ *  st.resetSyntax();
+ *  st.lowerCaseMode(false);
+ *  st.slashSlashComments(true);
+ *  st.slashStarComments(true);
+ *  st.eolIsSignificant(false);
+ *  st.wordChars('_', '_');
+ *  st.wordChars('$', '$');
+ *  st.wordChars('A', 'Z');
+ *  st.wordChars('a', 'z');
+ *  st.wordChars('0', '9');
+ *  st.wordChars('.', '.');
+ *  st.whitespaceChars(' ', ' ');
+ *  st.whitespaceChars('\t', '\t');
+ *  st.whitespaceChars('\f', '\f');
+ *  st.whitespaceChars('\r', '\r');
+ *  st.whitespaceChars('\n', '\n');
+ *  st.quoteChar('"');
+ *  st.quoteChar('\'');
+ *  </pre>
+ *
+ * <p>The most important (negative) difference with a
+ * {@link java.io.StreamTokenizer} is that this tokenizer does not properly
+ * handle C++ and Java // style comments in the middle of the line. It only
+ * ignores them if/when found at the start of the line.</p>
+ */
+public class ConfigFileTokenizer
+{
+  private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+  /** A constant indicating that the end of the stream has been read. */
+  public static final int TT_EOF = -1;
+  /** A constant indicating that a word token has been read. */
+  public static final int TT_WORD = -3;
+  /** A constant indicating that no tokens have been read yet. */
+  private static final int TT_NONE = -4;
+
+  public String sval;
+  public int ttype;
+
+  private BufferedReader br;
+  boolean initialised;
+  private CPStringBuilder sb;
+  private int sbNdx;
+
+  // Constructor(s)
+  // --------------------------------------------------------------------------
+
+  /** Trivial constructor. */
+  ConfigFileTokenizer(Reader r)
+  {
+    super();
+
+    br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r);
+    initialised = false;
+  }
+
+  // Class methods
+  // --------------------------------------------------------------------------
+
+  // Instance methods
+  // --------------------------------------------------------------------------
+
+  public int nextToken() throws IOException
+  {
+    if (!initialised)
+      init();
+
+    if (sbNdx >= sb.length())
+      return TT_EOF;
+
+    skipWhitespace();
+
+    if (sbNdx >= sb.length())
+      return TT_EOF;
+
+    int endNdx;
+    if (Character.isJavaIdentifierPart(sb.charAt(sbNdx)))
+      {
+        endNdx = sbNdx + 1;
+        while (Character.isJavaIdentifierPart(sb.charAt(endNdx))
+            || sb.charAt(endNdx) == '.')
+          endNdx++;
+
+        ttype = TT_WORD;
+        sval = sb.substring(sbNdx, endNdx);
+        sbNdx = endNdx;
+        return ttype;
+      }
+
+    int c = sb.charAt(sbNdx);
+    if (c == '{' || c == '}' || c == ';' || c == '=')
+      {
+        ttype = c;
+        sbNdx++;
+        return ttype;
+      }
+
+    if (c == '"' || c == '\'')
+      {
+        ttype = c;
+        String quote = sb.substring(sbNdx, sbNdx + 1);
+        int i = sbNdx + 1;
+        while (true)
+          {
+            // find a candidate
+            endNdx = sb.indexOf(quote, i);
+            if (endNdx == -1)
+              abort("Missing closing quote: " + quote);
+
+            // found one; is it escaped?
+            if (sb.charAt(endNdx - 1) != '\\')
+              break;
+
+            i++;
+            continue;
+          }
+
+        endNdx++;
+        sval = sb.substring(sbNdx, endNdx);
+        sbNdx = endNdx;
+        return ttype;
+      }
+
+    abort("Unknown character: " + sb.charAt(sbNdx));
+    return Integer.MIN_VALUE;
+  }
+
+  public void pushBack()
+  {
+    sbNdx -= ttype != TT_WORD ? 1 : sval.length();
+  }
+
+  private void init() throws IOException
+  {
+    sb = new CPStringBuilder();
+    String line;
+    while ((line = br.readLine()) != null)
+      {
+        line = line.trim();
+        if (line.length() == 0)
+          continue;
+
+        if (line.startsWith("#") || line.startsWith("//"))
+          continue;
+
+        sb.append(line).append(" ");
+      }
+
+    sbNdx = 0;
+    sval = null;
+    ttype = TT_NONE;
+
+    initialised = true;
+  }
+
+  private void skipWhitespace() throws IOException
+  {
+    int endNdx;
+    while (sbNdx < sb.length())
+      if (Character.isWhitespace(sb.charAt(sbNdx)))
+        {
+          sbNdx++;
+          while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx)))
+            sbNdx++;
+
+          continue;
+        }
+      else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*')
+        {
+          endNdx = sb.indexOf("*/", sbNdx + 2);
+          if (endNdx == -1)
+            abort("Missing closing */ sequence");
+
+          sbNdx = endNdx + 2;
+          continue;
+        }
+      else
+        break;
+  }
+
+  private void abort(String m) throws IOException
+  {
+    if (Configuration.DEBUG)
+      {
+        log.fine(m);
+        log.fine("sb = " + sb);
+        log.fine("sbNdx = " + sbNdx);
+      }
+    throw new IOException(m);
+  }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java
new file mode 100644
index 000000000..20d8f3afd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java
@@ -0,0 +1,466 @@
+/* GnuConfiguration.java -- GNU Classpath implementation of JAAS Configuration
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.security.auth.AuthPermission;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * An implementation of the {@link Configuration} class which interprets JAAS
+ * Login Configuration files written in the <i>default</i> syntax described in
+ * the publicly available documentation of that class. A more formal definition
+ * of this syntax is as follows:
+ *
+ * <pre>
+ *   CONFIG              ::= APP_OR_OTHER_ENTRY+
+ *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
+ *   APP_NAME_OR_OTHER   ::= APP_NAME
+ *                         | 'other'
+ *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
+ *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
+ *   FLAG                ::= 'required'
+ *                         | 'requisite'
+ *                         | 'sufficient'
+ *                         | 'optional'
+ *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
+ *
+ *   APP_NAME     ::= JAVA_IDENTIFIER
+ *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
+ *   PARAM_NAME   ::= STRING
+ *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
+ * </pre>
+ *
+ * <p>This implementation will specifically attempt to process one or more
+ * Login Configuration files in the following locations, and when found parse
+ * them and merge their contents. The locations, and the order in which they are
+ * investigated, follows:</p>
+ *
+ * <ol>
+ *   <li>If the following Security properties:
+ *   <i>java.security.auth.login.config.url.<b>N</b></i>, where <i><b>N</b></i>
+ *   is a digit, from <code>1</code> to an arbitrary number, are defined, then
+ *   the value of each of those properties will be considered as a JAAS Login
+ *   Configuration file written in the default syntax. This implementation will
+ *   attempt parsing all such files.
+ *
+ *   <p>It is worth noting the following:
+ *     <ul>
+ *       <li>The GNU Classpath security file, named <i>classpath.security</i>,
+ *       where all Security properties are encoded, is usually located in
+ *       <i>/usr/local/classpath/lib/security</i> folder.</li>
+ *
+ *       <li>The numbers used in the properties
+ *       <i>java.security.auth.login.config.url.<b>N</b></i> MUST be sequential,
+ *       with no breaks in-between.</li>
+ *     </ul>
+ *   </p>
+ *
+ *   <p>If at least one of the designated Configuration files was found, and
+ *   was parsed correctly, then no other location will be inspected.</p></li>
+ *
+ *   <li>If the System property named <i>java.security.auth.login.config</i>
+ *   is not null or empty, its contents are then interpreted as a URL to a
+ *   JAAS Login Configuration file written in the default syntax.
+ *
+ *   <p>If this System property is defined, and the file it refers to was
+ *   parsed correctly, then no other location will be inspected.</p></li>
+ *
+ *   <li>If a file named <i>.java.login.config</i> or <i>java.login.config</i>
+ *   (in that order) is found in the location referenced by the value of the
+ *   System property <i>user.home</i>, then that file is parsed as a JAAS Login
+ *   Configuration written in the default syntax.</li>
+ *
+ *   <li>If none of the above resulted in a correctly parsed JAAS Login
+ *   Configuration file, then this implementation will install a <i>Null
+ *   Configuration</i> which basically does not recognize any Application.</li>
+ * </ol>
+ */
+public final class GnuConfiguration extends Configuration
+{
+  private static final Logger log = Logger.getLogger(GnuConfiguration.class.getName());
+  /**
+   * The internal map of login modules keyed by application name. Each entry in
+   * this map is a {@link List} of {@link AppConfigurationEntry}s for that
+   * application name.
+   */
+  private Map loginModulesMap;
+  /** Our reference to our default syntax parser. */
+  private ConfigFileParser cp;
+
+  // Constructor(s)
+  // --------------------------------------------------------------------------
+
+  /** Trivial 0-arguments Constructor. */
+  public GnuConfiguration()
+  {
+    super();
+
+    loginModulesMap = new HashMap();
+    cp = new ConfigFileParser();
+    init();
+  }
+
+  // Class methods
+  // --------------------------------------------------------------------------
+
+  // Instance methods
+  // --------------------------------------------------------------------------
+
+  // Configuration abstract methods implementation ----------------------------
+
+  /* (non-Javadoc)
+   * @see javax.security.auth.login.Configuration#getAppConfigurationEntry(java.lang.String)
+   */
+  public AppConfigurationEntry[] getAppConfigurationEntry(String appName)
+  {
+    if (appName == null)
+      return null;
+
+    appName = appName.trim();
+    if (appName.length() == 0)
+      return null;
+
+    List loginModules = (List) loginModulesMap.get(appName);
+    if (loginModules == null || loginModules.size() == 0)
+      return null;
+
+    if (gnu.java.security.Configuration.DEBUG)
+      log.fine(appName + " -> " + loginModules.size() + " entry(ies)");
+    return (AppConfigurationEntry[]) loginModules.toArray(new AppConfigurationEntry[0]);
+  }
+
+  /**
+   * Refreshes and reloads this <code>Configuration</code>.
+   *
+   * <p>This method causes this <code>Configuration</code> object to refresh /
+   * reload its contents following the locations and logic described above in
+   * the class documentation section.</p>
+   *
+   * @throws SecurityException if the caller does not have an
+   * {@link AuthPermission} for the action named
+   * <code>refreshLoginConfiguration</code>.
+   * @see AuthPermission
+   */
+  public void refresh()
+  {
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
+
+    loginModulesMap.clear();
+    init();
+  }
+
+  // helper methods -----------------------------------------------------------
+
+  /**
+   * Attempts to find and parse JAAS Login Configuration file(s) written in
+   * the default syntax. The locations searched are as descibed in the class
+   * documentation.
+   */
+  private void init()
+  {
+    if (processSecurityProperties())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined by Security property(ies)");
+      }
+    else if (processSystemProperty())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined by System property");
+      }
+    else if (processUserHome())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Using login configuration defined in ${user.home}");
+      }
+    else
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("No login configuration file found");
+      }
+  }
+
+  /**
+   * Attempts to locate and parse one or more JAAS Login Configuration files
+   * defined as the values of the Security properties
+   * <i>java.security.auth.login.config.url.N</i>.
+   *
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processSecurityProperties()
+  {
+    boolean result = false;
+    int counter = 0;
+    String s;
+    while (true)
+      try
+        {
+          counter++;
+          s = Security.getProperty("java.security.auth.login.config.url."
+                                   + counter);
+          if (s == null)
+            break;
+
+          s = s.trim();
+          if (s.length() != 0)
+            {
+              if (gnu.java.security.Configuration.DEBUG)
+                log.fine("java.security.auth.login.config.url." + counter
+                         + " = " + s);
+              parseConfig(getInputStreamFromURL(s));
+              result = true;
+            }
+        }
+      catch (Throwable t)
+        {
+          if (gnu.java.security.Configuration.DEBUG)
+            log.fine("Exception while handling Security property at #"
+                     + counter + ". Continue: " + t);
+        }
+    return result;
+  }
+
+  /**
+   * Attempts to open a designated string as a well-formed {@link URL}. If a
+   * {@link MalformedURLException} occurs, this method then tries to open that
+   * string as a {@link File} (with the same name). If it succeeds, an
+   * {@link InputStream} is constructed and returned.
+   *
+   * @param s
+   *          the designated name of either a {@link URL} or a {@link File}
+   *          assumed to contain a JAAS Login Configuration in the default
+   *          syntax.
+   * @return an {@link InputStream} around the data source.
+   * @throws IOException
+   *           if an exception occurs during the operation.
+   */
+  private InputStream getInputStreamFromURL(String s) throws IOException
+  {
+    InputStream result = null;
+    try
+      {
+        URL url = new URL(s);
+        result = url.openStream();
+      }
+    catch (MalformedURLException x)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Failed opening as URL: " + s + ". Will try as File");
+        result = new FileInputStream(s);
+      }
+    return result;
+  }
+
+  /**
+   * Attempts to locate and parse a JAAS Login Configuration file defined as the
+   * value of the System property <i>java.security.auth.login.config</i>.
+   *
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processSystemProperty()
+  {
+    boolean result = false;
+    try
+      {
+        String s = System.getProperty("java.security.auth.login.config");
+        if (s != null)
+          {
+            s = s.trim();
+            if (s.length() != 0)
+              {
+                if (gnu.java.security.Configuration.DEBUG)
+                  log.fine("java.security.auth.login.config = " + s);
+                parseConfig(getInputStreamFromURL(s));
+                result = true;
+              }
+          }
+      }
+    catch (Throwable t)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Exception while handling System property. Continue: " + t);
+      }
+    return result;
+  }
+
+  /**
+   * Attempts to locate and parse a JAAS Login Configuration file named either
+   * as <i>.java.login.config</i> or <i>java.login.config</i> (without the
+   * leading dot) in the folder referenced by the System property
+   * <code>user.home</code>.
+   *
+   * @return <code>true</code> if it succeeds, and <code>false</code>
+   *         otherwsie.
+   */
+  private boolean processUserHome()
+  {
+    boolean result = false;
+    try
+      {
+        File userHome = getUserHome();
+        if (userHome == null)
+          return result;
+
+        File jaasFile;
+        jaasFile = getConfigFromUserHome(userHome, ".java.login.config");
+        if (jaasFile == null)
+          jaasFile = getConfigFromUserHome(userHome, "java.login.config");
+
+        if (jaasFile == null)
+          {
+            if (gnu.java.security.Configuration.DEBUG)
+              log.fine("Login Configuration file, in " + userHome
+                       + ", does not exist or is inaccessible");
+            return result;
+          }
+
+        FileInputStream fis = new FileInputStream(jaasFile);
+        parseConfig(fis);
+        result = true;
+      }
+    catch (Throwable t)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("Exception (ignored) while handling ${user.home}: " + t);
+      }
+    return result;
+  }
+
+  private void parseConfig(InputStream configStream) throws IOException
+  {
+    cp.parse(new InputStreamReader(configStream, "UTF-8"));
+    Map loginModulesMap = cp.getLoginModulesMap();
+    mergeLoginModules(loginModulesMap);
+  }
+
+  private void mergeLoginModules(Map otherLoginModules)
+  {
+    if (otherLoginModules == null || otherLoginModules.size() < 1)
+      return;
+
+    for (Iterator it = otherLoginModules.keySet().iterator(); it.hasNext();)
+      {
+        String appName = (String) it.next();
+        List thatListOfACEs = (List) otherLoginModules.get(appName);
+        if (thatListOfACEs == null || thatListOfACEs.size() < 1)
+          continue;
+
+        List thisListsOfACEs = (List) loginModulesMap.get(appName);
+        if (thisListsOfACEs == null)
+          loginModulesMap.put(appName, thatListOfACEs);
+        else
+          thisListsOfACEs.addAll(thatListOfACEs);
+      }
+  }
+
+  private File getUserHome()
+  {
+    String uh = System.getProperty("user.home");
+    if (uh == null || uh.trim().length() == 0)
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home path is not set or is empty");
+        return null;
+      }
+    uh = uh.trim();
+    File result = new File(uh);
+    if (! result.exists())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' does not exist");
+        return null;
+      }
+    if (! result.isDirectory())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' is not a directory");
+        return null;
+      }
+    if (! result.canRead())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("User home '" + uh + "' is not readable");
+        return null;
+      }
+    return result;
+  }
+
+  private File getConfigFromUserHome(File userHome, String fileName)
+  {
+    File result = new File(userHome, fileName);
+    if (! result.exists())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' does not exist in user's home");
+        return null;
+      }
+    if (! result.isFile())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' in user's home is not a file");
+        return null;
+      }
+    if (! result.canRead())
+      {
+        if (gnu.java.security.Configuration.DEBUG)
+          log.fine("File '" + fileName + "' in user's home is not readable");
+        return null;
+      }
+    return result;
+  }
+}
-- 
cgit v1.2.3