From a49d656306a1d9424e88059ef5fb752959e0c7c5 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 19 May 2016 20:31:38 -0400
Subject: [PATCH 1/3] Do not indicate deprecated GSS mechanisms

The mechanisms themeselves will continue to work if requested, but will
not be included in the gss_indicate_mech() list.  This works around a
bug in some legacy applications that cannot cope with deprecated mechs
being returned.

ticket: 8419 (new)

Signed-off-by: Nikola Pajkovsky <npajkovsky@suse.cz>
---
 src/lib/gssapi/generic/Makefile.in       |   8 ++
 src/lib/gssapi/generic/gssapi.hin        |  34 +++++++
 src/lib/gssapi/generic/gssapiP_generic.h |   7 ++
 src/lib/gssapi/generic/gssapi_generic.c  |  60 ++++++++++++
 src/lib/gssapi/generic/oid_ops.c         | 113 +++++++++++++++++++++++
 src/lib/gssapi/krb5/gssapiP_krb5.h       |   6 ++
 src/lib/gssapi/krb5/gssapi_krb5.c        |  50 ++++++++++
 src/lib/gssapi/krb5/krb5_gss_glue.c      |  21 +++++
 src/lib/gssapi/mechglue/Makefile.in      |   3 +
 src/lib/gssapi/mechglue/g_initialize.c   |  82 ++++++++++++----
 src/lib/gssapi/mechglue/g_mechattr.c     |  86 +++++++++++++++++
 src/lib/gssapi/mechglue/mglueP.h         |   8 ++
 src/lib/gssapi/spnego/gssapiP_spnego.h   |  10 ++
 src/lib/gssapi/spnego/spnego_mech.c      |  37 ++++++++
 14 files changed, 508 insertions(+), 17 deletions(-)
 create mode 100644 src/lib/gssapi/generic/oid_ops.c
 create mode 100644 src/lib/gssapi/mechglue/g_mechattr.c

diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in
index e63be6b78..d563d2c75 100644
--- a/src/lib/gssapi/generic/Makefile.in
+++ b/src/lib/gssapi/generic/Makefile.in
@@ -67,6 +67,7 @@ SRCS = \
 	$(srcdir)/disp_com_err_status.c \
 	$(srcdir)/disp_major_status.c \
 	$(srcdir)/gssapi_generic.c \
+	$(srcdir)/oid_ops.c \
 	$(srcdir)/rel_buffer.c \
 	$(srcdir)/rel_oid_set.c \
 	$(srcdir)/util_buffer.c \
@@ -80,6 +81,7 @@ OBJS = \
 	$(OUTPRE)disp_com_err_status.$(OBJEXT) \
 	$(OUTPRE)disp_major_status.$(OBJEXT) \
 	$(OUTPRE)gssapi_generic.$(OBJEXT) \
+	$(OUTPRE)oid_ops.$(OBJEXT) \
 	$(OUTPRE)rel_buffer.$(OBJEXT) \
 	$(OUTPRE)rel_oid_set.$(OBJEXT) \
 	$(OUTPRE)util_buffer.$(OBJEXT) \
@@ -93,6 +95,7 @@ STLIBOBJS = \
 	disp_com_err_status.o \
 	disp_major_status.o \
 	gssapi_generic.o \
+	oid_ops.o \
 	rel_buffer.o \
 	rel_oid_set.o \
 	util_buffer.o \
@@ -165,6 +168,11 @@ gssapi_generic.so gssapi_generic.po $(OUTPRE)gssapi_generic.$(OBJEXT): \
   $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
   gssapiP_generic.h gssapi_err_generic.h gssapi_generic.c \
   gssapi_generic.h
+oid_ops.so oid_ops.po $(OUTPRE)oid_ops.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  gssapiP_generic.h gssapi_err_generic.h gssapi_generic.h \
+  oid_ops.c
 rel_buffer.so rel_buffer.po $(OUTPRE)rel_buffer.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/gssapi/gssapi.h \
   $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin
index 71b365b0b..b6657b081 100644
--- a/src/lib/gssapi/generic/gssapi.hin
+++ b/src/lib/gssapi/generic/gssapi.hin
@@ -787,4 +787,38 @@ OM_uint32 KRB5_CALLCONV gss_canonicalize_name
 /* XXXX This is a necessary evil until the spec is fixed */
 #define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
 
+/*
+ * RFC 5587
+ */
+typedef const gss_OID_desc *gss_const_OID;
+typedef const gss_OID_set_desc *gss_const_OID_set;
+
+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;
+
 #endif /* _GSSAPI_H_ */
diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h
index e34055b6c..cbe94a9a2 100644
--- a/src/lib/gssapi/generic/gssapiP_generic.h
+++ b/src/lib/gssapi/generic/gssapiP_generic.h
@@ -255,4 +255,11 @@ OM_uint32 generic_gss_str_to_oid
 	    gss_OID *		/* oid */
 	   );
 
+OM_uint32 generic_gss_copy_oid_set
+(OM_uint32 *, /* minor_status */
+            const gss_OID_set_desc * const, /*oidset*/
+            gss_OID_set * /*new_oidset*/);
+
+extern gss_OID_set gss_ma_known_attrs;
+
 #endif /* _GSSAPIP_GENERIC_H_ */
diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
index db92abb96..9d314f3dc 100644
--- a/src/lib/gssapi/generic/gssapi_generic.c
+++ b/src/lib/gssapi/generic/gssapi_generic.c
@@ -118,6 +118,35 @@ static const gss_OID_desc const_oids[] = {
      * GSS_C_NT_EXPORT_NAME should be initialized to point
      * to that gss_OID_desc.
      */
+
+    /* 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.
@@ -146,3 +175,34 @@ GSS_DLLIMP gss_OID GSS_C_NT_ANONYMOUS           = oids+5;
 
 GSS_DLLIMP gss_OID GSS_C_NT_EXPORT_NAME         = oids+6;
 gss_OID gss_nt_exported_name         = oids+6;
+
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_CONCRETE     = oids+7;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_PSEUDO       = oids+8;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_COMPOSITE    = oids+9;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_NEGO         = oids+10;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MECH_GLUE         = oids+11;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_MECH          = oids+12;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DEPRECATED        = oids+13;
+GSS_DLLIMP gss_const_OID GSS_C_MA_NOT_DFLT_MECH     = oids+14;
+GSS_DLLIMP gss_const_OID GSS_C_MA_ITOK_FRAMED       = oids+15;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT         = oids+16;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG         = oids+17;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_INIT    = oids+18;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_INIT    = oids+19;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_INIT_ANON    = oids+20;
+GSS_DLLIMP gss_const_OID GSS_C_MA_AUTH_TARG_ANON    = oids+21;
+GSS_DLLIMP gss_const_OID GSS_C_MA_DELEG_CRED        = oids+22;
+GSS_DLLIMP gss_const_OID GSS_C_MA_INTEG_PROT        = oids+23;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CONF_PROT         = oids+24;
+GSS_DLLIMP gss_const_OID GSS_C_MA_MIC               = oids+25;
+GSS_DLLIMP gss_const_OID GSS_C_MA_WRAP              = oids+26;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PROT_READY        = oids+27;
+GSS_DLLIMP gss_const_OID GSS_C_MA_REPLAY_DET        = oids+28;
+GSS_DLLIMP gss_const_OID GSS_C_MA_OOS_DET           = oids+29;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CBINDINGS         = oids+30;
+GSS_DLLIMP gss_const_OID GSS_C_MA_PFS               = oids+31;
+GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS          = oids+32;
+GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS         = oids+33;
+
+static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+7 };
+gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c
new file mode 100644
index 000000000..62f2578f6
--- /dev/null
+++ b/src/lib/gssapi/generic/oid_ops.c
@@ -0,0 +1,113 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/oid_ops.c */
+/*
+ * Copyright 1995 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.
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* GSS-API V2 interfaces to manipulate OIDs */
+
+#include <gssapiP_generic.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+OM_uint32
+generic_gss_copy_oid_set(OM_uint32 *minor_status,
+                         const gss_OID_set_desc * const oidset,
+                         gss_OID_set *new_oidset)
+{
+    gss_OID_set_desc *copy;
+    OM_uint32 minor = 0;
+    OM_uint32 major = GSS_S_COMPLETE;
+    OM_uint32 i;
+
+    if (minor_status != NULL)
+        *minor_status = 0;
+
+    if (new_oidset != NULL)
+        *new_oidset = GSS_C_NO_OID_SET;
+
+    if (oidset == GSS_C_NO_OID_SET)
+        return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (new_oidset == NULL)
+        return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
+        major = GSS_S_FAILURE;
+        goto done;
+    }
+
+    if ((copy->elements = (gss_OID_desc *)
+         calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
+        major = GSS_S_FAILURE;
+        goto done;
+    }
+    copy->count = oidset->count;
+
+    for (i = 0; i < copy->count; i++) {
+        gss_OID_desc *out = &copy->elements[i];
+        gss_OID_desc *in = &oidset->elements[i];
+
+        if ((out->elements = (void *) malloc(in->length)) == NULL) {
+            major = GSS_S_FAILURE;
+            goto done;
+        }
+        (void) memcpy(out->elements, in->elements, in->length);
+        out->length = in->length;
+    }
+
+    *new_oidset = copy;
+done:
+    if (major != GSS_S_COMPLETE) {
+        (void) generic_gss_release_oid_set(&minor, &copy);
+    }
+
+    return (major);
+}
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 2bdcbeeb9..87a22b247 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -493,6 +493,12 @@ OM_uint32 krb5_gss_inquire_context
 	    int*              /* open */
 	   );
 
+OM_uint32 KRB5_CALLCONV
+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);
+
 /* New V2 entry points */
 OM_uint32 krb5_gss_get_mic
 (OM_uint32 *,		/* minor_status */
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index a0953e0b2..bc619c9d8 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -268,3 +268,53 @@ kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
     *minor_status = 0;
     return GSS_S_COMPLETE;
 }
+
+OM_uint32 KRB5_CALLCONV
+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_krb5)) {
+        MA_SUPPORTED(GSS_C_MA_DEPRECATED);
+    }
+
+cleanup:
+    if (GSS_ERROR(major))
+        gss_release_oid_set(&tmpMinor, mech_attrs);
+
+    return major;
+}
diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c
index 77cf0da5e..e8ffe1bd4 100644
--- a/src/lib/gssapi/krb5/krb5_gss_glue.c
+++ b/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -303,6 +303,13 @@ static OM_uint32 k5glue_inquire_names_for_mech
 	    gss_OID_set *		/* name_types */
 	   );
 
+static OM_uint32 k5glue_inquire_attrs_for_mech
+(void *, OM_uint32 *,           /* minor_status */
+           gss_const_OID,       /* mechanism */
+           gss_OID_set *,       /* mech_attrs */
+           gss_OID_set *        /* known_mech_attrs */
+           );
+
 #if 0
 static OM_uint32 k5glue_canonicalize_name
 (void *, OM_uint32  *,		/* minor_status */
@@ -363,6 +370,7 @@ static OM_uint32 k5glue_validate_cred
     k5glue_import_sec_context,				\
     k5glue_inquire_cred_by_mech,			\
     k5glue_inquire_names_for_mech,			\
+    k5glue_inquire_attrs_for_mech,                      \
     k5glue_inquire_context,				\
     k5glue_internal_release_oid,			\
     k5glue_wrap_size_limit,				\
@@ -747,6 +755,19 @@ k5glue_inquire_names_for_mech(ctx, minor_status, mechanism, name_types)
 					   name_types));
 }
 
+static OM_uint32
+k5glue_inquire_attrs_for_mech(ctx, minor_status, mech, mech_attrs,
+                              known_mech_attrs)
+    void *ctx;
+    OM_uint32 *minor_status;
+    gss_const_OID mech;
+    gss_OID_set *mech_attrs;
+    gss_OID_set *known_mech_attrs;
+{
+    return(krb5_gss_inquire_attrs_for_mech(minor_status, mech, mech_attrs,
+                                           known_mech_attrs));
+}
+
 #if 0
 /* V2 */
 static OM_uint32
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
index f8c9774a0..e17852317 100644
--- a/src/lib/gssapi/mechglue/Makefile.in
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -31,6 +31,7 @@ SRCS = \
 	$(srcdir)/g_inq_context.c \
 	$(srcdir)/g_inq_cred.c \
 	$(srcdir)/g_inq_names.c \
+	$(srcdir)/g_mechattr.c \
 	$(srcdir)/g_mechname.c \
 	$(srcdir)/g_oid_ops.c \
 	$(srcdir)/g_process_context.c \
@@ -65,6 +66,7 @@ OBJS = \
 	$(OUTPRE)g_inq_context.$(OBJEXT) \
 	$(OUTPRE)g_inq_cred.$(OBJEXT) \
 	$(OUTPRE)g_inq_names.$(OBJEXT) \
+	$(OUTPRE)g_mechattr.$(OBJEXT) \
 	$(OUTPRE)g_mechname.$(OBJEXT) \
 	$(OUTPRE)g_oid_ops.$(OBJEXT) \
 	$(OUTPRE)g_process_context.$(OBJEXT) \
@@ -99,6 +101,7 @@ STLIBOBJS = \
 	g_inq_context.o \
 	g_inq_cred.o \
 	g_inq_names.o \
+	g_mechattr.o \
 	g_mechname.o \
 	g_oid_ops.o \
 	g_process_context.o \
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index b4a668a55..a5f7fe221 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -124,34 +124,78 @@ gss_OID *oid;
 	return (generic_gss_release_oid(minor_status, oid));
 } /* gss_release_oid */
 
+/*
+ * Wrapper around inquire_attrs_for_mech to determine whether a mechanism has
+ * the deprecated attribute.  Must be called without g_mechSetLock since it
+ * will call into the mechglue.
+ */
+static int
+is_deprecated(gss_OID element)
+{
+	OM_uint32 major, minor;
+	gss_OID_set mech_attrs = GSS_C_NO_OID_SET;
+	int deprecated = 0;
+
+	major = gss_inquire_attrs_for_mech(&minor, element, &mech_attrs, NULL);
+	if (major == GSS_S_COMPLETE) {
+		gss_test_oid_set_member(&minor, (gss_OID)GSS_C_MA_DEPRECATED,
+					mech_attrs, &deprecated);
+	}
+
+	if (mech_attrs != GSS_C_NO_OID_SET)
+		gss_release_oid_set(&minor, &mech_attrs);
+
+	return deprecated;
+}
+
+/*
+ * Removes mechs with the deprecated attribute from an OID set.  Must be
+ * called without g_mechSetLock held since it calls into the mechglue.
+ */
+static void
+prune_deprecated(gss_OID_set mech_set)
+{
+	OM_uint32 i, j;
+
+	j = 0;
+	for (i = 0; i < mech_set->count; i++) {
+	    if (!is_deprecated(&mech_set->elements[i]))
+		mech_set->elements[j++] = mech_set->elements[i];
+	    else
+		free(mech_set->elements[i].elements);
+	}
+	mech_set->count = j;
+}
 
 /*
  * this function will return an oid set indicating available mechanisms.
  * The set returned is based on configuration file entries and
  * NOT on the loaded mechanisms.  This function does not check if any
  * of these can actually be loaded.
+ * Deprecated mechanisms will not be returned.
  * This routine needs direct access to the mechanism list.
  * To avoid reading the configuration file each call, we will save a
  * a mech oid set, and only update it once the file has changed.
  */
 OM_uint32 KRB5_CALLCONV
-gss_indicate_mechs(minorStatus, mechSet)
+gss_indicate_mechs(minorStatus, mechSet_out)
 OM_uint32 *minorStatus;
-gss_OID_set *mechSet;
+gss_OID_set *mechSet_out;
 {
 	int i, j;
 	gss_OID curItem;
+	gss_OID_set mechSet;
 
 	/* Initialize outputs. */
 
 	if (minorStatus != NULL)
 		*minorStatus = 0;
 
-	if (mechSet != NULL)
-		*mechSet = GSS_C_NO_OID_SET;
+	if (mechSet_out != NULL)
+		*mechSet_out = GSS_C_NO_OID_SET;
 
 	/* Validate arguments. */
-	if (minorStatus == NULL || mechSet == NULL)
+	if (minorStatus == NULL || mechSet_out == NULL)
 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
 
 	if (gssint_initialize_library())
@@ -164,7 +208,7 @@ gss_OID_set *mechSet;
 	 * the mech set is created and it is up to date
 	 * so just copy it to caller
 	 */
-	if ((*mechSet =
+	if ((mechSet =
 		(gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL)
 	{
 		return (GSS_S_FAILURE);
@@ -177,25 +221,24 @@ gss_OID_set *mechSet;
 	(void) k5_mutex_lock(&g_mechSetLock);
 
 	/* allocate space for the oid structures */
-	if (((*mechSet)->elements =
+	if ((mechSet->elements =
 		(void*) calloc(g_mechSet.count, sizeof (gss_OID_desc)))
 		== NULL)
 	{
 		(void) k5_mutex_unlock(&g_mechSetLock);
-		free(*mechSet);
-		*mechSet = NULL;
+		free(mechSet);
 		return (GSS_S_FAILURE);
 	}
 
 	/* now copy the oid structures */
-	(void) memcpy((*mechSet)->elements, g_mechSet.elements,
+	(void) memcpy(mechSet->elements, g_mechSet.elements,
 		g_mechSet.count * sizeof (gss_OID_desc));
 
-	(*mechSet)->count = g_mechSet.count;
+	mechSet->count = g_mechSet.count;
 
 	/* still need to copy each of the oid elements arrays */
-	for (i = 0; i < (*mechSet)->count; i++) {
-		curItem = &((*mechSet)->elements[i]);
+	for (i = 0; i < mechSet->count; i++) {
+		curItem = &(mechSet->elements[i]);
 		curItem->elements =
 			(void *) malloc(g_mechSet.elements[i].length);
 		if (curItem->elements == NULL) {
@@ -205,16 +248,21 @@ gss_OID_set *mechSet;
 			 * each allocated gss_OID_desc
 			 */
 			for (j = 0; j < i; j++) {
-				free((*mechSet)->elements[j].elements);
+				free(mechSet->elements[j].elements);
 			}
-			free((*mechSet)->elements);
-			free(*mechSet);
-			*mechSet = NULL;
+			free(mechSet->elements);
+			free(mechSet);
 			return (GSS_S_FAILURE);
 		}
 		g_OID_copy(curItem, &g_mechSet.elements[i]);
 	}
 	(void) k5_mutex_unlock(&g_mechSetLock);
+
+        *mechSet_out = mechSet;
+
+	if (*mechSet_out != GSS_C_NO_OID_SET)
+		prune_deprecated(*mechSet_out);
+
 	return (GSS_S_COMPLETE);
 } /* gss_indicate_mechs */
 
diff --git a/src/lib/gssapi/mechglue/g_mechattr.c b/src/lib/gssapi/mechglue/g_mechattr.c
new file mode 100644
index 000000000..69f5fb77a
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_mechattr.c
@@ -0,0 +1,86 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* 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"
+
+OM_uint32 KRB5_CALLCONV
+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(mech->context,
+                                                  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;
+}
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index ce40f8e87..684a40d8e 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -323,6 +323,14 @@ typedef struct gss_config {
 		    gss_OID,		/* mechanism */
 		    gss_OID_set *	/* name_types */
 		    );
+    OM_uint32       (*gss_inquire_attrs_for_mech)
+        (
+                    void *,             /* context */
+                    OM_uint32 *,        /* minor_status */
+                    gss_OID,            /* mechanism */
+                    gss_OID_set *,      /* mech_attrs */
+                    gss_OID_set *       /* known_mech_attrs */
+                    );
     OM_uint32	(*gss_inquire_context)
 	(
 		    void *,		/* context */
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index 09b45a98f..a24fbf555 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -340,6 +340,16 @@ OM_uint32 spnego_gss_verify
 	int *qop_state
 );
 
+OM_uint32
+spnego_gss_inquire_attrs_for_mech
+(
+       void *context,
+       OM_uint32 *minor_status,
+       gss_const_OID mech,
+       gss_OID_set *mech_attrs,
+       gss_OID_set *known_mech_attrs
+);
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 73b161f7e..8913b658d 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -184,6 +184,7 @@ static struct gss_config spnego_mechanism =
 	spnego_gss_import_sec_context,	/* gss_import_sec_context */
 	NULL, 				/* gss_inquire_cred_by_mech */
 	spnego_gss_inquire_names_for_mech,
+	spnego_gss_inquire_attrs_for_mech,
 	spnego_gss_inquire_context,	/* gss_inquire_context */
 	NULL,				/* gss_internal_release_oid */
 	spnego_gss_wrap_size_limit,	/* gss_wrap_size_limit */
@@ -1716,6 +1717,42 @@ spnego_gss_verify(void *context,
 	return (ret);
 }
 
+OM_uint32
+spnego_gss_inquire_attrs_for_mech(void *context,
+                                  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
-- 
2.19.2

