EAP Channel binding support
[mech_eap.git] / mech_eap / util.h
index 2242735..9a606ab 100644 (file)
 #ifndef _UTIL_H_
 #define _UTIL_H_ 1
 
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 #include <string.h>
 #include <errno.h>
 
 #include <krb5.h>
 
+#ifdef WIN32
+# ifndef __cplusplus
+# define inline __inline
+# endif
+#define snprintf _snprintf
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -75,7 +87,7 @@ extern "C" {
 #define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
 #endif
 
-#if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
 #define GSSEAP_UNUSED __attribute__ ((__unused__))
 #else
 #define GSSEAP_UNUSED
@@ -200,7 +212,10 @@ enum gss_eap_token_type {
 
 #define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
 
-#define GSSEAP_WIRE_FLAGS_MASK          GSS_C_MUTUAL_FLAG
+#define GSSEAP_WIRE_FLAGS_MASK          ( GSS_C_MUTUAL_FLAG             | \
+                                          GSS_C_DCE_STYLE               | \
+                                          GSS_C_IDENTIFY_FLAG           | \
+                                          GSS_C_EXTENDED_ERROR_FLAG       )
 
 OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
 OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
@@ -331,6 +346,21 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
                        krb5_keyblock *pKey);
 
 /* util_krb.c */
+
+#ifndef KRB_MALLOC
+/*
+ * If your Kerberos library uses a different allocator to your
+ * GSS mechanism glue, then you might wish to define these in
+ * config.h or elsewhere. This should eventually go away when
+ * we no longer need to allocate memory that is freed by the
+ * Kerberos library.
+ */
+#define KRB_CALLOC                      calloc
+#define KRB_MALLOC                      malloc
+#define KRB_FREE                        free
+#define KRB_REALLOC                     realloc
+#endif /* KRB_MALLOC */
+
 #ifdef HAVE_HEIMDAL_VERSION
 
 #define KRB_TIME_FOREVER        ((time_t)~0L)
@@ -349,6 +379,18 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
 
 #define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto)
 
+#define KRB_DATA_INIT(d)        krb5_data_zero((d))
+
+#define KRB_CHECKSUM_TYPE(c)    ((c)->cksumtype)
+#define KRB_CHECKSUM_LENGTH(c)  ((c)->checksum.length)
+#define KRB_CHECKSUM_DATA(c)    ((c)->checksum.data)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d)      do { \
+        (cksum)->cksumtype = (type);                \
+        (cksum)->checksum.length = (d)->length;     \
+        (cksum)->checksum.data = (d)->value;        \
+    } while (0)
+
 #else
 
 #define KRB_TIME_FOREVER        KRB5_INT32_MAX
@@ -361,12 +403,30 @@ gssEapDeriveRfc3961Key(OM_uint32 *minor,
 #define KRB_PRINC_TYPE(princ)   (krb5_princ_type(NULL, (princ)))
 #define KRB_PRINC_NAME(princ)   (krb5_princ_name(NULL, (princ)))
 #define KRB_PRINC_REALM(princ)  (krb5_princ_realm(NULL, (princ)))
+#define KRB_PRINC_COMPONENT(princ, component) \
+        (krb5_princ_component(NULL, (princ), (component)))
 
 #define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->key)
 #define KRB_KT_ENT_FREE(c, e)   krb5_free_keytab_entry_contents((c), (e))
 
 #define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key)
 
+#define KRB_DATA_INIT(d)        do {        \
+        (d)->magic = KV5M_DATA;             \
+        (d)->length = 0;                    \
+        (d)->data = NULL;                   \
+    } while (0)
+
+#define KRB_CHECKSUM_TYPE(c)    ((c)->checksum_type)
+#define KRB_CHECKSUM_LENGTH(c)  ((c)->length)
+#define KRB_CHECKSUM_DATA(c)    ((c)->contents)
+
+#define KRB_CHECKSUM_INIT(cksum, type, d)      do { \
+        (cksum)->checksum_type = (type);            \
+        (cksum)->length = (d)->length;              \
+        (cksum)->contents = (d)->value;             \
+    } while (0)
+
 #endif /* HAVE_HEIMDAL_VERSION */
 
 #define KRB_KEY_INIT(key)       do {        \
@@ -555,10 +615,13 @@ gssEapDisplayName(OM_uint32 *minor,
                   gss_buffer_t output_name_buffer,
                   gss_OID *output_name_type);
 
+#define COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS   0x1
+
 OM_uint32
 gssEapCompareName(OM_uint32 *minor,
                   gss_name_t name1,
                   gss_name_t name2,
+                  OM_uint32 flags,
                   int *name_equal);
 
 /* util_oid.c */
@@ -738,23 +801,71 @@ verifyTokenHeader(OM_uint32 *minor,
                   enum gss_eap_token_type *ret_tok_type);
 
 /* Helper macros */
-
+#ifndef GSSEAP_MALLOC
+#if _WIN32
+#include <gssapi/gssapi_alloc.h>
+#define GSSEAP_MALLOC                   gssalloc_malloc
+#define GSSEAP_CALLOC                   gssalloc_calloc
+#define GSSEAP_FREE                     gssalloc_free
+#define GSSEAP_REALLOC                  gssalloc_realloc
+#else
 #define GSSEAP_CALLOC                   calloc
 #define GSSEAP_MALLOC                   malloc
 #define GSSEAP_FREE                     free
 #define GSSEAP_REALLOC                  realloc
+#endif /* _WIN32 */
+#endif /* !GSSEAP_MALLOC */
+
+#ifndef GSSAPI_CALLCONV
+#define GSSAPI_CALLCONV                 KRB5_CALLCONV
+#endif
+
+#ifndef GSSEAP_ASSERT
+#include <assert.h>
+#define GSSEAP_ASSERT(x)                assert((x))
+#endif /* !GSSEAP_ASSERT */
+
+#ifdef WIN32
+#define GSSEAP_CONSTRUCTOR
+#define GSSEAP_DESTRUCTOR
+#else
+#define GSSEAP_CONSTRUCTOR              __attribute__((constructor))
+#define GSSEAP_DESTRUCTOR               __attribute__((destructor))
+#endif
 
 #define GSSEAP_NOT_IMPLEMENTED          do {            \
-        assert(0 && "not implemented");                 \
+        GSSEAP_ASSERT(0 && "not implemented");          \
         *minor = ENOSYS;                                \
         return GSS_S_FAILURE;                           \
     } while (0)
 
+#ifdef WIN32
+
+#include <winbase.h>
+
+#define GSSEAP_GET_LAST_ERROR()         (GetLastError()) /* XXX FIXME */
+
+#define GSSEAP_MUTEX                    CRITICAL_SECTION
+#define GSSEAP_MUTEX_INIT(m)            (InitializeCriticalSection((m)), 0)
+#define GSSEAP_MUTEX_DESTROY(m)         DeleteCriticalSection((m))
+#define GSSEAP_MUTEX_LOCK(m)            EnterCriticalSection((m))
+#define GSSEAP_MUTEX_UNLOCK(m)          LeaveCriticalSection((m))
+#define GSSEAP_ONCE_LEAVE              do { return TRUE; } while (0)
+
+/* Thread-local is handled separately */
+
+#define GSSEAP_THREAD_ONCE              INIT_ONCE
+#define GSSEAP_ONCE_CALLBACK(cb)        BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+#define GSSEAP_ONCE(o, i)               InitOnceExecuteOnce((o), (i), NULL, NULL)
+#define GSSEAP_ONCE_INITIALIZER         INIT_ONCE_STATIC_INIT
+
+#else
+
 #include <pthread.h>
 
-#define GSSEAP_MUTEX                    pthread_mutex_t
-#define GSSEAP_MUTEX_INITIALIZER        PTHREAD_MUTEX_INITIALIZER
+#define GSSEAP_GET_LAST_ERROR()         (errno)
 
+#define GSSEAP_MUTEX                    pthread_mutex_t
 #define GSSEAP_MUTEX_INIT(m)            pthread_mutex_init((m), NULL)
 #define GSSEAP_MUTEX_DESTROY(m)         pthread_mutex_destroy((m))
 #define GSSEAP_MUTEX_LOCK(m)            pthread_mutex_lock((m))
@@ -766,8 +877,12 @@ verifyTokenHeader(OM_uint32 *minor,
 #define GSSEAP_SETSPECIFIC(k, d)        pthread_setspecific((k), (d))
 
 #define GSSEAP_THREAD_ONCE              pthread_once_t
+#define GSSEAP_ONCE_CALLBACK(cb)        void cb(void)
 #define GSSEAP_ONCE(o, i)               pthread_once((o), (i))
 #define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
+#define GSSEAP_ONCE_LEAVE              do { } while (0)
+
+#endif /* WIN32 */
 
 /* Helper functions */
 static inline void
@@ -891,13 +1006,54 @@ static inline void
 krbPrincComponentToGssBuffer(krb5_principal krbPrinc,
                              int index, gss_buffer_t buffer)
 {
+    if (KRB_PRINC_LENGTH(krbPrinc) < index) {
+        buffer->value = NULL;
+        buffer->length = 0;
+    } else {
 #ifdef HAVE_HEIMDAL_VERSION
-    buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
-    buffer->length = strlen((char *)buffer->value);
+        buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
+        buffer->length = strlen((char *)buffer->value);
 #else
-    buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
-    buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
+        buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
+        buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
 #endif /* HAVE_HEIMDAL_VERSION */
+    }
+}
+
+static inline krb5_error_code
+krbPrincUnparseServiceSpecifics(krb5_context krbContext, krb5_principal krbPrinc,
+                                gss_buffer_t nameBuf)
+{
+    krb5_error_code result = 0;
+    if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
+        /* Acceptor-Service-Specific */
+        krb5_principal_data ssiPrinc = *krbPrinc;
+        char *ssi;
+
+        KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
+        KRB_PRINC_NAME(&ssiPrinc) += 2;
+
+        result = krb5_unparse_name_flags(krbContext, &ssiPrinc,
+                                         KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
+        if (result != 0)
+            return result;
+
+        nameBuf->value = ssi;
+        nameBuf->length = strlen(ssi);
+    } else {
+        nameBuf->value = NULL;
+        nameBuf->length = 0;
+    }
+
+    return result;
+}
+
+static inline void
+krbFreeUnparsedName(krb5_context krbContext, gss_buffer_t nameBuf)
+{
+    krb5_free_unparsed_name(krbContext, (char *)(nameBuf->value));
+    nameBuf->value = NULL;
+    nameBuf->length = 0;
 }
 
 static inline void
@@ -918,13 +1074,32 @@ gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
     data->length = buffer->length;
 }
 
+/* util_tld.c */
+struct gss_eap_status_info;
+
+struct gss_eap_thread_local_data {
+    krb5_context krbContext;
+    struct gss_eap_status_info *statusInfo;
+};
+
+struct gss_eap_thread_local_data *
+gssEapGetThreadLocalData(void);
+
+void
+gssEapDestroyStatusInfo(struct gss_eap_status_info *status);
+
+void
+gssEapDestroyKrbContext(krb5_context context);
+
 #ifdef __cplusplus
 }
 #endif
 
+#ifdef GSSEAP_ENABLE_ACCEPTOR
 #include "util_json.h"
 #include "util_attr.h"
 #include "util_base64.h"
+#endif /* GSSEAP_ENABLE_ACCEPTOR */
 #ifdef GSSEAP_ENABLE_REAUTH
 #include "util_reauth.h"
 #endif