Merge branch 'master' into tlv-mic
authorLuke Howard <lukeh@padl.com>
Mon, 28 Mar 2011 22:37:38 +0000 (09:37 +1100)
committerLuke Howard <lukeh@padl.com>
Mon, 28 Mar 2011 22:37:38 +0000 (09:37 +1100)
Conflicts:
mech_eap/export_sec_context.c
mech_eap/import_sec_context.c

25 files changed:
.gitmodules
builder
jansson [new submodule]
mech_eap/Makefile.am
mech_eap/acinclude.m4
mech_eap/configure.ac
mech_eap/export_sec_context.c
mech_eap/gssapiP_eap.h
mech_eap/util.h
mech_eap/util_attr.cpp
mech_eap/util_attr.h
mech_eap/util_base64.c [new file with mode: 0644]
mech_eap/util_base64.h [new file with mode: 0644]
mech_eap/util_json.cpp [new file with mode: 0644]
mech_eap/util_json.h [new file with mode: 0644]
mech_eap/util_name.c
mech_eap/util_radius.cpp
mech_eap/util_radius.h
mech_eap/util_saml.cpp
mech_eap/util_saml.h
mech_eap/util_shib.cpp
mech_eap/util_shib.h
shibboleth/resolver
shibboleth/xmltooling
source_packages

index 5070418..2513885 100644 (file)
@@ -25,3 +25,6 @@
 [submodule "openssh"]
        path = openssh
        url = http://www.project-moonshot.org/git/openssh.git
+[submodule "jansson"]
+       path = jansson
+       url = git://github.com/akheron/jansson.git
diff --git a/builder b/builder
index 9666bd0..0b45f46 100755 (executable)
--- a/builder
+++ b/builder
@@ -129,7 +129,7 @@ configure_opts = ['--prefix', prefix,
                   + " -Wl,-rpath="+prefix+"/lib'",
                   'CPPFLAGS="-I '+prefix+'/include"',
                   '--with-system-libtool', '--with-system-libltdl',
-                  '--enable-tls',
+                  '--enable-tls', '--with-gssapi='+prefix,
                   "--with-xmltooling="+prefix, 
                   ]
 if options.configure_opts is not None: 
diff --git a/jansson b/jansson
new file mode 160000 (submodule)
index 0000000..279d8bf
--- /dev/null
+++ b/jansson
@@ -0,0 +1 @@
+Subproject commit 279d8bf108bd1367bdd3647e881146e1acf0123d
index f87406a..163b9e0 100644 (file)
@@ -16,7 +16,7 @@ mech_eap_la_LDFLAGS  = -avoid-version -module \
                        -export-symbols mech_eap.exports -no-undefined \
                        @EAP_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
 mech_eap_la_LIBADD   = @KRB5_LIBS@ @EAP_LIBS@ @RADSEC_LIBS@ \
-                      @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@
+                      @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@
 
 mech_eap_la_SOURCES =                          \
        accept_sec_context.c                    \
@@ -70,11 +70,13 @@ mech_eap_la_SOURCES =                       \
        unwrap_iov.c                            \
        userok.c                                \
        util_attr.cpp                           \
+       util_base64.c                           \
        util_buffer.c                           \
        util_context.c                          \
        util_cksum.c                            \
        util_cred.c                             \
        util_crypt.c                            \
+       util_json.cpp                           \
        util_krb.c                              \
        util_lucid.c                            \
        util_mech.c                             \
index ad31df8..eab00b4 100644 (file)
@@ -220,3 +220,41 @@ else
        AC_SUBST(RADSEC_LIBS)
 fi
 ])dnl
+
+AC_DEFUN([AX_CHECK_JANSSON],
+[AC_MSG_CHECKING(for jansson)
+JANSSON_DIR=
+found_jansson="no"
+AC_ARG_WITH(jansson,
+    AC_HELP_STRING([--with-jansson],
+       [Use jansson (in specified installation directory)]),
+    [check_jansson_dir="$withval"],
+    [check_jansson_dir=])
+for dir in $check_jansson_dir $prefix /usr /usr/local ; do
+   janssondir="$dir"
+   if test -f "$dir/include/jansson.h"; then
+     found_jansson="yes";
+     JANSSON_DIR="${janssondir}"
+     JANSSON_CFLAGS="-I$janssondir/include";
+     break;
+   fi
+done
+AC_MSG_RESULT($found_jansson)
+if test x_$found_jansson != x_yes; then
+   AC_MSG_ERROR([
+----------------------------------------------------------------------
+  Cannot find jansson libraries.
+
+  Please install libjansson or specify installation directory with
+  --with-jansson=(dir).
+----------------------------------------------------------------------
+])
+else
+       printf "jansson found in $janssondir\n";
+       JANSSON_LIBS="-ljansson";
+       JANSSON_LDFLAGS="-L$janssondir/lib";
+       AC_SUBST(JANSSON_CFLAGS)
+       AC_SUBST(JANSSON_LDFLAGS)
+       AC_SUBST(JANSSON_LIBS)
+fi
+])dnl
index 0115b0b..a7e6942 100644 (file)
@@ -51,5 +51,6 @@ AX_CHECK_EAP
 AX_CHECK_SHIBSP
 AX_CHECK_SHIBRESOLVER
 AX_CHECK_RADSEC
+AX_CHECK_JANSSON
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
index eb52b40..91f032f 100644 (file)
@@ -50,8 +50,12 @@ exportPartialRadiusContext(OM_uint32 *minor,
     if (ctx->acceptorCtx.radConn != NULL) {
         if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn,
                                      serverBuf, sizeof(serverBuf)) != 0) {
+#if 0
             return gssEapRadiusMapError(minor,
                                         rs_err_conn_pop(ctx->acceptorCtx.radConn));
+#else
+            serverBuf[0] = '\0'; /* not implemented yet */
+#endif
         }
         serverLen = strlen(serverBuf);
     }
@@ -95,7 +99,7 @@ cleanup:
     return major;
 }
 
-static OM_uint32
+OM_uint32
 gssEapExportSecContext(OM_uint32 *minor,
                        gss_ctx_id_t ctx,
                        gss_buffer_t token)
@@ -124,6 +128,7 @@ gssEapExportSecContext(OM_uint32 *minor,
         if (GSS_ERROR(major))
             goto cleanup;
     }
+
     if (ctx->acceptorName != GSS_C_NO_NAME) {
         major = gssEapExportNameInternal(minor, ctx->acceptorName,
                                          &acceptorName,
@@ -136,10 +141,9 @@ gssEapExportSecContext(OM_uint32 *minor,
      * The partial context is only transmitted for unestablished acceptor
      * contexts.
      */
-    if (!CTX_IS_INITIATOR(ctx) &&
-        !CTX_IS_ESTABLISHED(ctx) &&
-        ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0)) {
-        major = exportPartialRadiusContext(minor, ctx, &partialCtx);
+    if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
+        (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
+        major = gssEapExportPartialContext(minor, ctx, &partialCtx);
         if (GSS_ERROR(major))
             goto cleanup;
     }
index c11b21b..7cf31cf 100644 (file)
@@ -264,6 +264,13 @@ gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
 #define IS_WIRE_ERROR(err)              ((err) > GSSEAP_RESERVED && \
                                          (err) <= GSSEAP_RADIUS_PROT_FAILURE)
 
+/* export_sec_context.c */
+OM_uint32
+gssEapExportSecContext(OM_uint32 *minor,
+                       gss_ctx_id_t ctx,
+                       gss_buffer_t token);
+
+
 #ifdef __cplusplus
 }
 #endif
index 0c59266..9478cb6 100644 (file)
@@ -472,8 +472,8 @@ gss_OID
 gssEapSaslNameToOid(const gss_buffer_t name);
 
 /* util_name.c */
-#define EXPORT_NAME_FLAG_OID        0x1
-#define EXPORT_NAME_FLAG_COMPOSITE  0x2
+#define EXPORT_NAME_FLAG_OID                    0x1
+#define EXPORT_NAME_FLAG_COMPOSITE              0x2
 
 OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
 OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
@@ -483,7 +483,7 @@ OM_uint32 gssEapExportName(OM_uint32 *minor,
 OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
                                    const gss_name_t name,
                                    gss_buffer_t exportedName,
-                                   unsigned int flags);
+                                   OM_uint32 flags);
 OM_uint32 gssEapImportName(OM_uint32 *minor,
                            const gss_buffer_t input_name_buffer,
                            const gss_OID input_name_type,
@@ -492,7 +492,7 @@ OM_uint32 gssEapImportName(OM_uint32 *minor,
 OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
                                    const gss_buffer_t input_name_buffer,
                                    gss_name_t *output_name,
-                                   unsigned int flags);
+                                   OM_uint32 flags);
 OM_uint32
 gssEapDuplicateName(OM_uint32 *minor,
                     const gss_name_t input_name,
@@ -888,7 +888,9 @@ gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
 }
 #endif
 
+#include "util_json.h"
 #include "util_attr.h"
+#include "util_base64.h"
 #ifdef GSSEAP_ENABLE_REAUTH
 #include "util_reauth.h"
 #endif
index 9d4827d..dacdf14 100644 (file)
@@ -38,7 +38,9 @@
 
 #include <typeinfo>
 #include <string>
+#include <sstream>
 #include <exception>
+#include <stdexcept>
 #include <new>
 
 /* lazy initialisation */
@@ -273,58 +275,27 @@ gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
     return ret;
 }
 
-#define UPDATE_REMAIN(n)    do {                \
-        p += (n);                               \
-        remain -= (n);                          \
-    } while (0)
-
-#define CHECK_REMAIN(n)     do {                \
-        if (remain < (n)) {                     \
-            return false;                       \
-        }                                       \
-    } while (0)
-
-/*
- * Initialize a context from an exported context or name token
- */
 bool
-gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
 {
     bool ret = false;
-    size_t remain = buffer->length;
-    unsigned char *p = (unsigned char *)buffer->value;
-    bool didInit[ATTR_TYPE_MAX + 1];
+    bool foundSource[ATTR_TYPE_MAX + 1];
     unsigned int type;
 
     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
-        didInit[type] = false;
-
-    /* flags */
-    CHECK_REMAIN(4);
-    m_flags = load_uint32_be(p);
-    UPDATE_REMAIN(4);
+        foundSource[type] = false;
 
-    while (remain) {
-        OM_uint32 type;
-        gss_buffer_desc providerToken;
-        gss_eap_attr_provider *provider;
-
-        /* TLV encoding of provider type, length, value */
-        CHECK_REMAIN(4);
-        type = load_uint32_be(p);
-        UPDATE_REMAIN(4);
+    if (obj["version"].integer() != 1)
+        return false;
 
-        CHECK_REMAIN(4);
-        providerToken.length = load_uint32_be(p);
-        UPDATE_REMAIN(4);
+    m_flags = obj["flags"].integer();
 
-        CHECK_REMAIN(providerToken.length);
-        providerToken.value = p;
-        UPDATE_REMAIN(providerToken.length);
+    JSONObject sources = obj["sources"];
 
-        if (type < ATTR_TYPE_MIN || type > ATTR_TYPE_MAX ||
-            didInit[type])
-            return false;
+    /* Initialize providers from serialized state */
+    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+        gss_eap_attr_provider *provider;
+        const char *key;
 
         if (!providerEnabled(type)) {
             releaseProvider(type);
@@ -332,27 +303,25 @@ gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
         }
 
         provider = m_providers[type];
+        key = provider->name();
+        if (key == NULL)
+            continue;
 
-        ret = provider->initFromBuffer(this, &providerToken);
-        if (ret == false) {
+        JSONObject source = sources.get(key);
+        if (!source.isnull() &&
+            !provider->initWithJsonObject(this, source)) {
             releaseProvider(type);
-            break;
+            return false;
         }
-        didInit[type] = true;
-    }
 
-    if (ret == false)
-        return ret;
+        foundSource[type] = true;
+    }
 
-    /*
-     * The call the initFromGssContext methods for attribute
-     * providers that can initialize themselves from other
-     * providers.
-     */
+    /* Initialize remaining providers from initialized providers */
     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
         gss_eap_attr_provider *provider;
 
-        if (didInit[type] || !providerEnabled(type))
+        if (foundSource[type] || !providerEnabled(type))
             continue;
 
         provider = m_providers[type];
@@ -369,6 +338,62 @@ gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
     return true;
 }
 
+JSONObject
+gss_eap_attr_ctx::jsonRepresentation(void) const
+{
+    JSONObject obj, sources;
+    unsigned int i;
+
+    obj.set("version", 1);
+    obj.set("flags", m_flags);
+
+    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+        gss_eap_attr_provider *provider;
+        const char *key;
+
+        provider = m_providers[i];
+        if (provider == NULL)
+            continue; /* provider not initialised */
+
+        key = provider->name();
+        if (key == NULL)
+            continue; /* provider does not have state */
+
+        JSONObject source = provider->jsonRepresentation();
+        sources.set(key, source);
+    }
+
+    obj.set("sources", sources);
+
+    return obj;
+}
+
+/*
+ * Initialize a context from an exported context or name token
+ */
+bool
+gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
+{
+    OM_uint32 major, minor;
+    bool ret;
+    char *s;
+    json_error_t error;
+
+    major = bufferToString(&minor, buffer, &s);
+    if (GSS_ERROR(major))
+        return false;
+
+    JSONObject obj = JSONObject::load(s, 0, &error);
+    if (!obj.isnull()) {
+        ret = initWithJsonObject(obj);
+    } else
+        ret = false;
+
+    GSSEAP_FREE(s);
+
+    return ret;
+}
+
 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
 {
     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
@@ -502,10 +527,8 @@ gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
     unsigned int i;
 
     major = gss_create_empty_buffer_set(&minor, attrs);
-    if (GSS_ERROR(major)) {
+    if (GSS_ERROR(major))
         throw new std::bad_alloc;
-        return false;
-    }
 
     args.attrs = *attrs;
 
@@ -601,51 +624,19 @@ gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
 void
 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
 {
-    OM_uint32 tmpMinor;
-    gss_buffer_desc providerTokens[ATTR_TYPE_MAX + 1];
-    size_t length = 4; /* m_flags */
-    unsigned char *p;
-    unsigned int i;
+    OM_uint32 minor;
+    char *s;
 
-    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-        providerTokens[i].length = 0;
-        providerTokens[i].value = NULL;
-    }
+    JSONObject obj = jsonRepresentation();
 
-    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-        gss_eap_attr_provider *provider = m_providers[i];
-
-        if (provider == NULL)
-            continue;
-
-        provider->exportToBuffer(&providerTokens[i]);
+#if 0
+    obj.dump(stdout, JSON_INDENT(3));
+#endif
 
-        if (providerTokens[i].value != NULL)
-            length += 8 + providerTokens[i].length;
-    }
+    s = obj.dump(JSON_COMPACT);
 
-    buffer->length = length;
-    buffer->value = GSSEAP_MALLOC(length);
-    if (buffer->value == NULL)
+    if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
         throw new std::bad_alloc;
-
-    p = (unsigned char *)buffer->value;
-    store_uint32_be(m_flags, p);
-    p += 4;
-
-    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
-        if (providerTokens[i].value == NULL)
-            continue;
-
-        store_uint32_be(i, p);
-        p += 4;
-        store_uint32_be(providerTokens[i].length, p);
-        p += 4;
-        memcpy(p, providerTokens[i].value, providerTokens[i].length);
-        p += providerTokens[i].length;
-
-        gss_release_buffer(&tmpMinor, &providerTokens[i]);
-    }
 }
 
 /*
@@ -1145,12 +1136,10 @@ gssEapCreateAttrContext(OM_uint32 *minor,
     major = GSS_S_FAILURE;
 
     try {
-        ctx = new gss_eap_attr_ctx();
+        *pAttrContext = ctx = new gss_eap_attr_ctx();
         if (ctx->initFromGssContext(gssCred, gssCtx)) {
             *minor = 0;
             major = GSS_S_COMPLETE;
-        } else {
-            delete ctx;
         }
     } catch (std::exception &e) {
         if (ctx != NULL)
@@ -1158,8 +1147,10 @@ gssEapCreateAttrContext(OM_uint32 *minor,
     }
 
     if (major == GSS_S_COMPLETE) {
-        *pAttrContext = ctx;
         *pExpiryTime = ctx->getExpiryTime();
+    } else {
+        delete ctx;
+        *pAttrContext = NULL;
     }
 
     return major;
index 6af4cf3..e391df1 100644 (file)
@@ -41,6 +41,8 @@
 #include <string>
 #include <new>
 
+using namespace gss_eap_util;
+
 struct gss_eap_attr_provider;
 struct gss_eap_attr_ctx;
 
@@ -121,26 +123,36 @@ public:
     {
         return NULL;
     }
+
     virtual void releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
                                        gss_any_t input GSSEAP_UNUSED) const
     {
     }
 
+    /* prefix to be prepended to attributes emitted by gss_get_name_attribute */
     virtual const char *prefix(void) const
     {
         return NULL;
     }
 
-    virtual void exportToBuffer(gss_buffer_t buffer GSSEAP_UNUSED) const
+    /* optional key for storing JSON dictionary */
+    virtual const char *name(void) const
     {
+        return NULL;
     }
 
-    virtual bool initFromBuffer(const gss_eap_attr_ctx *manager,
-                                const gss_buffer_t buffer GSSEAP_UNUSED)
+    virtual bool initWithJsonObject(const gss_eap_attr_ctx *manager,
+                                    JSONObject &object GSSEAP_UNUSED)
     {
         return initWithManager(manager);
     }
 
+
+    virtual JSONObject jsonRepresentation(void) const
+    {
+        return JSONObject::null();
+    }
+
     virtual time_t getExpiryTime(void) const { return 0; }
 
     virtual OM_uint32 mapException(OM_uint32 *minor GSSEAP_UNUSED,
@@ -242,6 +254,9 @@ private:
     unsigned int attributePrefixToType(const gss_buffer_t prefix) const;
     gss_buffer_desc attributeTypeToPrefix(unsigned int type) const;
 
+    bool initWithJsonObject(JSONObject &object);
+    JSONObject jsonRepresentation(void) const;
+
     gss_eap_attr_provider *getPrimaryProvider(void) const;
 
     /* make non-copyable */
diff --git a/mech_eap/util_base64.c b/mech_eap/util_base64.c
new file mode 100644 (file)
index 0000000..8d13aaf
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "gssapiP_eap.h"
+
+static const char base64_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int
+pos(char c)
+{
+    const char *p;
+    for (p = base64_chars; *p; p++)
+       if (*p == c)
+           return p - base64_chars;
+    return -1;
+}
+
+int
+base64Encode(const void *data, int size, char **str)
+{
+    char *s, *p;
+    int i;
+    int c;
+    const unsigned char *q;
+
+    if (size > INT_MAX/4 || size < 0) {
+       *str = NULL;
+       return -1;
+    }
+
+    p = s = (char *)GSSEAP_MALLOC(BASE64_EXPAND(size));
+    if (p == NULL) {
+        *str = NULL;
+       return -1;
+    }
+    q = (const unsigned char *) data;
+
+    for (i = 0; i < size;) {
+       c = q[i++];
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       c *= 256;
+       if (i < size)
+           c += q[i];
+       i++;
+       p[0] = base64_chars[(c & 0x00fc0000) >> 18];
+       p[1] = base64_chars[(c & 0x0003f000) >> 12];
+       p[2] = base64_chars[(c & 0x00000fc0) >> 6];
+       p[3] = base64_chars[(c & 0x0000003f) >> 0];
+       if (i > size)
+           p[3] = '=';
+       if (i > size + 1)
+           p[2] = '=';
+       p += 4;
+    }
+    *p = 0;
+    *str = s;
+    return (int) strlen(s);
+}
+
+#define DECODE_ERROR 0xffffffff
+
+static unsigned int
+token_decode(const char *token)
+{
+    int i;
+    unsigned int val = 0;
+    int marker = 0;
+    if (strlen(token) < 4)
+       return DECODE_ERROR;
+    for (i = 0; i < 4; i++) {
+       val *= 64;
+       if (token[i] == '=')
+           marker++;
+       else if (marker > 0)
+           return DECODE_ERROR;
+       else
+           val += pos(token[i]);
+    }
+    if (marker > 2)
+       return DECODE_ERROR;
+    return (marker << 24) | val;
+}
+
+int
+base64Decode(const char *str, void *data)
+{
+    const char *p;
+    unsigned char *q;
+
+    q = data;
+    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+       unsigned int val = token_decode(p);
+       unsigned int marker = (val >> 24) & 0xff;
+       if (val == DECODE_ERROR)
+           return -1;
+       *q++ = (val >> 16) & 0xff;
+       if (marker < 2)
+           *q++ = (val >> 8) & 0xff;
+       if (marker < 1)
+           *q++ = val & 0xff;
+    }
+    return q - (unsigned char *) data;
+}
diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h
new file mode 100644 (file)
index 0000000..84313e4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _UTIL_BASE64_H_
+#define _UTIL_BASE64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+base64Encode(const void *, int, char **);
+
+int
+base64Decode(const char *, void *);
+
+#define BASE64_EXPAND(n)        (n * 4 / 3 + 4)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mech_eap/util_json.cpp b/mech_eap/util_json.cpp
new file mode 100644 (file)
index 0000000..76cf31c
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * JSONObject utilities.
+ */
+
+#include "gssapiP_eap.h"
+
+#include <typeinfo>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <stdexcept>
+#include <new>
+
+#define JSON_INIT(obj) do {                                     \
+        if ((obj) == NULL)                                      \
+            throw new std::bad_alloc;                           \
+        m_obj = (obj);                                          \
+    } while (0)
+
+#define JSON_CHECK_CONTAINER() do {                             \
+        if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
+            std::string s("JSONObject is not a container");     \
+            throw new std::runtime_error(s);                    \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK_OBJECT() do {                                \
+        if (!json_is_object(m_obj)) {                           \
+            std::string s("JSONObject is not a dictionary");    \
+            throw new std::runtime_error(s);                    \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK_ARRAY() do {                                 \
+        if (!json_is_array(m_obj)) {                            \
+            std::string s("JSONObject is not an array");        \
+            throw new std::runtime_error(s);                    \
+        }                                                       \
+    } while (0)
+
+#define JSON_CHECK(s) do {              \
+        if ((s) != 0)                   \
+            throw new std::bad_alloc;   \
+    } while (0)
+
+JSONObject
+JSONObject::load(const char *input, size_t flags, json_error_t *error)
+{
+    json_t *obj;
+
+    obj = json_loads(input, flags, error);
+
+    return JSONObject(obj, false);
+}
+
+JSONObject
+JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
+{
+    json_t *obj;
+
+    obj = json_loadf(fp, flags, error);
+
+    return JSONObject(obj, false);
+}
+
+char *
+JSONObject::dump(size_t flags) const
+{
+    char *s = json_dumps(m_obj, flags);
+
+    if (s == NULL)
+        throw new std::bad_alloc;
+
+    return s;
+}
+
+void
+JSONObject::dump(FILE *fp, size_t flags) const
+{
+    int r = json_dumpf(m_obj, fp, flags);
+
+    if (r != 0)
+        throw new std::bad_alloc;
+}
+
+size_t
+JSONObject::size(void) const
+{
+    if (json_is_object(m_obj))
+        return json_object_size(m_obj);
+    else if (json_is_array(m_obj))
+        return json_array_size(m_obj);
+    else
+        return 0;
+}
+
+JSONObject::JSONObject(json_t *obj, bool retain)
+{
+    if (retain)
+        json_incref(obj);
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(const char *value)
+{
+    json_t *obj = json_string(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(json_int_t value)
+{
+    json_t *obj = json_integer(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(double value)
+{
+    json_t *obj = json_real(value);
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(bool value)
+{
+    json_t *obj = value ? json_true() : json_false();
+
+    JSON_INIT(obj);
+}
+
+JSONObject::JSONObject(void)
+{
+    json_t *obj = json_object();
+
+    JSON_INIT(obj);
+}
+
+JSONObject
+JSONObject::object(void)
+{
+    return JSONObject();
+}
+
+JSONObject
+JSONObject::null(void)
+{
+    return JSONObject(json_null(), false);
+}
+
+JSONObject
+JSONObject::array(void)
+{
+    return JSONObject(json_array(), false);
+}
+
+void
+JSONObject::set(const char *key, JSONObject &value)
+{
+    JSON_CHECK_OBJECT();
+    JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
+}
+
+void
+JSONObject::set(const char *key, const char *value)
+{
+    JSONObject jobj(value);
+    set(key, jobj);
+}
+
+void
+JSONObject::set(const char *key, json_int_t value)
+{
+    JSONObject jobj(value);
+    set(key, jobj);
+}
+
+void
+JSONObject::del(const char *key)
+{
+    json_object_del(m_obj, key);
+}
+
+JSONObject
+JSONObject::get(const char *key) const
+{
+    json_t *obj;
+
+    obj = json_object_get(m_obj, key);
+    if (obj == NULL)
+        return JSONObject::null();
+
+    return JSONObject(obj, true);
+}
+
+JSONObject
+JSONObject::get(size_t index) const
+{
+    json_t *obj;
+
+    obj = json_array_get(m_obj, index);
+    if (obj == NULL)
+        return JSONObject::null();
+
+    return JSONObject(obj, true);
+}
+
+void
+JSONObject::update(JSONObject &value)
+{
+    JSON_CHECK_OBJECT();
+    json_t *other = value.get();
+    JSON_CHECK(json_object_update(m_obj, other));
+    json_decref(other);
+}
+
+JSONObject
+JSONObject::operator[](size_t index) const
+{
+    return get(index);
+}
+
+JSONObject
+JSONObject::operator[](const char *key) const
+{
+    return get(key);
+}
+
+void
+JSONObject::append(JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_append_new(m_obj, value.get()));
+}
+
+void
+JSONObject::insert(size_t index, JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
+}
+
+void
+JSONObject::remove(size_t index)
+{
+    JSON_CHECK_ARRAY();
+    JSON_CHECK(json_array_remove(m_obj, index));
+}
+
+void
+JSONObject::clear(void)
+{
+    JSON_CHECK_CONTAINER();
+
+    if (json_is_object(m_obj)) {
+        JSON_CHECK(json_object_clear(m_obj));
+    } else if (json_is_array(m_obj)) {
+        JSON_CHECK(json_array_clear(m_obj));
+    }
+}
+
+void
+JSONObject::extend(JSONObject &value)
+{
+    JSON_CHECK_ARRAY();
+    json_t *other = value.get();
+    JSON_CHECK(json_array_extend(m_obj, other));
+    json_decref(other);
+}
+
+const char *
+JSONObject::string(void) const
+{
+    return json_string_value(m_obj);
+}
+
+json_int_t
+JSONObject::integer(void) const
+{
+    return json_integer_value(m_obj);
+}
+
+double
+JSONObject::real(void) const
+{
+    return json_real_value(m_obj);
+}
+
+double
+JSONObject::number(void) const
+{
+    return json_number_value(m_obj);
+}
+
+bool
+JSONObject::isnull(void) const
+{
+    return json_is_null(m_obj);
+}
+
+JSONObject::JSONObject(DDF &ddf)
+{
+    if (ddf.isstruct()) {
+        DDF elem = ddf.first();
+        JSONObject jobj = JSONObject::array();
+
+        while (!elem.isnull()) {
+            JSONObject jtmp(elem);
+            jobj.append(jtmp);
+            elem = ddf.next();
+        }
+    } else if (ddf.islist()) {
+        DDF elem = ddf.first();
+        JSONObject jobj = JSONObject::object();
+
+        while (!elem.isnull()) {
+            JSONObject jtmp(elem);
+            jobj.set(elem.name(), jtmp);
+            elem = ddf.next();
+        }
+    } else if (ddf.isstring()) {
+        JSONObject(ddf.string());
+    } else if (ddf.isint()) {
+        JSONObject((json_int_t)ddf.integer());
+    } else if (ddf.isfloat()) {
+        JSONObject(ddf.floating());
+    } else if (ddf.isempty() || ddf.ispointer()) {
+        JSONObject::object();
+    } else if (ddf.isnull()) {
+        JSONObject::null();
+    }
+
+    std::string s("Unbridgeable DDF object");
+    throw new std::runtime_error(s);
+}
+
+DDF
+JSONObject::ddf(void) const
+{
+    DDF ddf(NULL);
+
+    switch (type()) {
+    case JSON_OBJECT: {
+        JSONIterator iter = iterator();
+
+        do {
+            const char *key = iter.key();
+            DDF value = iter.value().ddf();
+            ddf.add(value.name(key));
+        } while (iter.next());
+        break;
+    }
+    case JSON_ARRAY: {
+        size_t i, nelems = size();
+
+        for (i = 0; i < nelems; i++) {
+            DDF value = get(i).ddf();
+            ddf.add(value);
+        }
+        break;
+    }
+    case JSON_STRING:
+        ddf.string(string());
+        break;
+    case JSON_INTEGER:
+        ddf.integer(integer());
+        break;
+    case JSON_REAL:
+        ddf.floating(real());
+        break;
+    case JSON_TRUE:
+        ddf.integer(1L);
+        break;
+    case JSON_FALSE:
+        ddf.integer(0L);
+        break;
+    case JSON_NULL:
+        break;
+    }
+
+    return DDF(NULL);
+}
+
+JSONIterator::JSONIterator(const JSONObject &obj)
+{
+    m_obj = obj.get();
+    m_iter = json_object_iter(m_obj);
+}
+
+JSONIterator::~JSONIterator(void)
+{
+    json_decref(m_obj);
+}
+
+const char *
+JSONIterator::key(void) const
+{
+    return json_object_iter_key(m_iter);
+}
+
+JSONObject
+JSONIterator::value(void) const
+{
+    return JSONObject(json_object_iter_value(m_iter));
+}
+
+bool
+JSONIterator::next(void)
+{
+    m_iter = json_object_iter_next(m_obj, m_iter);
+    return m_iter != NULL;
+}
diff --git a/mech_eap/util_json.h b/mech_eap/util_json.h
new file mode 100644 (file)
index 0000000..f987d34
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * JSON object wrapper with not-entirely-toll-free DDF bridging.
+ */
+
+#ifndef _UTIL_JSON_H_
+#define _UTIL_JSON_H_ 1
+
+#ifdef __cplusplus
+#include <string>
+#include <new>
+
+#include <jansson.h>
+#include <shibsp/remoting/ddf.h>
+
+using namespace shibsp;
+
+namespace gss_eap_util {
+    class JSONObject;
+
+    class JSONIterator {
+    public:
+        JSONIterator(const JSONObject &obj);
+        ~JSONIterator(void);
+        const char *key(void) const;
+        JSONObject value(void) const;
+        bool next(void);
+
+    private:
+        json_t *m_obj;
+        void *m_iter;
+    };
+
+    class JSONObject {
+    public:
+        static JSONObject load(const char *input, size_t flags, json_error_t *error);
+        static JSONObject load(FILE *, size_t flags, json_error_t *error);
+
+        static JSONObject object(void);
+        static JSONObject array(void);
+        static JSONObject null(void);
+
+        char *dump(size_t flags = 0) const;
+        void dump(FILE *fp, size_t flags = 0) const;
+
+        json_type type(void) const { return json_typeof(m_obj); }
+        size_t size(void) const;
+
+        JSONObject(void);
+        JSONObject(DDF &value);
+        JSONObject(const char *value);
+        JSONObject(json_int_t value);
+        JSONObject(double value);
+        JSONObject(bool value);
+
+        void set(const char *key, JSONObject &value);
+        void set(const char *key, const char *value);
+        void set(const char *key, json_int_t value);
+        void del(const char *key);
+        void update(JSONObject &value);
+        JSONIterator iterator(void) const { return JSONIterator(*this); }
+        JSONObject get(const char *key) const;
+        JSONObject operator[](const char *key) const;
+
+        JSONObject get(size_t index) const;
+        JSONObject operator[](size_t index) const;
+        void append(JSONObject &value);
+        void insert(size_t index, JSONObject &value);
+        void remove(size_t index);
+        void clear(void);
+        void extend(JSONObject &value);
+
+        const char *string(void) const;
+        json_int_t integer(void) const;
+        double real(void) const;
+        double number(void) const;
+        bool isnull(void) const;
+        DDF ddf(void) const;
+
+        ~JSONObject(void)
+        {
+            if (m_obj != NULL)
+                json_decref(m_obj);
+        }
+
+        JSONObject(const JSONObject &obj)
+        {
+            m_obj = json_incref(obj.m_obj);
+        }
+
+        JSONObject& operator=(const JSONObject &obj)
+        {
+            if (this != &obj)
+                set(obj.m_obj);
+            return *this;
+        }
+
+    private:
+        friend class JSONIterator;
+
+        json_t *get(void) const {
+            return json_incref(m_obj);
+        }
+
+        void set(json_t *obj) {
+            if (m_obj != obj) {
+                json_decref(m_obj);
+                m_obj = json_incref(m_obj);
+            }
+        }
+
+        JSONObject(json_t *obj, bool retain);
+
+        json_t *m_obj;
+    };
+}
+
+#endif /* __cplusplus */
+
+#endif /* _UTIL_JSON_H_ */
index aa19b94..aeef333 100644 (file)
@@ -335,7 +335,7 @@ OM_uint32
 gssEapImportNameInternal(OM_uint32 *minor,
                          const gss_buffer_t nameBuffer,
                          gss_name_t *pName,
-                         unsigned int flags)
+                         OM_uint32 flags)
 {
     OM_uint32 major, tmpMinor;
     krb5_context krbContext;
@@ -524,7 +524,7 @@ OM_uint32
 gssEapExportNameInternal(OM_uint32 *minor,
                          const gss_name_t name,
                          gss_buffer_t exportedName,
-                         unsigned int flags)
+                         OM_uint32 flags)
 {
     OM_uint32 major = GSS_S_FAILURE, tmpMinor;
     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
index 934aa5f..fe43135 100644 (file)
@@ -503,7 +503,7 @@ gssEapRadiusAddAvp(OM_uint32 *minor,
         VALUE_PAIR *vp;
         size_t n = remain;
 
-       /*
+        /*
          * There's an extra byte of padding; RADIUS AVPs can only
          * be 253 octets.
          */
@@ -619,72 +619,52 @@ gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
     return GSS_S_COMPLETE;
 }
 
-/*
- * Encoding is:
- * 4 octet NBO attribute ID | 4 octet attribute length | attribute data
- */
-static size_t
-avpSize(const VALUE_PAIR *vp)
-{
-    size_t size = 4 + 1;
-
-    if (vp != NULL)
-        size += vp->length;
-
-    return size;
-}
-
-static bool
-avpExport(const VALUE_PAIR *vp,
-          unsigned char **pBuffer,
-          size_t *pRemain)
+static JSONObject
+avpToJson(const VALUE_PAIR *vp)
 {
-    unsigned char *p = *pBuffer;
-    size_t remain = *pRemain;
+    JSONObject obj;
 
-    assert(remain >= avpSize(vp));
-
-    store_uint32_be(vp->attribute, p);
+    assert(vp->length <= MAX_STRING_LEN);
 
     switch (vp->type) {
     case PW_TYPE_INTEGER:
     case PW_TYPE_IPADDR:
     case PW_TYPE_DATE:
-        p[4] = 4;
-        store_uint32_be(vp->lvalue, p + 5);
+        obj.set("value", vp->lvalue);
         break;
-    default:
-        assert(vp->length <= MAX_STRING_LEN);
-        p[4] = (uint8_t)vp->length;
-        memcpy(p + 5, vp->vp_octets, vp->length);
+    case PW_TYPE_STRING:
+        obj.set("value", vp->vp_strvalue);
         break;
-    }
+    default: {
+        char *b64;
+
+        if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
+            throw new std::bad_alloc;
 
-    *pBuffer += 5 + p[4];
-    *pRemain -= 5 + p[4];
+        obj.set("value", b64);
+        GSSEAP_FREE(b64);
+        break;
+    }
+    }
 
-    return true;
+    obj.set("type", vp->attribute);
 
+    return obj;
 }
 
 static bool
-avpImport(VALUE_PAIR **pVp,
-          unsigned char **pBuffer,
-          size_t *pRemain)
+jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
 {
-    unsigned char *p = *pBuffer;
-    size_t remain = *pRemain;
     VALUE_PAIR *vp = NULL;
     DICT_ATTR *da;
     uint32_t attrid;
 
-    if (remain < avpSize(NULL))
+    JSONObject type = obj["type"];
+    JSONObject value = obj["value"];
+    if (type.isnull() || value.isnull())
         goto fail;
 
-    attrid = load_uint32_be(p);
-    p += 4;
-    remain -= 4;
-
+    attrid = type.integer();
     da = dict_attrbyvalue(attrid);
     if (da != NULL) {
         vp = pairalloc(da);
@@ -696,40 +676,45 @@ avpImport(VALUE_PAIR **pVp,
         goto fail;
     }
 
-    if (remain < p[0])
-        goto fail;
-
     switch (vp->type) {
     case PW_TYPE_INTEGER:
     case PW_TYPE_IPADDR:
     case PW_TYPE_DATE:
-        if (p[0] != 4)
-            goto fail;
-
         vp->length = 4;
-        vp->lvalue = load_uint32_be(p + 1);
-        p += 5;
-        remain -= 5;
+        vp->lvalue = value.integer();
         break;
-    case PW_TYPE_STRING:
-    default:
-        if (p[0] >= MAX_STRING_LEN)
+    case PW_TYPE_STRING: {
+        const char *str = value.string();
+        size_t len;
+
+        if (str == NULL || (len = strlen(str)) >= MAX_STRING_LEN)
             goto fail;
 
-        vp->length = (uint32_t)p[0];
-        memcpy(vp->vp_octets, p + 1, vp->length);
+        vp->length = len;
+        memcpy(vp->vp_strvalue, str, len + 1);
+        break;
+    }
+    case PW_TYPE_OCTETS:
+    default: {
+        const char *str = value.string();
+        int len;
+
+        /* this optimization requires base64Decode only understand packed encoding */
+        if (str == NULL ||
+            strlen(str) >= BASE64_EXPAND(MAX_STRING_LEN))
+            goto fail;
 
-        if (vp->type == PW_TYPE_STRING)
-            vp->vp_strvalue[vp->length] = '\0';
+        len = base64Decode(str, vp->vp_octets);
+        if (len < 0)
+            goto fail;
 
-        p += 1 + vp->length;
-        remain -= 1 + vp->length;
+        vp->length = len;
+        vp->vp_octets[len] = '\0';
         break;
     }
+    }
 
     *pVp = vp;
-    *pBuffer = p;
-    *pRemain = remain;
 
     return true;
 
@@ -740,26 +725,34 @@ fail:
     return false;
 }
 
+const char *
+gss_eap_radius_attr_provider::name(void) const
+{
+    return "radius";
+}
+
 bool
-gss_eap_radius_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
-                                             const gss_buffer_t buffer)
+gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
+                                                 JSONObject &obj)
 {
-    unsigned char *p = (unsigned char *)buffer->value;
-    size_t remain = buffer->length;
     VALUE_PAIR **pNext = &m_vps;
 
-    if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
+    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
         return false;
 
-    do {
-        VALUE_PAIR *attr;
+    JSONObject attrs = obj["attributes"];
+    size_t nelems = attrs.size();
 
-        if (!avpImport(&attr, &p, &remain))
+    for (size_t i = 0; i < nelems; i++) {
+        JSONObject attr = attrs[i];
+        VALUE_PAIR *vp;
+
+        if (!jsonToAvp(&vp, attr))
             return false;
 
-        *pNext = attr;
-        pNext = &attr->next;
-    } while (remain != 0);
+        *pNext = vp;
+        pNext = &vp->next;
+    }
 
     return true;
 }
@@ -770,31 +763,19 @@ gss_eap_radius_attr_provider::prefix(void) const
     return "urn:ietf:params:gss-eap:radius-avp";
 }
 
-void
-gss_eap_radius_attr_provider::exportToBuffer(gss_buffer_t buffer) const
+JSONObject
+gss_eap_radius_attr_provider::jsonRepresentation(void) const
 {
-    VALUE_PAIR *vp;
-    unsigned char *p;
-    size_t remain = 0;
+    JSONObject obj, attrs = JSONObject::array();
 
-    for (vp = m_vps; vp != NULL; vp = vp->next) {
-        remain += avpSize(vp);
+    for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
+        JSONObject attr = avpToJson(vp);
+        attrs.append(attr);
     }
 
-    buffer->value = GSSEAP_MALLOC(remain);
-    if (buffer->value == NULL) {
-        throw new std::bad_alloc;
-        return;
-    }
-    buffer->length = remain;
-
-    p = (unsigned char *)buffer->value;
-
-    for (vp = m_vps; vp != NULL; vp = vp->next) {
-        avpExport(vp, &p, &remain);
-    }
+    obj.set("attributes", attrs);
 
-    assert(remain == 0);
+    return obj;
 }
 
 time_t
index bc6165b..a7878df 100644 (file)
@@ -67,10 +67,10 @@ public:
                                gss_any_t input) const;
 
     const char *prefix(void) const;
-
-    void exportToBuffer(gss_buffer_t buffer) const;
-    bool initFromBuffer(const gss_eap_attr_ctx *ctx,
-                        const gss_buffer_t buffer);
+    const char *name(void) const;
+    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
+                           JSONObject &obj);
+    JSONObject jsonRepresentation(void) const;
 
     bool getAttribute(uint32_t attribute,
                       int *authenticated,
index 24d125d..8722b84 100644 (file)
@@ -310,20 +310,6 @@ gss_eap_saml_assertion_provider::prefix(void) const
     return "urn:ietf:params:gss-eap:saml-aaa-assertion";
 }
 
-void
-gss_eap_saml_assertion_provider::exportToBuffer(gss_buffer_t buffer) const
-{
-    buffer->length = 0;
-    buffer->value = NULL;
-}
-
-bool
-gss_eap_saml_assertion_provider::initFromBuffer(const gss_eap_attr_ctx *ctx GSSEAP_UNUSED,
-                                                const gss_buffer_t buffer GSSEAP_UNUSED)
-{
-    return false;
-}
-
 bool
 gss_eap_saml_assertion_provider::init(void)
 {
@@ -694,20 +680,6 @@ gss_eap_saml_attr_provider::prefix(void) const
     return "urn:ietf:params:gss-eap:saml-attr";
 }
 
-void
-gss_eap_saml_attr_provider::exportToBuffer(gss_buffer_t buffer) const
-{
-    buffer->length = 0;
-    buffer->value = NULL;
-}
-
-bool
-gss_eap_saml_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx GSSEAP_UNUSED,
-                                           const gss_buffer_t buffer GSSEAP_UNUSED)
-{
-    return false;
-}
-
 bool
 gss_eap_saml_attr_provider::init(void)
 {
index 17edb2b..eeb17e3 100644 (file)
@@ -75,10 +75,14 @@ public:
                                gss_any_t input) const;
 
     const char *prefix(void) const;
-    void exportToBuffer(gss_buffer_t buffer) const;
-
-    bool initFromBuffer(const gss_eap_attr_ctx *ctx,
-                        const gss_buffer_t buffer);
+    const char *name(void) const { return NULL; }
+    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
+                           JSONObject &object GSSEAP_UNUSED) {
+        return false;
+    }
+    JSONObject jsonRepresentation(void) const {
+        return JSONObject::null();
+    }
 
     opensaml::saml2::Assertion *initAssertion(void);
 
@@ -132,10 +136,16 @@ public:
                                gss_any_t input) const;
 
     const char *prefix(void) const;
-
-    void exportToBuffer(gss_buffer_t buffer) const;
-    bool initFromBuffer(const gss_eap_attr_ctx *ctx,
-                        const gss_buffer_t buffer);
+    const char *name(void) const {
+        return NULL;
+    }
+    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
+                            JSONObject &object GSSEAP_UNUSED) {
+        return false;
+    }
+    JSONObject jsonRepresentation(void) const {
+        return JSONObject::null();
+    }
 
     bool getAttribute(const gss_buffer_t attr,
                       int *authenticated,
index 4da9a31..2f6e54d 100644 (file)
@@ -70,6 +70,7 @@ using namespace std;
 
 gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
 {
+    m_initialized = false;
     m_authenticated = false;
 }
 
@@ -99,53 +100,7 @@ gss_eap_shib_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *mana
         m_authenticated = shib->authenticated();
     }
 
-    return true;
-}
-
-bool
-addRadiusAttribute(const gss_eap_attr_ctx *manager,
-                   const gss_eap_attr_provider *provider,
-                   const gss_buffer_t attribute,
-                   void *data)
-{
-    const gss_eap_radius_attr_provider *radius;
-    const gss_eap_shib_attr_provider *shib;
-    int authenticated, complete, more = -1;
-    vector <string> attributeIds(1);
-    SimpleAttribute *a;
-
-    radius = static_cast<const gss_eap_radius_attr_provider *>(provider);
-    shib = static_cast<const gss_eap_shib_attr_provider *>(data);
-
-    assert(radius != NULL && shib != NULL);
-
-    string attributeName =
-        manager->composeAttributeName(ATTR_TYPE_RADIUS, attribute);
-
-    attributeIds.push_back(attributeName);
-    a = new SimpleAttribute(attributeIds);
-    if (a == NULL)
-        return false;
-
-    while (more != 0) {
-        gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
-        OM_uint32 minor;
-
-        if (!radius->getAttribute(attribute,
-                                  &authenticated,
-                                  &complete,
-                                  &value,
-                                  NULL,
-                                  &more))
-            return false;
-
-        string attributeValue((char *)value.value, value.length);
-        a->getValues().push_back(attributeValue);
-
-        gss_release_buffer(&minor, &value);
-    }
-
-    shib->getAttributes().push_back(a);
+    m_initialized = true;
 
     return true;
 }
@@ -156,18 +111,17 @@ gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
                                                const gss_ctx_id_t gssCtx)
 {
     const gss_eap_saml_assertion_provider *saml;
-    const gss_eap_radius_attr_provider *radius;
+    gss_buffer_desc exportedCtx = GSS_C_EMPTY_BUFFER;
+    OM_uint32 major, minor;
+
 #if 0
     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-    OM_uint32 minor;
 #endif
     if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
         return false;
 
     saml = static_cast<const gss_eap_saml_assertion_provider *>
         (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
-    radius = static_cast<const gss_eap_radius_attr_provider *>
-        (m_manager->getProvider(ATTR_TYPE_RADIUS));
 
     auto_ptr<ShibbolethResolver> resolver(ShibbolethResolver::create());
 
@@ -185,17 +139,15 @@ gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
     }
 #endif
 
-    m_authenticated = false;
-
-    if (radius != NULL) {
-        radius->getAttributeTypes(addRadiusAttribute, (void *)this);
-        m_authenticated = radius->authenticated();
+    major = gssEapExportSecContext(&minor, gssCtx, &exportedCtx);
+    if (major == GSS_S_COMPLETE) {
+        resolver->addToken(&exportedCtx);
+        gss_release_buffer(&minor, &exportedCtx);
     }
 
     if (saml != NULL && saml->getAssertion() != NULL) {
         resolver->addToken(saml->getAssertion());
-        if (m_authenticated)
-            m_authenticated = saml->authenticated();
+        m_authenticated = saml->authenticated();
     }
 
     try {
@@ -208,6 +160,8 @@ gss_eap_shib_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
 #endif
     }
 
+    m_initialized = true;
+
     return true;
 }
 
@@ -216,6 +170,8 @@ gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const
 {
     int i = 0;
 
+    assert(m_initialized);
+
     for (vector<Attribute *>::const_iterator a = m_attributes.begin();
          a != m_attributes.end();
          ++a)
@@ -242,6 +198,8 @@ gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
     vector <string> ids(1, attrStr);
     SimpleAttribute *a = new SimpleAttribute(ids);
 
+    assert(m_initialized);
+
     if (value->length != 0) {
         string valueStr((char *)value->value, value->length);
 
@@ -259,6 +217,8 @@ gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr)
 {
     int i;
 
+    assert(m_initialized);
+
     i = getAttributeIndex(attr);
     if (i >= 0)
         m_attributes.erase(m_attributes.begin() + i);
@@ -272,6 +232,8 @@ bool
 gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
                                               void *data) const
 {
+    assert(m_initialized);
+
     for (vector<Attribute*>::const_iterator a = m_attributes.begin();
         a != m_attributes.end();
         ++a)
@@ -293,6 +255,8 @@ gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
 {
     const Attribute *ret = NULL;
 
+    assert(m_initialized);
+
     for (vector<Attribute *>::const_iterator a = m_attributes.begin();
          a != m_attributes.end();
          ++a)
@@ -325,6 +289,8 @@ gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
     gss_buffer_desc buf;
     int nvalues, i = *more;
 
+    assert(m_initialized);
+
     *more = 0;
 
     shibAttr = getAttribute(attr);
@@ -366,6 +332,8 @@ gss_eap_shib_attr_provider::mapToAny(int authenticated,
 {
     gss_any_t output;
 
+    assert(m_initialized);
+
     if (authenticated && !m_authenticated)
         return (gss_any_t)NULL;
 
@@ -380,6 +348,8 @@ void
 gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
                                                   gss_any_t input) const
 {
+    assert(m_initialized);
+
     vector <Attribute *> *v = ((vector <Attribute *> *)input);
     delete v;
 }
@@ -390,67 +360,57 @@ gss_eap_shib_attr_provider::prefix(void) const
     return NULL;
 }
 
-void
-gss_eap_shib_attr_provider::exportToBuffer(gss_buffer_t buffer) const
+const char *
+gss_eap_shib_attr_provider::name(void) const
+{
+    return "local";
+}
+
+JSONObject
+gss_eap_shib_attr_provider::jsonRepresentation(void) const
 {
-    DDF obj(NULL);
-    DDF attrs(NULL);
+    JSONObject obj;
 
-    buffer->length = 0;
-    buffer->value = NULL;
+    if (m_initialized == false)
+        return obj; /* don't export incomplete context */
 
-    obj.addmember("version").integer(1);
-    obj.addmember("authenticated").integer(m_authenticated);
+    JSONObject attrs = JSONObject::array();
 
-    attrs = obj.addmember("attributes").list();
     for (vector<Attribute*>::const_iterator a = m_attributes.begin();
          a != m_attributes.end(); ++a) {
         DDF attr = (*a)->marshall();
-        attrs.add(attr);
+        JSONObject jobj(attr);
+        attrs.append(jobj);
     }
 
-    ostringstream sink;
-    sink << obj;
-    string str = sink.str();
+    obj.set("attributes", attrs);
 
-    duplicateBuffer(str, buffer);
+    obj.set("authenticated", m_authenticated);
 
-    attrs.destroy();
+    return obj;
 }
 
 bool
-gss_eap_shib_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
-                                           const gss_buffer_t buffer)
+gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
+                                               JSONObject &obj)
 {
-    if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
+    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
         return false;
 
-    if (buffer->length == 0)
-        return true;
-
     assert(m_authenticated == false);
     assert(m_attributes.size() == 0);
 
-    DDF obj(NULL);
-    string str((const char *)buffer->value, buffer->length);
-    istringstream source(str);
-
-    source >> obj;
-
-    if (obj["version"].integer() != 1)
-        return false;
-
-    m_authenticated = (obj["authenticated"].integer() != 0);
+    JSONObject attrs = obj["attributes"];
+    size_t nelems = attrs.size();
 
-    DDF attrs = obj["attributes"];
-    DDF attr = attrs.first();
-    while (!attr.isnull()) {
+    for (size_t i = 0; i < nelems; i++) {
+        DDF attr = attrs.get(i).ddf();
         Attribute *attribute = Attribute::unmarshall(attr);
         m_attributes.push_back(attribute);
-        attr = attrs.next();
     }
 
-    attrs.destroy();
+    m_authenticated = obj["authenticated"].integer();
+    m_initialized = true;
 
     return true;
 }
index a6fe0ec..8080e0c 100644 (file)
@@ -77,10 +77,10 @@ public:
                                gss_any_t input) const;
 
     const char *prefix(void) const;
-
-    void exportToBuffer(gss_buffer_t buffer) const;
-    bool initFromBuffer(const gss_eap_attr_ctx *ctx,
-                        const gss_buffer_t buffer);
+    const char *name(void) const;
+    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
+                            JSONObject &obj);
+    JSONObject jsonRepresentation(void) const;
 
     static bool init(void);
     static void finalize(void);
@@ -104,16 +104,11 @@ private:
 
     bool authenticated(void) const { return m_authenticated; }
 
-    friend bool
-    addRadiusAttribute(const gss_eap_attr_provider *source,
-                       const gss_buffer_t attribute,
-                       void *data);
-
+    bool m_initialized;
+    bool m_authenticated;
     std::vector<shibsp::Attribute *> m_attributes;
-    int m_authenticated;
 };
 
-
 extern "C" {
 #endif
 
index 420cc8a..28fb7b6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 420cc8ae67db726cb6d22ae2a8dbcdeabb547ad6
+Subproject commit 28fb7b606f379cda416cbc4239d2690b6a1c161f
index 4c22d78..ec12184 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4c22d78d500385b10bd0fbb4a291b47a840ba4ad
+Subproject commit ec12184bd72287b88af4301bde2df916fc475615
index a1e9b0e..39ee29e 100644 (file)
@@ -7,4 +7,5 @@ shibboleth/sp
 shibboleth/resolver
 libradsec/lib
 libeap
+jansson
 mech_eap