Merge branch 'master' into tlv-mic tlv-mic
authorLuke Howard <lukeh@padl.com>
Thu, 19 May 2011 14:53:12 +0000 (16:53 +0200)
committerLuke Howard <lukeh@padl.com>
Thu, 19 May 2011 14:53:12 +0000 (16:53 +0200)
13 files changed:
moonshot/acinclude.m4
moonshot/mech_eap/README.samba4 [new file with mode: 0644]
moonshot/mech_eap/TODO
moonshot/mech_eap/dictionary.ukerna
moonshot/mech_eap/gssapiP_eap.h
moonshot/mech_eap/inquire_attrs_for_mech.c
moonshot/mech_eap/util_base64.c
moonshot/mech_eap/util_context.c
moonshot/mech_eap/util_radius.cpp
moonshot/mech_eap/util_radius.h
moonshot/mech_eap/util_shib.cpp
openssh
shibboleth/sp

index eab00b4..80c71bb 100644 (file)
@@ -34,9 +34,9 @@ else
        AC_SUBST(KRB5_CFLAGS)
        AC_SUBST(KRB5_LIBS)
        AC_SUBST(COMPILE_ET)
-       AC_CHECK_LIB(gssapi_krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS")
-       AC_CHECK_LIB(gssapi_krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS")
-       AC_CHECK_LIB(gssapi_krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS")
+       AC_CHECK_LIB(krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS")
+       AC_CHECK_LIB(krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS")
+       AC_CHECK_LIB(krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS")
        AC_CHECK_LIB(krb5, heimdal_version, [AC_DEFINE_UNQUOTED([HAVE_HEIMDAL_VERSION], 1, [Define if building against Heimdal Kerberos implementation]), heimdal=yes], [heimdal=no], "$KRB5_LIBS")
        AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno")
 fi
diff --git a/moonshot/mech_eap/README.samba4 b/moonshot/mech_eap/README.samba4
new file mode 100644 (file)
index 0000000..d0a94d1
--- /dev/null
@@ -0,0 +1,52 @@
+Notes on using Moonshot with Samba4. Replace paths as appropriate.
+
+Samba
+-----
+
+* Download Samba4 and apply patches for mechanism agnosticism which are
+  available at http://www.padl.com/~lukeh/samba/
+* Join Samba as a member server or domain controller (only tested former)
+* Extract local service principal key to keytab (currently there do not
+  appear to be tools to do this, but you can get the cleartext password
+  from /usr/local/samba/private/secrets.ldb)
+
+Shibboleth
+----------
+
+* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
+  /usr/local/etc/shibboleth/attribute-map.xml:
+
+  <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
+                   id="urn:mspac:" binary="true"/>
+
+FreeRADIUS
+----------
+
+Install the rlm_mspac module and configure per below.
+
+* Install dictionary.ukerna so MS-Windows-Auth-Data is defined
+* Create /usr/local/etc/raddb/modules/mspac with the following:
+
+    mspac {
+        keytab = /etc/krb5.keytab
+        spn = host/host.fqdn@KERBEROS.REALM
+    }       
+
+* Add mspac to instantiate stanza in radiusd.conf
+* Add mspac to post-auth stanza in sites-enabled/inner-tunnel
+
+You will need to have a TGT for the host service principal before starting
+radiusd. It's easiest to do this with kinit -k.
+
+Testing
+-------
+
+The Samba server doesn't require any specific command line arguments, although
+on OS X it was necessary to start it with -M single to function under gdb.
+
+For the client, the GSS EAP mechanism can be specified on the command line:
+
+smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
+
+There is no Moonshot SSPI implementation as yet, so it is not possible to test
+with a Windows client.
index 17780ec..986cbf6 100644 (file)
@@ -3,5 +3,9 @@
 - test Heimdal port
 
 - fix ABNF: no slash in the case where there is no host
-- specify anonymous behaviour: use empty name
 - always intern OIDs so they never need to be freed
+
+- handle many-to-many Shibboleth attribute mappings; need to encode
+  both attribute and value index into more
+- proper acquire_cred_ext implementation
+- MIC on flags token
index d62d829..1694566 100644 (file)
@@ -14,5 +14,6 @@ ATTRIBUTE     GSS-Acceptor-Host-Name          129     string
 ATTRIBUTE      GSS-Acceptor-Service-Specific   130     string
 ATTRIBUTE      GSS-Acceptor-Realm-Name         131     string
 ATTRIBUTE      SAML-AAA-Assertion              132     string
+ATTRIBUTE      MS-Windows-Auth-Data            133     octets
 
 END-VENDOR UKERNA
index 19e7fb2..401495d 100644 (file)
@@ -58,6 +58,10 @@ typedef struct gss_any *gss_any_t;
 #endif
 #include "gssapi_eap.h"
 
+#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
+typedef const gss_OID_desc *gss_const_OID;
+#endif
+
 /* Kerberos headers */
 #include <krb5.h>
 
index 8c1bf12..b85953b 100644 (file)
 #define MA_SUPPORTED(ma)    MA_ADD((ma), mech_attrs)
 #define MA_KNOWN(ma)        MA_ADD((ma), known_mech_attrs)
 
-#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
-typedef const gss_OID_desc *gss_const_OID;
-#endif
-
 OM_uint32
 gss_inquire_attrs_for_mech(OM_uint32 *minor,
                            gss_const_OID mech_oid,
index 5d5241d..aaa1ea8 100644 (file)
@@ -122,7 +122,9 @@ base64Decode(const char *str, void *data)
     unsigned char *q;
 
     q = data;
-    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+    p = str;
+
+    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
        unsigned int val = token_decode(p);
        unsigned int marker = (val >> 24) & 0xff;
        if (val == DECODE_ERROR)
@@ -132,6 +134,9 @@ base64Decode(const char *str, void *data)
            *q++ = (val >> 8) & 0xff;
        if (marker < 1)
            *q++ = val & 0xff;
+       p += 4;
+       if (*p == '\n')
+           p++;
     }
     return q - (unsigned char *) data;
 }
@@ -139,15 +144,18 @@ base64Decode(const char *str, void *data)
 int
 base64Valid(const char *str)
 {
-    const char *p;
+    const char *p = str;
     int valid = 1;
 
-    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
+    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
        unsigned int val = token_decode(p);
        if (val == DECODE_ERROR) {
             valid = 0;
            break;
         }
+       p += 4;
+       if (*p == '\n')
+           p++;
     }
     return valid;
 }
index 148afed..d6ce55b 100644 (file)
@@ -70,7 +70,8 @@ gssEapAllocContext(OM_uint32 *minor,
                     GSS_C_INTEG_FLAG    |   /* integrity */
                     GSS_C_CONF_FLAG     |   /* confidentiality */
                     GSS_C_SEQUENCE_FLAG |   /* sequencing */
-                    GSS_C_REPLAY_FLAG;      /* replay detection */
+                    GSS_C_REPLAY_FLAG|      /* replay detection */
+      GSS_C_MUTUAL_FLAG; /*xxx big hack */
 
     *pCtx = ctx;
 
index 5462acc..0ab02b9 100644 (file)
@@ -155,7 +155,17 @@ isInternalAttributeP(uint16_t attrid, uint16_t vendor)
 
     switch (vendor) {
     case VENDORPEC_UKERNA:
-        bInternalAttribute = true;
+        switch (attrid) {
+        case PW_GSS_ACCEPTOR_SERVICE_NAME:
+        case PW_GSS_ACCEPTOR_HOST_NAME:
+        case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
+        case PW_GSS_ACCEPTOR_REALM_NAME:
+        case PW_SAML_AAA_ASSERTION:
+            bInternalAttribute = true;
+            break;
+        default:
+            break;
+        }
         break;
     default:
         break;
@@ -170,6 +180,20 @@ isInternalAttributeP(uint32_t attribute)
     return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
 }
 
+static bool
+isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
+{
+    /* A bit of a hack for the PAC for now. Should be configurable. */
+    return (vendor == VENDORPEC_UKERNA) &&
+        !isInternalAttributeP(attrid, vendor);
+}
+
+static bool
+isFragmentedAttributeP(uint32_t attribute)
+{
+    return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
+}
+
 /*
  * Copy AVP list, same as paircopy except it filters out attributes
  * containing keys.
@@ -350,6 +374,15 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
     if (i == -1)
         i = 0;
 
+    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
+        return false;
+    } else if (isFragmentedAttributeP(attrid)) {
+        return getFragmentedAttribute(attrid,
+                                      authenticated,
+                                      complete,
+                                      value);
+    }
+
     for (vp = pairfind(m_vps, attrid);
          vp != NULL;
          vp = pairfind(vp->next, attrid)) {
@@ -372,7 +405,8 @@ gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
         duplicateBuffer(valueBuf, value);
     }
 
-    if (display_value != GSS_C_NO_BUFFER) {
+    if (display_value != GSS_C_NO_BUFFER &&
+        vp->type != PW_TYPE_OCTETS) {
         char displayString[MAX_STRING_LEN];
         gss_buffer_desc displayBuf;
 
@@ -411,6 +445,16 @@ gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
 }
 
 bool
+gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
+                                                     int *authenticated,
+                                                     int *complete,
+                                                     gss_buffer_t value) const
+{
+    return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
+                                  authenticated, complete, value);
+}
+
+bool
 gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
                                            uint16_t vendor,
                                            int *authenticated,
@@ -557,8 +601,10 @@ gssEapRadiusGetAvp(OM_uint32 *minor,
     unsigned char *p;
     uint32_t attr = VENDORATTR(vendor, attribute);
 
-    buffer->length = 0;
-    buffer->value = NULL;
+    if (buffer != GSS_C_NO_BUFFER) {
+        buffer->length = 0;
+        buffer->value = NULL;
+    }
 
     vp = pairfind(vps, attr);
     if (vp == NULL) {
@@ -566,23 +612,25 @@ gssEapRadiusGetAvp(OM_uint32 *minor,
         return GSS_S_UNAVAILABLE;
     }
 
-    do {
-        buffer->length += vp->length;
-    } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
+    if (buffer != GSS_C_NO_BUFFER) {
+        do {
+            buffer->length += vp->length;
+        } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
 
-    buffer->value = GSSEAP_MALLOC(buffer->length);
-    if (buffer->value == NULL) {
-        *minor = ENOMEM;
-        return GSS_S_FAILURE;
-    }
+        buffer->value = GSSEAP_MALLOC(buffer->length);
+        if (buffer->value == NULL) {
+            *minor = ENOMEM;
+            return GSS_S_FAILURE;
+        }
 
-    p = (unsigned char *)buffer->value;
+        p = (unsigned char *)buffer->value;
 
-    for (vp = pairfind(vps, attr);
-         concat && vp != NULL;
-         vp = pairfind(vp->next, attr)) {
-        memcpy(p, vp->vp_octets, vp->length);
-        p += vp->length;
+        for (vp = pairfind(vps, attr);
+             concat && vp != NULL;
+             vp = pairfind(vp->next, attr)) {
+            memcpy(p, vp->vp_octets, vp->length);
+            p += vp->length;
+        }
     }
 
     *minor = 0;
index ebd348b..04e6fc5 100644 (file)
@@ -95,6 +95,10 @@ public:
                                 int *authenticated,
                                 int *complete,
                                 gss_buffer_t value) const;
+    bool getFragmentedAttribute(uint32_t attrid,
+                                int *authenticated,
+                                int *complete,
+                                gss_buffer_t value) const;
 
     bool authenticated(void) const { return m_authenticated; }
 
@@ -164,6 +168,7 @@ gssEapRadiusMapError(OM_uint32 *minor,
 #define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC    130
 #define PW_GSS_ACCEPTOR_REALM_NAME          131
 #define PW_SAML_AAA_ASSERTION               132
+#define PW_MS_WINDOWS_AUTH_DATA             133
 
 #define IS_RADIUS_ERROR(code)               ((code) >= ERROR_TABLE_BASE_rse && \
                                              (code) <= ERROR_TABLE_BASE_rse + RSE_TIMEOUT_IO)
index 3d2aa2c..15a8b44 100644 (file)
@@ -304,7 +304,24 @@ gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
     buf.value = (void *)shibAttr->getSerializedValues()[*more].c_str();
     buf.length = strlen((char *)buf.value);
 
-    if (buf.length != 0) {
+    /* XXX hack until we have proper binary attribute support */
+    if (attr->length == sizeof("urn:mspac:") - 1 &&
+        memcmp(attr->value, "urn:mspac:", attr->length) == 0) {
+        ssize_t octetLen;
+
+        value->value = GSSEAP_MALLOC(buf.length);
+        if (value->value == NULL)
+            throw std::bad_alloc();
+
+        octetLen = base64Decode((char *)buf.value, value->value);
+        if (octetLen < 0) {
+            GSSEAP_FREE(value->value);
+            value->value = NULL;
+            return false;
+        }
+
+        value->length = octetLen;
+    } else if (buf.length != 0) {
         if (value != NULL)
             duplicateBuffer(buf, value);
 
@@ -315,7 +332,7 @@ gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
     if (authenticated != NULL)
         *authenticated = m_authenticated;
     if (complete != NULL)
-        *complete = false;
+        *complete = true;
 
     if (nvalues > ++i)
         *more = i;
@@ -417,13 +434,18 @@ gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
 bool
 gss_eap_shib_attr_provider::init(void)
 {
-    if (SPConfig::getConfig().getFeatures() == 0 &&
-        ShibbolethResolver::init() == false)
-        return false;
+    bool ret = false;
+
+    try {
+        if (SPConfig::getConfig().getFeatures() == 0)
+            ret = ShibbolethResolver::init();
+    } catch (exception &e) {
+    }
 
-    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
+    if (ret)
+        gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
 
-    return true;
+    return ret;
 }
 
 void
diff --git a/openssh b/openssh
index ac0ba1f..1a72587 160000 (submodule)
--- a/openssh
+++ b/openssh
@@ -1 +1 @@
-Subproject commit ac0ba1f390586dd0300f0a036ce30952b1dd5def
+Subproject commit 1a7258779c5454494ac8e257cca2fc99a7e36dfe
index 28fcbaa..bdbac80 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 28fcbaa4e8c5090550a3e0ceaf0ea6a1355b890b
+Subproject commit bdbac801c636a747fdb3c0a39a564f3f77452cf3