svn rev #24436: trunk/src/ appl/gss-sample/ lib/gssapi/ lib/gssapi/generic/ lib/gssapi/krb5/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Wed Oct 6 14:25:04 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24436
Commit By: ghudson
Log Message:
Merge users/lhoward/sasl-gs2 to trunk.



Changed Files:
U   trunk/src/appl/gss-sample/gss-client.c
U   trunk/src/appl/gss-sample/gss-server.c
U   trunk/src/lib/gssapi/generic/gssapi.hin
U   trunk/src/lib/gssapi/generic/gssapiP_generic.h
U   trunk/src/lib/gssapi/generic/gssapi_generic.c
U   trunk/src/lib/gssapi/generic/util_buffer.c
U   trunk/src/lib/gssapi/krb5/gssapi_krb5.c
U   trunk/src/lib/gssapi/libgssapi_krb5.exports
U   trunk/src/lib/gssapi/mechglue/Makefile.in
U   trunk/src/lib/gssapi/mechglue/g_initialize.c
A   trunk/src/lib/gssapi/mechglue/g_mechattr.c
A   trunk/src/lib/gssapi/mechglue/g_saslname.c
U   trunk/src/lib/gssapi/mechglue/mglueP.h
U   trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
U   trunk/src/lib/gssapi/spnego/spnego_mech.c
U   trunk/src/tests/gssapi/Makefile.in
A   trunk/src/tests/gssapi/t_saslname.c
Modified: trunk/src/appl/gss-sample/gss-client.c
===================================================================
--- trunk/src/appl/gss-sample/gss-client.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/appl/gss-sample/gss-client.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -69,12 +69,17 @@
 #include "gss-misc.h"
 
 static int verbose = 1;
+static int spnego = 0;
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+        {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
 
 static void
 usage()
 {
-    fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
-    fprintf(stderr, "       [-seq] [-noreplay] [-nomutual] [-user user] [-pass pw]");
+    fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] "
+            "[-spnego] [-d]\n");
+    fprintf(stderr, "       [-seq] [-noreplay] [-nomutual] [-user user] "
+            "[-pass pw]");
 #ifdef _WIN32
     fprintf(stderr, " [-threads num]");
 #endif
@@ -176,10 +181,17 @@
         gss_name_t gss_username = GSS_C_NO_NAME;
         gss_OID_set_desc mechs, *mechsp = GSS_C_NO_OID_SET;
 
-        if (oid != GSS_C_NO_OID) {
+        if (spnego) {
+            mechs.elements = &gss_spnego_mechanism_oid_desc;
+            mechs.count = 1;
+            mechsp = &mechs;
+        } else if (oid != GSS_C_NO_OID) {
             mechs.elements = oid;
             mechs.count = 1;
             mechsp = &mechs;
+        } else {
+            mechs.elements = NULL;
+            mechs.count = 0;
         }
 
         if (username != NULL) {
@@ -218,6 +230,20 @@
             gss_release_name(&min_stat, &gss_username);
             return -1;
         }
+        if (spnego && oid != GSS_C_NO_OID) {
+            gss_OID_set_desc neg_mechs;
+
+            neg_mechs.elements = oid;
+            neg_mechs.count = 1;
+
+            maj_stat = gss_set_neg_mechs(&min_stat, cred, &neg_mechs);
+            if (maj_stat != GSS_S_COMPLETE) {
+                display_status("setting neg mechs", maj_stat, min_stat);
+                gss_release_name(&min_stat, &gss_username);
+                gss_release_cred(&min_stat, &cred);
+                return -1;
+            }
+        }
         gss_release_name(&min_stat, &gss_username);
 
         /*
@@ -264,7 +290,8 @@
         do {
             maj_stat = gss_init_sec_context(&init_sec_min_stat,
                                             cred, gss_context,
-                                            target_name, oid, gss_flags, 0,
+                                            target_name, mechs.elements,
+                                            gss_flags, 0,
                                             NULL, /* channel bindings */
                                             token_ptr, NULL, /* mech type */
                                             &send_tok, ret_flags,
@@ -409,7 +436,7 @@
     char    *username;
     char    *password;
 {
-    gss_ctx_id_t context;
+    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
     gss_buffer_desc in_buf, out_buf;
     int     s, state;
     OM_uint32 ret_flags;
@@ -523,7 +550,7 @@
     } else {
         /* Seal the message */
         in_buf.value = msg;
-        in_buf.length = strlen(msg);
+        in_buf.length = strlen((char *)in_buf.value);
     }
 
     for (i = 0; i < mcount; i++) {
@@ -611,6 +638,7 @@
     }
 
     (void) close(s);
+
     return 0;
 }
 
@@ -776,7 +804,7 @@
         } else if (strcmp(*argv, "-iakerb") == 0) {
             mechanism = "{ 1 3 6 1 5 2 5 }";
         } else if (strcmp(*argv, "-spnego") == 0) {
-            mechanism = "{ 1 3 6 1 5 5 2 }";
+            spnego = 1;
         } else if (strcmp(*argv, "-krb5") == 0) {
             mechanism = "{ 1 3 5 1 5 2 }";
 #ifdef _WIN32

Modified: trunk/src/appl/gss-sample/gss-server.c
===================================================================
--- trunk/src/appl/gss-sample/gss-server.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/appl/gss-sample/gss-server.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -67,6 +67,9 @@
 #include <strings.h>
 #endif
 
+static OM_uint32
+enumerateAttributes(OM_uint32 *minor, gss_name_t name, int noisy);
+
 static void
 usage()
 {
@@ -104,6 +107,7 @@
  * fails, an error message is displayed and -1 is returned; otherwise,
  * 0 is returned.
  */
+
 static int
 server_acquire_creds(char *service_name, gss_cred_id_t *server_creds)
 {
@@ -121,7 +125,7 @@
     }
 
     maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
-                                GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+                                GSS_C_NO_OID_SET, GSS_C_ACCEPT,
                                 server_creds, NULL, NULL);
     if (maj_stat != GSS_S_COMPLETE) {
         display_status("acquiring credentials", maj_stat, min_stat);
@@ -262,6 +266,7 @@
             display_status("displaying name", maj_stat, min_stat);
             return -1;
         }
+        enumerateAttributes(&min_stat, client, TRUE);
         maj_stat = gss_release_name(&min_stat, &client);
         if (maj_stat != GSS_S_COMPLETE) {
             display_status("releasing name", maj_stat, min_stat);
@@ -410,7 +415,8 @@
     gss_buffer_desc client_name, xmit_buf, msg_buf;
     gss_ctx_id_t context;
     OM_uint32 maj_stat, min_stat;
-    int     i, conf_state, ret_flags;
+    int     i, conf_state;
+    OM_uint32 ret_flags;
     char   *cp;
     int     token_flags;
 
@@ -796,3 +802,77 @@
 
     return 0;
 }
+
+static void
+dumpAttribute(OM_uint32 *minor,
+              gss_name_t name,
+              gss_buffer_t attribute,
+              int noisy)
+{
+    OM_uint32 major, tmp;
+    gss_buffer_desc value;
+    gss_buffer_desc display_value;
+    int authenticated = 0;
+    int complete = 0;
+    int more = -1;
+    unsigned int i;
+
+    while (more != 0) {
+        value.value = NULL;
+        display_value.value = NULL;
+
+        major = gss_get_name_attribute(minor, name, attribute, &authenticated,
+                                       &complete, &value, &display_value,
+                                       &more);
+        if (GSS_ERROR(major)) {
+            display_status("gss_get_name_attribute", major, *minor);
+            break;
+        }
+
+        printf("Attribute %.*s %s %s\n\n%.*s\n",
+               (int)attribute->length, (char *)attribute->value,
+               authenticated ? "Authenticated" : "",
+               complete ? "Complete" : "",
+               (int)display_value.length, (char *)display_value.value);
+
+        if (noisy) {
+            for (i = 0; i < value.length; i++) {
+                if ((i % 32) == 0)
+                    printf("\n");
+                printf("%02x", ((char *)value.value)[i] & 0xFF);
+            }
+            printf("\n\n");
+        }
+
+        gss_release_buffer(&tmp, &value);
+        gss_release_buffer(&tmp, &display_value);
+    }
+}
+
+static OM_uint32
+enumerateAttributes(OM_uint32 *minor,
+                    gss_name_t name,
+                    int noisy)
+{
+    OM_uint32 major, tmp;
+    int name_is_MN;
+    gss_OID mech = GSS_C_NO_OID;
+    gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
+    unsigned int i;
+
+    major = gss_inquire_name(minor, name, &name_is_MN, &mech, &attrs);
+    if (GSS_ERROR(major)) {
+        display_status("gss_inquire_name", major, *minor);
+        return major;
+    }
+
+    if (attrs != GSS_C_NO_BUFFER_SET) {
+        for (i = 0; i < attrs->count; i++)
+            dumpAttribute(minor, name, &attrs->elements[i], noisy);
+    }
+
+    gss_release_oid(&tmp, &mech);
+    gss_release_buffer_set(&tmp, &attrs);
+
+    return major;
+}

Modified: trunk/src/lib/gssapi/generic/gssapi.hin
===================================================================
--- trunk/src/lib/gssapi/generic/gssapi.hin	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/generic/gssapi.hin	2010-10-06 18:25:04 UTC (rev 24436)
@@ -289,6 +289,8 @@
      (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
 #define GSS_S_NAME_NOT_MN \
      (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MECH_ATTR \
+     (((OM_uint32) 19ul) << GSS_C_ROUTINE_ERROR_OFFSET)
 
 /*
  * Supplementary info bits:
@@ -831,4 +833,85 @@
 /* XXXX This is a necessary evil until the spec is fixed */
 #define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
 
+/*
+ * RFC 5587
+ */
+typedef const gss_buffer_desc *gss_const_buffer_t;
+typedef const struct gss_channel_bindings_struct *gss_const_channel_bindings_t;
+typedef const struct gss_ctx_id_struct gss_const_ctx_id_t;
+typedef const struct gss_cred_id_struct gss_const_cred_id_t;
+typedef const struct gss_name_struct gss_const_name_t;
+typedef const gss_OID_desc *gss_const_OID;
+typedef const gss_OID_set_desc *gss_const_OID_set;
+
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs_by_attrs(
+    OM_uint32 *,        /* minor_status */
+    gss_const_OID_set,  /* desired_mech_attrs */
+    gss_const_OID_set,  /* except_mech_attrs */
+    gss_const_OID_set,  /* critical_mech_attrs */
+    gss_OID_set *);     /* mechs */
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_attrs_for_mech(
+    OM_uint32 *,        /* minor_status */
+    gss_const_OID,      /* mech */
+    gss_OID_set *,      /* mech_attrs */
+    gss_OID_set *);     /* known_mech_attrs */
+
+OM_uint32 KRB5_CALLCONV
+gss_display_mech_attr(
+    OM_uint32 *,        /* minor_status */
+    gss_const_OID,      /* mech_attr */
+    gss_buffer_t,       /* name */
+    gss_buffer_t,       /* short_desc */
+    gss_buffer_t);      /* long_desc */
+
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_CONCRETE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_PSEUDO;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_COMPOSITE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_NEGO;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MECH_GLUE;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_MECH;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_DEPRECATED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_NOT_DFLT_MECH;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_ITOK_FRAMED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_INIT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_INIT_ANON;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_AUTH_TARG_ANON;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_DELEG_CRED;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_INTEG_PROT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CONF_PROT;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_MIC;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_WRAP;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_PROT_READY;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_REPLAY_DET;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_OOS_DET;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CBINDINGS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_PFS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_COMPRESS;
+GSS_DLLIMP extern gss_const_OID GSS_C_MA_CTX_TRANS;
+
+/*
+ * RFC 5801
+ */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_saslname_for_mech(
+    OM_uint32 *,        /* minor_status */
+    const gss_OID,      /* desired_mech */
+    gss_buffer_t,       /* sasl_mech_name */
+    gss_buffer_t,       /* mech_name */
+    gss_buffer_t        /* mech_description */
+);
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_mech_for_saslname(
+    OM_uint32 *,        /* minor_status */
+    const gss_buffer_t, /* sasl_mech_name */
+    gss_OID *           /* mech_type */
+);
+
 #endif /* _GSSAPI_H_ */

Modified: trunk/src/lib/gssapi/generic/gssapiP_generic.h
===================================================================
--- trunk/src/lib/gssapi/generic/gssapiP_generic.h	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/generic/gssapiP_generic.h	2010-10-06 18:25:04 UTC (rev 24436)
@@ -294,4 +294,13 @@
             const gss_OID_set_desc *, /* const oidset*/
             gss_OID_set * /*new_oidset*/);
 
+extern gss_OID_set gss_ma_known_attrs;
+
+OM_uint32 generic_gss_display_mech_attr(
+      OM_uint32         *minor_status,
+      gss_const_OID      mech_attr,
+      gss_buffer_t       name,
+      gss_buffer_t       short_desc,
+      gss_buffer_t       long_desc);
+
 #endif /* _GSSAPIP_GENERIC_H_ */

Modified: trunk/src/lib/gssapi/generic/gssapi_generic.c
===================================================================
--- trunk/src/lib/gssapi/generic/gssapi_generic.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/generic/gssapi_generic.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -122,6 +122,35 @@
 
     /* GSS_C_INQ_SSPI_SESSION_KEY 1.2.840.113554.1.2.2.5.5 */
     {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"},
+
+    /* RFC 5587 attributes, see below */
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x01"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x02"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x03"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x04"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x05"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x06"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x07"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x08"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x09"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0a"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0b"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0c"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0d"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0e"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x0f"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x10"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x11"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x12"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x13"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x14"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x15"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x16"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x17"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x18"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"},
+    {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"},
 };
 
 /* Here are the constants which point to the static structure above.
@@ -152,3 +181,234 @@
 gss_OID gss_nt_exported_name                    = oids+6;
 
 GSS_DLLIMP gss_OID GSS_C_INQ_SSPI_SESSION_KEY   = oids+7;
+
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_CONCRETE     = oids+8;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_PSEUDO       = oids+9;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_COMPOSITE    = oids+10;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_NEGO         = oids+11;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_GLUE         = oids+12;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_MECH          = oids+13;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DEPRECATED        = oids+14;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_DFLT_MECH     = oids+15;
+GSS_DLLIMP gss_const_OID GSS_C_MA_ITOK_FRAMED       = oids+16;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT         = oids+17;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG         = oids+18;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_INIT    = oids+19;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_INIT    = oids+20;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_ANON    = oids+21;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_ANON    = oids+22;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DELEG_CRED        = oids+23;
+GSS_DLLIMP gss_const_OID GSS_C_MA_INTEG_PROT        = oids+24;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CONF_PROT         = oids+25;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MIC               = oids+26;
+GSS_DLLIMP gss_const_OID GSS_C_MA_WRAP              = oids+27;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PROT_READY        = oids+28;
+GSS_DLLIMP gss_const_OID GSS_C_MA_REPLAY_DET        = oids+29;
+GSS_DLLIMP gss_const_OID GSS_C_MA_OOS_DET           = oids+30;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CBINDINGS         = oids+31;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PFS               = oids+32;
+GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS          = oids+33;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS         = oids+34;
+
+static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+8 };
+gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
+
+#define STRING_BUFFER(x)    { sizeof((x) - 1), (x) }
+
+static struct mech_attr_info_desc {
+    gss_OID mech_attr;
+    gss_buffer_desc name;
+    gss_buffer_desc short_desc;
+    gss_buffer_desc long_desc;
+} mech_attr_info[] = {
+    {
+        oids+8,
+        STRING_BUFFER("GSS_C_MA_MECH_CONCRETE"),
+        STRING_BUFFER("Mechanism is neither a pseudo-mechanism nor a "
+                      "composite mechanism."),
+    },
+    {
+        oids+9,
+        STRING_BUFFER("GSS_C_MA_MECH_PSEUDO"),
+        STRING_BUFFER("Mechanism is a pseudo-mechanism"),
+    },
+    {
+        oids+10,
+        STRING_BUFFER("GSS_C_MA_MECH_COMPOSITE"),
+        STRING_BUFFER("Mechanism is a composite of other mechanisms."),
+    },
+    {
+        oids+11,
+        STRING_BUFFER("GSS_C_MA_MECH_NEGO"),
+        STRING_BUFFER("Mechanism negotiates other mechanisms."),
+    },
+    {
+        oids+12,
+        STRING_BUFFER("GSS_C_MA_MECH_GLUE"),
+        STRING_BUFFER("OID is not a mechanism but the GSS-API itself."),
+    },
+    {
+        oids+13,
+        STRING_BUFFER("GSS_C_MA_NOT_MECH"),
+        STRING_BUFFER("Known OID but not a mechanism OID."),
+    },
+    {
+        oids+14,
+        STRING_BUFFER("GSS_C_MA_DEPRECATED"),
+        STRING_BUFFER("Mechanism is deprecated."),
+    },
+    {
+        oids+15,
+        STRING_BUFFER("GSS_C_MA_NOT_DFLT_MECH"),
+        STRING_BUFFER("Mechanism must not be used as a default mechanism."),
+    },
+    {
+        oids+16,
+        STRING_BUFFER("GSS_C_MA_ITOK_FRAMED"),
+        STRING_BUFFER("Mechanism's initial contexts are properly framed."),
+    },
+    {
+        oids+17,
+        STRING_BUFFER("GSS_C_MA_AUTH_INIT"),
+        STRING_BUFFER("Mechanism supports authentication of initiator to "
+                      "acceptor."),
+    },
+    {
+        oids+18,
+        STRING_BUFFER("GSS_C_MA_AUTH_TARG"),
+        STRING_BUFFER("Mechanism supports authentication of acceptor to "
+                      "initiator."),
+    },
+    {
+        oids+19,
+        STRING_BUFFER("GSS_C_MA_AUTH_INIT_INIT"),
+        STRING_BUFFER("Mechanism supports authentication of initiator using "
+                      "initial credentials."),
+    },
+    {
+        oids+20,
+        STRING_BUFFER("GSS_C_MA_AUTH_TARG_INIT"),
+        STRING_BUFFER("Mechanism supports authentication of acceptor using "
+                      "initial credentials."),
+    },
+    {
+        oids+21,
+        STRING_BUFFER("GSS_C_MA_AUTH_INIT_ANON"),
+        STRING_BUFFER("Mechanism supports GSS_C_NT_ANONYMOUS as an initiator "
+                      "name."),
+    },
+    {
+        oids+22,
+        STRING_BUFFER("GSS_C_MA_AUTH_TARG_ANON"),
+        STRING_BUFFER("Mechanism supports GSS_C_NT_ANONYMOUS as an acceptor "
+                      "name."),
+    },
+    {
+        oids+23,
+        STRING_BUFFER("GSS_C_MA_DELEG_CRED"),
+        STRING_BUFFER("Mechanism supports credential delegation."),
+    },
+    {
+        oids+24,
+        STRING_BUFFER("GSS_C_MA_INTEG_PROT"),
+        STRING_BUFFER("Mechanism supports per-message integrity protection."),
+    },
+    {
+        oids+25,
+        STRING_BUFFER("GSS_C_MA_CONF_PROT"),
+        STRING_BUFFER("Mechanism supports per-message confidentiality"
+                      "protection."),
+    },
+    {
+        oids+26,
+        STRING_BUFFER("GSS_C_MA_MIC"),
+        STRING_BUFFER("Mechanism supports Message Integrity Code (MIC) "
+                      "tokens."),
+    },
+    {
+        oids+27,
+        STRING_BUFFER("GSS_C_MA_WRAP"),
+        STRING_BUFFER("Mechanism supports wrap tokens."),
+    },
+    {
+        oids+28,
+        STRING_BUFFER("GSS_C_MA_PROT_READY"),
+        STRING_BUFFER("Mechanism supports per-message proteciton prior to "
+                      "full context establishment."),
+    },
+    {
+        oids+29,
+        STRING_BUFFER("GSS_C_MA_REPLAY_DET"),
+        STRING_BUFFER("Mechanism supports replay detection."),
+    },
+    {
+        oids+30,
+        STRING_BUFFER("GSS_C_MA_OOS_DET"),
+        STRING_BUFFER("Mechanism supports out-of-sequence detection."),
+    },
+    {
+        oids+31,
+        STRING_BUFFER("GSS_C_MA_CBINDINGS"),
+        STRING_BUFFER("Mechanism supports channel bindings."),
+    },
+    {
+        oids+32,
+        STRING_BUFFER("GSS_C_MA_PFS"),
+        STRING_BUFFER("Mechanism supports Perfect Forward Security."),
+    },
+    {
+        oids+33,
+        STRING_BUFFER("GSS_C_MA_COMPRESS"),
+        STRING_BUFFER("Mechanism supports compression of data inputs to "
+                      "gss_wrap()."),
+    },
+    {
+        oids+34,
+        STRING_BUFFER("GSS_C_MA_CTX_TRANS"),
+        STRING_BUFFER("Mechanism supports security context export/import."),
+    },
+};
+
+OM_uint32
+generic_gss_display_mech_attr(
+      OM_uint32         *minor_status,
+      gss_const_OID      mech_attr,
+      gss_buffer_t       name,
+      gss_buffer_t       short_desc,
+      gss_buffer_t       long_desc)
+{
+    size_t i;
+
+    if (name != GSS_C_NO_BUFFER) {
+        name->length = 0;
+        name->value = NULL;
+    }
+    if (short_desc != GSS_C_NO_BUFFER) {
+        short_desc->length = 0;
+        short_desc->value = NULL;
+    }
+    if (long_desc != GSS_C_NO_BUFFER) {
+        long_desc->length = 0;
+        long_desc->value = NULL;
+    }
+    for (i = 0; i < sizeof(mech_attr_info)/sizeof(mech_attr_info[0]); i++) {
+        struct mech_attr_info_desc *mai = &mech_attr_info[i];
+
+        if (g_OID_equal(mech_attr, mai->mech_attr)) {
+            if (name != GSS_C_NO_BUFFER &&
+                !g_make_string_buffer((char *)mai->name.value, name)) {
+                *minor_status = ENOMEM;
+                return GSS_S_FAILURE;
+            }
+            if (short_desc != GSS_C_NO_BUFFER &&
+                !g_make_string_buffer((char *)mai->short_desc.value,
+                                      short_desc)) {
+                *minor_status = ENOMEM;
+                return GSS_S_FAILURE;
+            }
+            return GSS_S_COMPLETE;
+        }
+    }
+
+    return GSS_S_BAD_MECH_ATTR;
+}

Modified: trunk/src/lib/gssapi/generic/util_buffer.c
===================================================================
--- trunk/src/lib/gssapi/generic/util_buffer.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/generic/util_buffer.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -34,6 +34,9 @@
 
 int g_make_string_buffer(const char *str, gss_buffer_t buffer)
 {
+    if (buffer == GSS_C_NO_BUFFER)
+        return (1);
+
     buffer->length = strlen(str);
 
     if ((buffer->value = strdup(str)) == NULL) {

Modified: trunk/src/lib/gssapi/krb5/gssapi_krb5.c
===================================================================
--- trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -630,6 +630,116 @@
     return GSS_S_UNAVAILABLE;
 }
 
+#define GS2_KRB5_SASL_NAME        "GS2-KRB5"
+#define GS2_KRB5_SASL_NAME_LEN    (sizeof(GS2_KRB5_SASL_NAME) - 1)
+
+#define GS2_IAKERB_SASL_NAME      "GS2-IAKERB"
+#define GS2_IAKERB_SASL_NAME_LEN  (sizeof(GS2_IAKERB_SASL_NAME) - 1)
+
+static OM_uint32
+krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
+                                   const gss_buffer_t sasl_mech_name,
+                                   gss_OID *mech_type)
+{
+    *minor_status = 0;
+
+    if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN &&
+        memcmp(sasl_mech_name->value,
+               GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) {
+        if (mech_type != NULL)
+            *mech_type = (gss_OID)gss_mech_krb5;
+        return GSS_S_COMPLETE;
+    } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN &&
+        memcmp(sasl_mech_name->value,
+               GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) {
+        if (mech_type != NULL)
+            *mech_type = (gss_OID)gss_mech_iakerb;
+        return GSS_S_COMPLETE;
+    }
+
+    return GSS_S_BAD_MECH;
+}
+
+static OM_uint32
+krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
+                                   const gss_OID desired_mech,
+                                   gss_buffer_t sasl_mech_name,
+                                   gss_buffer_t mech_name,
+                                   gss_buffer_t mech_description)
+{
+    if (g_OID_equal(desired_mech, gss_mech_iakerb)) {
+        if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) ||
+            !g_make_string_buffer("iakerb", mech_name) ||
+            !g_make_string_buffer("Initial and Pass Through Authentication "
+                             "Kerberos Mechanism (IAKERB)", mech_description))
+            goto fail;
+    } else {
+        if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) ||
+            !g_make_string_buffer("krb5", mech_name) ||
+            !g_make_string_buffer("Kerberos 5 GSS-API Mechanism",
+                                  mech_description))
+            goto fail;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+
+fail:
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+}
+
+static OM_uint32
+krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
+                                gss_const_OID mech,
+                                gss_OID_set *mech_attrs,
+                                gss_OID_set *known_mech_attrs)
+{
+    OM_uint32 major, tmpMinor;
+
+    if (mech_attrs == NULL) {
+        *minor_status = 0;
+        return GSS_S_COMPLETE;
+    }
+
+    major = gss_create_empty_oid_set(minor_status, mech_attrs);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+#define MA_SUPPORTED(ma)    do { \
+    major = gss_add_oid_set_member(minor_status, (gss_OID)ma, mech_attrs);  \
+    if (GSS_ERROR(major))                                                   \
+        goto cleanup;                                                       \
+    } while (0)
+
+    MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
+    MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+    MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
+    MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
+    MA_SUPPORTED(GSS_C_MA_DELEG_CRED);
+    MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
+    MA_SUPPORTED(GSS_C_MA_CONF_PROT);
+    MA_SUPPORTED(GSS_C_MA_MIC);
+    MA_SUPPORTED(GSS_C_MA_WRAP);
+    MA_SUPPORTED(GSS_C_MA_PROT_READY);
+    MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
+    MA_SUPPORTED(GSS_C_MA_OOS_DET);
+    MA_SUPPORTED(GSS_C_MA_CBINDINGS);
+    MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
+
+    if (g_OID_equal(mech, gss_mech_iakerb)) {
+        MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
+    } else if (!g_OID_equal(mech, gss_mech_krb5)) {
+        MA_SUPPORTED(GSS_C_MA_DEPRECATED);
+    }
+
+cleanup:
+    if (GSS_ERROR(major))
+        gss_release_oid_set(&tmpMinor, mech_attrs);
+
+    return major;
+}
+
 static struct gss_config krb5_mechanism = {
     { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
     NULL,
@@ -701,6 +811,9 @@
     krb5_gss_release_any_name_mapping,
     krb5_gss_pseudo_random,
     NULL,               /* set_neg_mechs */
+    krb5_gss_inquire_saslname_for_mech,
+    krb5_gss_inquire_mech_for_saslname,
+    krb5_gss_inquire_attrs_for_mech,
 };
 
 static struct gss_config_ext krb5_mechanism_ext = {

Modified: trunk/src/lib/gssapi/libgssapi_krb5.exports
===================================================================
--- trunk/src/lib/gssapi/libgssapi_krb5.exports	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/libgssapi_krb5.exports	2010-10-06 18:25:04 UTC (rev 24436)
@@ -7,6 +7,33 @@
 GSS_C_NT_STRING_UID_NAME
 GSS_C_NT_USER_NAME
 GSS_KRB5_NT_PRINCIPAL_NAME
+GSS_C_MA_MECH_CONCRETE
+GSS_C_MA_MECH_PSEUDO
+GSS_C_MA_MECH_COMPOSITE
+GSS_C_MA_MECH_NEGO
+GSS_C_MA_MECH_GLUE
+GSS_C_MA_NOT_MECH
+GSS_C_MA_DEPRECATED
+GSS_C_MA_NOT_DFLT_MECH
+GSS_C_MA_ITOK_FRAMED
+GSS_C_MA_AUTH_INIT
+GSS_C_MA_AUTH_TARG
+GSS_C_MA_AUTH_INIT_INIT
+GSS_C_MA_AUTH_TARG_INIT
+GSS_C_MA_AUTH_INIT_ANON
+GSS_C_MA_AUTH_TARG_ANON
+GSS_C_MA_DELEG_CRED
+GSS_C_MA_INTEG_PROT
+GSS_C_MA_CONF_PROT
+GSS_C_MA_MIC
+GSS_C_MA_WRAP
+GSS_C_MA_PROT_READY
+GSS_C_MA_REPLAY_DET
+GSS_C_MA_OOS_DET
+GSS_C_MA_CBINDINGS
+GSS_C_MA_PFS
+GSS_C_MA_COMPRESS
+GSS_C_MA_CTX_TRANS
 gss_accept_sec_context
 gss_acquire_cred
 gss_acquire_cred_with_password
@@ -23,6 +50,7 @@
 gss_create_empty_oid_set
 gss_delete_name_attribute
 gss_delete_sec_context
+gss_display_mech_attr
 gss_display_name
 gss_display_name_ext
 gss_display_status
@@ -36,12 +64,16 @@
 gss_import_sec_context
 gss_indicate_mechs
 gss_init_sec_context
+gss_indicate_mechs_by_attrs
+gss_inquire_attrs_for_mech
 gss_inquire_context
 gss_inquire_cred
 gss_inquire_cred_by_mech
 gss_inquire_cred_by_oid
+gss_inquire_mech_for_saslname
 gss_inquire_mechs_for_name
 gss_inquire_names_for_mech
+gss_inquire_saslname_for_mech
 gss_inquire_sec_context_by_oid
 gss_krb5_ccache_name
 gss_krb5_copy_ccache

Modified: trunk/src/lib/gssapi/mechglue/Makefile.in
===================================================================
--- trunk/src/lib/gssapi/mechglue/Makefile.in	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/mechglue/Makefile.in	2010-10-06 18:25:04 UTC (rev 24436)
@@ -42,6 +42,7 @@
 	$(srcdir)/g_inq_names.c \
 	$(srcdir)/g_map_name_to_any.c \
 	$(srcdir)/g_mech_invoke.c \
+	$(srcdir)/g_mechattr.c \
 	$(srcdir)/g_mechname.c \
 	$(srcdir)/g_oid_ops.c \
 	$(srcdir)/g_prf.c \
@@ -51,6 +52,7 @@
 	$(srcdir)/g_rel_name.c \
 	$(srcdir)/g_rel_name_mapping.c \
 	$(srcdir)/g_rel_oid_set.c \
+	$(srcdir)/g_saslname.c \
 	$(srcdir)/g_seal.c \
 	$(srcdir)/g_set_context_option.c \
 	$(srcdir)/g_set_cred_option.c \
@@ -98,6 +100,7 @@
 	$(OUTPRE)g_inq_names.$(OBJEXT) \
 	$(OUTPRE)g_map_name_to_any.$(OBJEXT) \
 	$(OUTPRE)g_mech_invoke.$(OBJEXT) \
+	$(OUTPRE)g_mechattr.$(OBJEXT) \
 	$(OUTPRE)g_mechname.$(OBJEXT) \
 	$(OUTPRE)g_oid_ops.$(OBJEXT) \
 	$(OUTPRE)g_prf.$(OBJEXT) \
@@ -107,6 +110,7 @@
 	$(OUTPRE)g_rel_name.$(OBJEXT) \
 	$(OUTPRE)g_rel_name_mapping.$(OBJEXT) \
 	$(OUTPRE)g_rel_oid_set.$(OBJEXT) \
+	$(OUTPRE)g_saslname.$(OBJEXT) \
 	$(OUTPRE)g_seal.$(OBJEXT) \
 	$(OUTPRE)g_set_context_option.$(OBJEXT) \
 	$(OUTPRE)g_set_cred_option.$(OBJEXT) \
@@ -154,6 +158,7 @@
 	g_inq_names.o \
 	g_map_name_to_any.o \
 	g_mech_invoke.o \
+	g_mechattr.o \
 	g_mechname.o \
 	g_oid_ops.o \
 	g_prf.o \
@@ -163,6 +168,7 @@
 	g_rel_name.o \
 	g_rel_name_mapping.o \
 	g_rel_oid_set.o \
+	g_saslname.o \
 	g_seal.o \
 	g_set_context_option.o \
 	g_set_cred_option.o \

Modified: trunk/src/lib/gssapi/mechglue/g_initialize.c
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_initialize.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/mechglue/g_initialize.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -791,6 +791,11 @@
 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_pseudo_random);
 	/* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */
 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_set_neg_mechs);
+        /* draft-ietf-sasl-gs2 */
+        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_saslname_for_mech);
+        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_mech_for_saslname);
+        /* RFC 5587 */
+        GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_attrs_for_mech);
 
 	assert(mech_type != GSS_C_NO_OID);
 

Copied: trunk/src/lib/gssapi/mechglue/g_mechattr.c (from rev 24434, users/lhoward/sasl-gs2/src/lib/gssapi/mechglue/g_mechattr.c)
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_mechattr.c	                        (rev 0)
+++ trunk/src/lib/gssapi/mechglue/g_mechattr.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -0,0 +1,224 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/gssapi/mechglue/g_mechattr.c
+ *
+ * Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * 
+ */
+#include "mglueP.h"
+
+static int
+testMechAttr(gss_const_OID attr,
+             gss_const_OID_set against)
+{
+    int present = 0;
+    OM_uint32 minor;
+
+    if (GSS_ERROR(generic_gss_test_oid_set_member(&minor, attr,
+                                                  (gss_OID_set)against,
+                                                  &present)))
+        return 0;
+
+    return present;
+}
+
+/*
+ * Return TRUE iff all the elements of desired and none of the elements
+ * of except exist in available.
+ */
+static int
+testMechAttrsOffered(gss_const_OID_set desired,
+                     gss_const_OID_set except,
+                     gss_const_OID_set available)
+{
+    size_t i;
+
+    if (desired != GSS_C_NO_OID_SET) {
+        for (i = 0; i < desired->count; i++) {
+            if (!testMechAttr(&desired->elements[i], available))
+                return 0;
+        }
+    }
+
+    if (except != GSS_C_NO_OID_SET) {
+        for (i = 0; i < except->count; i++) {
+            if (testMechAttr(&except->elements[i], available))
+                return 0;
+        }
+    }
+
+    return 1;
+}
+
+/*
+ * Return TRUE iff all the elements of critical exist in known.
+ */
+static int
+testMechAttrsKnown(gss_const_OID_set critical,
+                   gss_const_OID_set known)
+{
+    size_t i;
+
+    if (critical != GSS_C_NO_OID_SET) {
+        for (i = 0; i < critical->count; i++) {
+            if (!testMechAttr(&critical->elements[i], known))
+                return 0;
+        }
+    }
+
+    return 1;
+}
+
+OM_uint32 gss_indicate_mechs_by_attrs(
+      OM_uint32         *minor,
+      gss_const_OID_set  desired_mech_attrs,
+      gss_const_OID_set  except_mech_attrs,
+      gss_const_OID_set  critical_mech_attrs,
+      gss_OID_set       *mechs)
+{
+    OM_uint32       status, tmpMinor;
+    gss_OID_set     allMechs = GSS_C_NO_OID_SET;
+    size_t          i;
+
+    if (minor == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *minor = 0;
+
+    if (mechs == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *mechs = GSS_C_NO_OID_SET;
+
+    status = gss_indicate_mechs(minor, &allMechs);
+    if (GSS_ERROR(status))
+        goto cleanup;
+
+    status = generic_gss_create_empty_oid_set(minor, mechs);
+    if (GSS_ERROR(status))
+        goto cleanup;
+
+    for (i = 0; i < allMechs->count; i++) {
+        gss_OID_set supportedAttrs = GSS_C_NO_OID_SET;
+        gss_OID_set knownAttrs = GSS_C_NO_OID_SET;
+
+        status = gss_inquire_attrs_for_mech(minor, &allMechs->elements[i],
+                                            &supportedAttrs, &knownAttrs);
+        if (GSS_ERROR(status))
+            continue;
+
+        if (testMechAttrsOffered(desired_mech_attrs,
+                                 except_mech_attrs, supportedAttrs) &&
+            testMechAttrsKnown(critical_mech_attrs, knownAttrs)) {
+            status = gss_add_oid_set_member(minor, &allMechs->elements[i],
+                                            mechs);
+            if (GSS_ERROR(status)) {
+                gss_release_oid_set(&tmpMinor, &supportedAttrs);
+                gss_release_oid_set(&tmpMinor, &knownAttrs);
+                goto cleanup;
+            }
+        }
+
+        gss_release_oid_set(&tmpMinor, &supportedAttrs);
+        gss_release_oid_set(&tmpMinor, &knownAttrs);
+    }
+
+    *minor = 0;
+    status = GSS_S_COMPLETE;
+
+cleanup:
+    gss_release_oid_set(&tmpMinor, &allMechs);
+
+    return status;
+}
+
+OM_uint32 gss_inquire_attrs_for_mech(
+      OM_uint32         *minor,
+      gss_const_OID      mech_oid,
+      gss_OID_set       *mech_attrs,
+      gss_OID_set       *known_mech_attrs)
+{
+    OM_uint32       status, tmpMinor;
+    gss_mechanism   mech;
+
+    if (minor == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *minor = 0;
+
+    if (mech_attrs != NULL)
+        *mech_attrs = GSS_C_NO_OID_SET;
+
+    if (known_mech_attrs != NULL)
+        *known_mech_attrs = GSS_C_NO_OID_SET;
+
+    mech = gssint_get_mechanism((gss_OID)mech_oid);
+    if (mech != NULL && mech->gss_inquire_attrs_for_mech != NULL) {
+        status = mech->gss_inquire_attrs_for_mech(minor,
+                                                  mech_oid,
+                                                  mech_attrs,
+                                                  known_mech_attrs);
+        if (GSS_ERROR(status))
+            return status;
+    }
+
+    if (mech_attrs != NULL && mech != gssint_get_mechanism(NULL)) {
+        if (*mech_attrs == GSS_C_NO_OID_SET) {
+            status = generic_gss_create_empty_oid_set(minor, mech_attrs);
+            if (GSS_ERROR(status))
+                return status;
+        }
+
+        status = generic_gss_add_oid_set_member(minor, GSS_C_MA_NOT_DFLT_MECH,
+                                                mech_attrs);
+        if (GSS_ERROR(status)) {
+            gss_release_oid_set(&tmpMinor, mech_attrs);
+            return status;
+        }
+    }
+
+    if (known_mech_attrs != NULL && *known_mech_attrs == GSS_C_NO_OID_SET) {
+        status = generic_gss_copy_oid_set(minor,
+                                          gss_ma_known_attrs,
+                                          known_mech_attrs);
+        if (GSS_ERROR(status)) {
+            gss_release_oid_set(&tmpMinor, mech_attrs);
+            *mech_attrs = GSS_C_NO_OID_SET;
+        }
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_display_mech_attr(
+      OM_uint32         *minor,
+      gss_const_OID      mech_attr,
+      gss_buffer_t       name,
+      gss_buffer_t       short_desc,
+      gss_buffer_t       long_desc)
+{
+    return generic_gss_display_mech_attr(minor, mech_attr,
+                                         name, short_desc, long_desc);
+}

Copied: trunk/src/lib/gssapi/mechglue/g_saslname.c (from rev 24434, users/lhoward/sasl-gs2/src/lib/gssapi/mechglue/g_saslname.c)
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_saslname.c	                        (rev 0)
+++ trunk/src/lib/gssapi/mechglue/g_saslname.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -0,0 +1,210 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/gssapi/mechglue/g_saslname.c
+ *
+ * Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * 
+ */
+#include "mglueP.h"
+#include <krb5/krb5.h>
+
+static char basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+#define OID_SASL_NAME_LENGTH  (sizeof("GS2-XXXXXXXXXXX") - 1)
+
+static OM_uint32
+oidToSaslName(OM_uint32 *minor, const gss_OID mech,
+              char sasl_name[OID_SASL_NAME_LENGTH + 1])
+{
+    unsigned char derBuf[2];
+    krb5_crypto_iov iov[3];
+    unsigned char cksumBuf[20], *q = cksumBuf;
+    char *p = sasl_name;
+
+    if (mech->length > 127) {
+        *minor = ERANGE;
+        return GSS_S_BAD_MECH;
+    }
+
+    derBuf[0] = 0x06;
+    derBuf[1] = (unsigned char)mech->length;
+
+    iov[0].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+    iov[0].data.length = 2;
+    iov[0].data.data = (char *)derBuf;
+    iov[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+    iov[1].data.length = mech->length;
+    iov[1].data.data = (char *)mech->elements;
+    iov[2].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+    iov[2].data.length = sizeof(cksumBuf);
+    iov[2].data.data = (char *)cksumBuf;
+
+    *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_NIST_SHA,
+                                      NULL, 0, iov, 3);
+    if (*minor != 0)
+        return GSS_S_FAILURE;
+
+    memcpy(p, "GS2-", 4);
+    p += 4;
+
+    *p++ = basis_32[q[0] >> 3];
+    *p++ = basis_32[((q[0] & 7) << 2) | (q[1] >> 6)];
+    *p++ = basis_32[(q[1] & 0x3f) >> 1];
+    *p++ = basis_32[((q[1] & 1) << 4) | (q[2] >> 4)];
+    *p++ = basis_32[((q[2] & 0xf) << 1) | (q[3] >> 7)];
+    *p++ = basis_32[(q[3] & 0x7f) >> 2];
+    *p++ = basis_32[((q[3] & 3) << 3) | (q[4] >> 5)];
+    *p++ = basis_32[(q[4] & 0x1f)];
+    *p++ = basis_32[q[5] >> 3];
+    *p++ = basis_32[((q[5] & 7) << 2) | (q[6] >> 6)];
+    *p++ = basis_32[(q[6] & 0x3f) >> 1];
+
+    *p++ = '\0';
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+oidToSaslNameAlloc(OM_uint32 *minor, const gss_OID mech,
+                   gss_buffer_t sasl_name)
+{
+    OM_uint32 status, tmpMinor;
+
+    sasl_name->value = malloc(OID_SASL_NAME_LENGTH + 1);
+    if (sasl_name->value == NULL) {
+        *minor = ENOMEM;
+        return GSS_S_FAILURE;
+    }
+    sasl_name->length = OID_SASL_NAME_LENGTH;
+
+    status = oidToSaslName(minor, mech, (char *)sasl_name->value);
+    if (GSS_ERROR(status)) {
+        gss_release_buffer(&tmpMinor, sasl_name);
+        return status;
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32 KRB5_CALLCONV gss_inquire_saslname_for_mech(
+    OM_uint32     *minor_status,
+    const gss_OID  desired_mech,
+    gss_buffer_t   sasl_mech_name,
+    gss_buffer_t   mech_name,
+    gss_buffer_t   mech_description)
+{
+    OM_uint32       status = GSS_S_BAD_MECH;
+    gss_mechanism   mech;
+
+    if (minor_status == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *minor_status = 0;
+
+    if (sasl_mech_name != GSS_C_NO_BUFFER) {
+        sasl_mech_name->length = 0;
+        sasl_mech_name->value = NULL;
+    }
+
+    if (mech_name != GSS_C_NO_BUFFER) {
+        mech_name->length = 0;
+        mech_name->value = NULL;
+    }
+
+    if (mech_description != GSS_C_NO_BUFFER) {
+        mech_description->length = 0;
+        mech_description->value = NULL;
+    }
+
+    mech = gssint_get_mechanism(desired_mech);
+    if (mech != NULL && mech->gss_inquire_saslname_for_mech != NULL) {
+        status = mech->gss_inquire_saslname_for_mech(minor_status,
+                                                     desired_mech,
+                                                     sasl_mech_name,
+                                                     mech_name,
+                                                     mech_description);
+    }
+    if (status == GSS_S_BAD_MECH) {
+        if (sasl_mech_name != GSS_C_NO_BUFFER)
+            status = oidToSaslNameAlloc(minor_status, desired_mech,
+                                        sasl_mech_name);
+        else
+            status = GSS_S_COMPLETE;
+    }
+
+    return status;
+}
+
+OM_uint32 KRB5_CALLCONV gss_inquire_mech_for_saslname(
+    OM_uint32           *minor_status,
+    const gss_buffer_t   sasl_mech_name,
+    gss_OID             *mech_type)
+{
+    OM_uint32       status, tmpMinor;
+    gss_OID_set     mechSet = GSS_C_NO_OID_SET;
+    size_t          i;
+
+    if (minor_status == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    *minor_status = 0;
+
+    if (mech_type != NULL)
+        *mech_type = GSS_C_NO_OID;
+
+    status = gss_indicate_mechs(minor_status, &mechSet);
+    if (status != GSS_S_COMPLETE)
+        return status;
+
+    for (i = 0, status = GSS_S_BAD_MECH; i < mechSet->count; i++) {
+        gss_mechanism mech;
+        char mappedName[OID_SASL_NAME_LENGTH + 1];
+
+        mech = gssint_get_mechanism(&mechSet->elements[i]);
+        if (mech != NULL && mech->gss_inquire_mech_for_saslname != NULL) {
+            status = mech->gss_inquire_mech_for_saslname(minor_status,
+                                                         sasl_mech_name,
+                                                         mech_type);
+            if (status == GSS_S_COMPLETE)
+                break;
+        }
+        if (status == GSS_S_BAD_MECH &&
+            sasl_mech_name->length == OID_SASL_NAME_LENGTH &&
+            oidToSaslName(&tmpMinor, &mechSet->elements[i],
+                          mappedName) == GSS_S_COMPLETE &&
+            memcmp(sasl_mech_name->value, mappedName,
+                   OID_SASL_NAME_LENGTH) == 0) {
+            if (mech_type != NULL)
+                *mech_type = &mech->mech_type;
+            status = GSS_S_COMPLETE;
+            break;
+        }
+    }
+
+    gss_release_oid_set(&tmpMinor, &mechSet);
+
+    return status;
+}

Modified: trunk/src/lib/gssapi/mechglue/mglueP.h
===================================================================
--- trunk/src/lib/gssapi/mechglue/mglueP.h	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/mechglue/mglueP.h	2010-10-06 18:25:04 UTC (rev 24436)
@@ -588,6 +588,31 @@
 	    gss_cred_id_t,		/* cred_handle */
 	    const gss_OID_set		/* mech_set */
 	/* */);
+
+	OM_uint32	(*gss_inquire_saslname_for_mech)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    const gss_OID,		/* desired_mech */
+	    gss_buffer_t,		/* sasl_mech_name */
+	    gss_buffer_t,		/* mech_name */
+	    gss_buffer_t		/* mech_description */
+	/* */);
+
+	OM_uint32	(*gss_inquire_mech_for_saslname)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    const gss_buffer_t,		/* sasl_mech_name */
+	    gss_OID *			/* mech_type */
+	/* */);
+
+	OM_uint32	(*gss_inquire_attrs_for_mech)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    gss_const_OID,		/* mech */
+	    gss_OID_set *,		/* mech_attrs */
+	    gss_OID_set *		/* known_mech_attrs */
+	/* */);
+
 } *gss_mechanism;
 
 /* This structure MUST NOT be used by any code outside libgss */

Modified: trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
===================================================================
--- trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2010-10-06 18:25:04 UTC (rev 24436)
@@ -565,6 +565,33 @@
 	const gss_OID_set mech_list
 );
 
+OM_uint32
+spnego_gss_inquire_mech_for_saslname
+(
+	OM_uint32 *minor_status,
+	const gss_buffer_t sasl_mech_name,
+	gss_OID *mech_type
+);
+
+OM_uint32
+spnego_gss_inquire_saslname_for_mech
+(
+	OM_uint32 *minor_status,
+	const gss_OID desired_mech,
+	gss_buffer_t sasl_mech_name,
+	gss_buffer_t mech_name,
+	gss_buffer_t mech_description
+);
+
+OM_uint32
+spnego_gss_inquire_attrs_for_mech
+(
+	OM_uint32 *minor_status,
+	gss_const_OID mech,
+	gss_OID_set *mech_attrs,
+	gss_OID_set *known_mech_attrs
+);
+
 #ifdef	__cplusplus
 }
 #endif

Modified: trunk/src/lib/gssapi/spnego/spnego_mech.c
===================================================================
--- trunk/src/lib/gssapi/spnego/spnego_mech.c	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/lib/gssapi/spnego/spnego_mech.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -272,6 +272,9 @@
 	spnego_gss_release_any_name_mapping,
 	spnego_gss_pseudo_random,
 	spnego_gss_set_neg_mechs,
+	spnego_gss_inquire_saslname_for_mech,
+	spnego_gss_inquire_mech_for_saslname,
+	spnego_gss_inquire_attrs_for_mech,
 };
 
 static struct gss_config_ext spnego_mechanism_ext =
@@ -2257,7 +2260,6 @@
 	gss_cred_id_t mcred;
 
 	mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
-
 	ret = gss_set_cred_option(minor_status,
 				  &mcred,
 				  desired_object,
@@ -2279,6 +2281,23 @@
 		*cred_handle = (gss_cred_id_t)spcred;
 	}
 
+	if (ret == GSS_S_COMPLETE && spcred == NULL) {
+		/*
+		 * If the mechanism allocated a new credential handle, then
+		 * we need to wrap it up in an SPNEGO credential handle.
+		 */
+
+		spcred = malloc(sizeof(spnego_gss_cred_id_rec));
+		if (spcred == NULL) {
+			gss_release_cred(&tmp_minor_status, &mcred);
+			*minor_status = ENOMEM;
+			return (GSS_S_FAILURE);
+		}
+		spcred->mcred = mcred;
+		spcred->neg_mechs = GSS_C_NULL_OID_SET;
+		*cred_handle = (gss_cred_id_t)spcred;
+	}
+
 	return (ret);
 }
 
@@ -2686,6 +2705,85 @@
 	return (ret);
 }
 
+#define SPNEGO_SASL_NAME	"SPNEGO"
+#define SPNEGO_SASL_NAME_LEN	(sizeof(SPNEGO_SASL_NAME) - 1)
+
+OM_uint32
+spnego_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
+                                     const gss_buffer_t sasl_mech_name,
+                                     gss_OID *mech_type)
+{
+	if (sasl_mech_name->length == SPNEGO_SASL_NAME_LEN &&
+	    memcmp(sasl_mech_name->value, SPNEGO_SASL_NAME,
+		   SPNEGO_SASL_NAME_LEN) == 0) {
+		if (mech_type != NULL)
+			*mech_type = (gss_OID)gss_mech_spnego;
+		return (GSS_S_COMPLETE);
+	}
+
+	return (GSS_S_BAD_MECH);
+}
+
+OM_uint32
+spnego_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
+                                     const gss_OID desired_mech,
+                                     gss_buffer_t sasl_mech_name,
+                                     gss_buffer_t mech_name,
+                                     gss_buffer_t mech_description)
+{
+	*minor_status = 0;
+
+	if (!g_OID_equal(desired_mech, gss_mech_spnego))
+		return (GSS_S_BAD_MECH);
+
+	if (!g_make_string_buffer(SPNEGO_SASL_NAME, sasl_mech_name) ||
+	    !g_make_string_buffer("spnego", mech_name) ||
+	    !g_make_string_buffer("Simple and Protected GSS-API "
+				  "Negotiation Mechanism", mech_description))
+		goto fail;
+
+	return (GSS_S_COMPLETE);
+
+fail:
+	*minor_status = ENOMEM;
+	return (GSS_S_FAILURE);
+}
+
+OM_uint32
+spnego_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
+				  gss_const_OID mech,
+				  gss_OID_set *mech_attrs,
+				  gss_OID_set *known_mech_attrs)
+{
+	OM_uint32 major, tmpMinor;
+
+	/* known_mech_attrs is handled by mechglue */
+	*minor_status = 0;
+
+	if (mech_attrs == NULL)
+	    return (GSS_S_COMPLETE);
+
+	major = gss_create_empty_oid_set(minor_status, mech_attrs);
+	if (GSS_ERROR(major))
+		goto cleanup;
+
+#define MA_SUPPORTED(ma)    do {					\
+		major = gss_add_oid_set_member(minor_status,		\
+					       (gss_OID)ma, mech_attrs); \
+		if (GSS_ERROR(major))					\
+			goto cleanup;					\
+	} while (0)
+
+	MA_SUPPORTED(GSS_C_MA_MECH_NEGO);
+	MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
+
+cleanup:
+	if (GSS_ERROR(major))
+		gss_release_oid_set(&tmpMinor, mech_attrs);
+
+	return (major);
+}
+
 /*
  * We will release everything but the ctx_handle so that it
  * can be passed back to init/accept context. This routine should

Modified: trunk/src/tests/gssapi/Makefile.in
===================================================================
--- trunk/src/tests/gssapi/Makefile.in	2010-10-06 18:18:41 UTC (rev 24435)
+++ trunk/src/tests/gssapi/Makefile.in	2010-10-06 18:25:04 UTC (rev 24436)
@@ -4,11 +4,11 @@
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c $(srcdir)/t_gssexts.c
+SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c $(srcdir)/t_gssexts.c $(srcdir)/t_saslname.c
 
-OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o t_spnego.o
+OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o t_spnego.o t_saslname.o
 
-all:: t_imp_name t_s4u t_namingexts t_gssexts t_spnego
+all:: t_imp_name t_s4u t_namingexts t_gssexts t_spnego t_saslname
 
 check-pytests:: t_spnego
 	$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
@@ -23,7 +23,9 @@
 	$(CC_LINK) -o t_gssexts t_gssexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 t_spnego: t_spnego.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_spnego t_spnego.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_saslname: t_saslname.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_saslname t_saslname.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 
 clean::
-	$(RM) t_imp_name t_s4u t_namingexts t_gssexts t_spnego
+	$(RM) t_imp_name t_s4u t_namingexts t_gssexts t_spnego t_saslname
 

Copied: trunk/src/tests/gssapi/t_saslname.c (from rev 24434, users/lhoward/sasl-gs2/src/tests/gssapi/t_saslname.c)
===================================================================
--- trunk/src/tests/gssapi/t_saslname.c	                        (rev 0)
+++ trunk/src/tests/gssapi/t_saslname.c	2010-10-06 18:25:04 UTC (rev 24436)
@@ -0,0 +1,188 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+
+static void
+displayStatus_1(char *m, OM_uint32 code, int type)
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+
+     msg_ctx = 0;
+     while (1) {
+          maj_stat = gss_display_status(&min_stat, code,
+                                       type, GSS_C_NULL_OID,
+                                       &msg_ctx, &msg);
+          fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+          (void) gss_release_buffer(&min_stat, &msg);
+
+          if (!msg_ctx)
+               break;
+     }
+}
+
+static void
+displayStatus(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+     displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+     displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static
+OM_uint32 dumpMechAttrs(OM_uint32 *minor, gss_OID mech)
+{
+    OM_uint32 major, tmpMinor;
+    gss_OID_set mech_attrs = GSS_C_NO_OID_SET;
+    gss_OID_set known_attrs = GSS_C_NO_OID_SET;
+    size_t i;
+
+    major = gss_inquire_attrs_for_mech(minor, mech, &mech_attrs, &known_attrs);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_inquire_attrs_for_mech", major, *minor);
+        return major;
+    }
+
+    printf("Mech attrs:  ");
+
+    for (i = 0; i < mech_attrs->count; i++) {
+        gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc short_desc = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc long_desc = GSS_C_EMPTY_BUFFER;
+
+        major = gss_display_mech_attr(minor, &mech_attrs->elements[i],
+                                      &name, &short_desc, &long_desc);
+        if (GSS_ERROR(major)) {
+            displayStatus("gss_display_mech_attr", major, *minor);
+            continue;
+        }
+        printf("%.*s ", (int)name.length, (char *)name.value);
+        gss_release_buffer(minor, &name);
+        gss_release_buffer(minor, &short_desc);
+        gss_release_buffer(minor, &long_desc);
+    }
+    printf("\n");
+
+    printf("Known attrs: ");
+
+    for (i = 0; i < known_attrs->count; i++) {
+        gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc short_desc = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc long_desc = GSS_C_EMPTY_BUFFER;
+
+        major = gss_display_mech_attr(minor, &known_attrs->elements[i],
+                                      &name, &short_desc, &long_desc);
+        if (GSS_ERROR(major)) {
+            displayStatus("gss_display_mech_attr", major, *minor);
+            continue;
+        }
+        printf("%.*s ", (int)name.length, (char *)name.value);
+        gss_release_buffer(minor, &name);
+        gss_release_buffer(minor, &short_desc);
+        gss_release_buffer(minor, &long_desc);
+    }
+    printf("\n");
+
+    gss_release_oid_set(&tmpMinor, &mech_attrs);
+    gss_release_oid_set(&tmpMinor, &known_attrs);
+
+    return GSS_S_COMPLETE;
+}
+
+int main(int argc, char *argv[])
+{
+    gss_OID_set mechs;
+    OM_uint32 major, minor;
+    size_t i;
+
+    major = gss_indicate_mechs(&minor, &mechs);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_indicate_mechs", major, minor);
+        return major;
+    }
+
+    for (i = 0; i < mechs->count; i++) {
+        gss_buffer_desc oidstr = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER;
+        gss_OID oid = GSS_C_NO_OID;
+
+        major = gss_oid_to_str(&minor, &mechs->elements[i], &oidstr);
+        if (GSS_ERROR(major))
+            continue;
+
+        major = gss_inquire_saslname_for_mech(&minor, &mechs->elements[i],
+                                              &sasl_mech_name, &mech_name,
+                                              &mech_description);
+        if (GSS_ERROR(major)) {
+            gss_release_buffer(&minor, &oidstr);
+            continue;
+        }
+
+        printf("-------------------------------------------------------------"
+               "-----------------\n");
+        printf("OID        : %.*s\n", (int)oidstr.length,
+               (char *)oidstr.value);
+        printf("SASL mech  : %.*s\n", (int)sasl_mech_name.length,
+               (char *)sasl_mech_name.value);
+        printf("Mech name  : %.*s\n", (int)mech_name.length,
+               (char *)mech_name.value);
+        printf("Mech desc  : %.*s\n", (int)mech_description.length,
+               (char *)mech_description.value);
+        dumpMechAttrs(&minor, &mechs->elements[i]);
+        printf("-------------------------------------------------------------"
+               "-----------------\n");
+
+        if (GSS_ERROR(gss_inquire_mech_for_saslname(&minor, &sasl_mech_name,
+                                                    &oid))) {
+            displayStatus("gss_inquire_mech_for_saslname", major, minor);
+        } else if (oid == GSS_C_NO_OID ||
+            (oid->length != mechs->elements[i].length &&
+             memcmp(oid->elements, mechs->elements[i].elements,
+                    oid->length) != 0)) {
+            gss_release_buffer(&minor, &oidstr);
+            (void) gss_oid_to_str(&minor, oid, &oidstr);
+            fprintf(stderr, "Got different OID %.*s for mechanism %.*s\n",
+                    (int)oidstr.length, (char *)oidstr.value,
+                    (int)sasl_mech_name.length, (char *)sasl_mech_name.value);
+        }
+        gss_release_buffer(&minor, &oidstr);
+        gss_release_buffer(&minor, &sasl_mech_name);
+        gss_release_buffer(&minor, &mech_name);
+        gss_release_buffer(&minor, &mech_description);
+    }
+
+    gss_release_oid_set(&minor, &mechs);
+
+    return GSS_ERROR(major) ? 1 : 0;
+}




More information about the cvs-krb5 mailing list