aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2006-10-03 19:07:17 +0000
committerSam Hartman <hartmans@mit.edu>2006-10-03 19:07:17 +0000
commit63a8ab15aa5ee116b26a50c073fe8ee33e147cbd (patch)
tree40296b89921ea7edb3117c4d38c4132494d4ce06 /src/plugins
parent7f7a4fff296db90d36c39fb01dd35b61bdd6a2b0 (diff)
downloadkrb5-63a8ab15aa5ee116b26a50c073fe8ee33e147cbd.zip
krb5-63a8ab15aa5ee116b26a50c073fe8ee33e147cbd.tar.gz
krb5-63a8ab15aa5ee116b26a50c073fe8ee33e147cbd.tar.bz2
Preauthentication Plugin Framework
Patch from Nalin Dahyabhai at Redhat to implement a preauthentication framework based on the plugin architecture. Currently. the API is considered internal and the header is not installed. See src/include/krb5/preauth_plugin.h for the interface. ticket: new Tags: enhancement Status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18641 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/preauth/cksum_body/Makefile.in42
-rw-r--r--src/plugins/preauth/cksum_body/cksum_body.exports1
-rw-r--r--src/plugins/preauth/cksum_body/configure.in14
-rw-r--r--src/plugins/preauth/cksum_body/src/cksum_body.c489
-rw-r--r--src/plugins/preauth/wpse/Makefile.in42
-rw-r--r--src/plugins/preauth/wpse/configure.in14
-rw-r--r--src/plugins/preauth/wpse/src/wpse.c337
-rw-r--r--src/plugins/preauth/wpse/wpse.exports1
8 files changed, 940 insertions, 0 deletions
diff --git a/src/plugins/preauth/cksum_body/Makefile.in b/src/plugins/preauth/cksum_body/Makefile.in
new file mode 100644
index 0000000..ddac24d
--- /dev/null
+++ b/src/plugins/preauth/cksum_body/Makefile.in
@@ -0,0 +1,42 @@
+thisconfigdir=.
+myfulldir=plugins/preauth/cksum_body
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR)
+DEFS=@DEFS@
+
+LOCALINCLUDES = -I../../../include/krb5
+
+LIBBASE=cksum_body
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/preauth/cksum_body
+# Depends on libk5crypto and libkrb5
+SHLIB_EXPDEPS = \
+ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+ $(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS)
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+STOBJLISTS=OBJS.ST
+STLIBOBJS=src/cksum_body.o
+
+SRCS= $(srcdir)/src/cksum_body.c
+
+all-unix:: $(LIBBASE)$(SO_EXT)
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+clean::
+ $(RM) lib$(LIBBASE)$(SO_EXT)
+
+@libnover_frag@
+@libobj_frag@
+
+# +++ Dependency line eater +++
diff --git a/src/plugins/preauth/cksum_body/cksum_body.exports b/src/plugins/preauth/cksum_body/cksum_body.exports
new file mode 100644
index 0000000..ff5e3f1
--- /dev/null
+++ b/src/plugins/preauth/cksum_body/cksum_body.exports
@@ -0,0 +1 @@
+preauthentication0
diff --git a/src/plugins/preauth/cksum_body/configure.in b/src/plugins/preauth/cksum_body/configure.in
new file mode 100644
index 0000000..868dfd5
--- /dev/null
+++ b/src/plugins/preauth/cksum_body/configure.in
@@ -0,0 +1,14 @@
+K5_AC_INIT(configure.in)
+enable_shared=yes
+build_dynobj=yes
+CONFIG_RULES
+
+AC_CHECK_HEADERS(errno.h string.h)
+
+KRB5_RUN_FLAGS
+dnl The following is for check...
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+AC_CONFIG_HEADERS(config.h)
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/plugins/preauth/cksum_body/src/cksum_body.c b/src/plugins/preauth/cksum_body/src/cksum_body.c
new file mode 100644
index 0000000..ff4cc84
--- /dev/null
+++ b/src/plugins/preauth/cksum_body/src/cksum_body.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Red Hat, Inc., 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 OWNER
+ * 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.
+ */
+
+/*
+ * Checksum the request body with the user's long-term key.
+ *
+ * The e-data from the KDC is a list of network-byte-order 32-bit integers
+ * listing key types which the KDC has for the user.
+ *
+ * The client uses one of these key types to generate a checksum over the body
+ * of the request, and includes the checksum in the AS-REQ as preauthentication
+ * data.
+ *
+ * The AS-REP carries no preauthentication data for this scheme.
+ */
+
+#ident "$Id$"
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include <krb5/krb5.h>
+#include <krb5/preauth_plugin.h>
+
+/* This is not a standardized value. It's defined here only to make it easier
+ * to change in this module. */
+#define KRB5_PADATA_CKSUM_BODY_REQ 130
+
+struct server_stats{
+ int successes, failures;
+};
+
+static int
+client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
+{
+ return PA_REAL;
+}
+
+static krb5_error_code
+client_process(krb5_context kcontext,
+ void *client_module_context,
+ void **client_request_context,
+ krb5_kdc_req *request,
+ krb5_data *encoded_request_body,
+ krb5_data *encoded_previous_request,
+ krb5_pa_data *pa_data,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ preauth_get_as_key_proc gak_fct,
+ krb5_data *salt, krb5_data *s2kparams,
+ void *gak_data,
+ krb5_keyblock *as_key,
+ krb5_pa_data **out_pa_data)
+{
+ krb5_pa_data *send_pa;
+ krb5_checksum checksum;
+ krb5_enctype enctype;
+ krb5_cksumtype *cksumtypes;
+ krb5_error_code status;
+ krb5_int32 cksumtype, *enctypes;
+ unsigned int i, n_enctypes, cksumtype_count;
+
+ memset(&checksum, 0, sizeof(checksum));
+
+ /* Get the user's long-term key if we haven't asked for it yet. Try
+ * all of the encryption types which the server supports. */
+ if (as_key->length == 0) {
+ if ((pa_data != NULL) && (pa_data->length >= 4)) {
+#ifdef DEBUG
+ fprintf(stderr, "%d bytes of preauth data.\n", pa_data->length);
+#endif
+ n_enctypes = pa_data->length / 4;
+ enctypes = (krb5_int32*) pa_data->contents;
+ } else {
+ n_enctypes = request->nktypes;
+ }
+ for (i = 0; i < n_enctypes; i++) {
+ if ((pa_data != NULL) && (pa_data->length >= 4)) {
+ memcpy(&enctype, pa_data->contents + 4 * i, 4);
+ enctype = ntohl(enctype);
+ } else {
+ enctype = request->ktype[i];
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Asking for AS key (type = %d).\n", enctype);
+#endif
+ status = (*gak_fct)(kcontext, request->client, enctype,
+ prompter, prompter_data,
+ salt, s2kparams, as_key, gak_data);
+ if (status == 0)
+ break;
+ }
+ if (status != 0)
+ return status;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Got AS key (type = %d).\n", as_key->enctype);
+#endif
+
+ /* Determine an appropriate checksum type for this key. */
+ cksumtype_count = 0;
+ cksumtypes = NULL;
+ status = krb5_c_keyed_checksum_types(kcontext, as_key->enctype,
+ &cksumtype_count, &cksumtypes);
+ if (status != 0)
+ return status;
+
+ /* Generate the checksum. */
+ for (i = 0; i < cksumtype_count; i++) {
+ status = krb5_c_make_checksum(kcontext, cksumtypes[i], as_key,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+ encoded_request_body,
+ &checksum);
+ if (status == 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Made checksum (type = %d, %d bytes).\n",
+ checksum.checksum_type, encoded_request_body->length);
+#endif
+ break;
+ }
+ }
+ cksumtype = htonl(cksumtypes[i]);
+ krb5_free_cksumtypes(kcontext, cksumtypes);
+ if (status != 0) {
+ if (checksum.length > 0)
+ krb5_free_checksum_contents(kcontext, &checksum);
+ return status;
+ }
+
+ /* Allocate the preauth data structure. */
+ send_pa = malloc(sizeof(krb5_pa_data));
+ if (send_pa == NULL) {
+ krb5_free_checksum_contents(kcontext, &checksum);
+ return ENOMEM;
+ }
+ send_pa->pa_type = KRB5_PADATA_CKSUM_BODY_REQ;
+ send_pa->length = 4 + checksum.length;
+ send_pa->contents = malloc(4 + checksum.length);
+ if (send_pa->contents == NULL) {
+ krb5_free_checksum_contents(kcontext, &checksum);
+ free(send_pa);
+ return ENOMEM;
+ }
+
+ /* Store the checksum. */
+ memcpy(send_pa->contents, &cksumtype, 4);
+ memcpy(send_pa->contents + 4, checksum.contents, checksum.length);
+ *out_pa_data = send_pa;
+
+ /* Clean up. */
+ krb5_free_checksum_contents(kcontext, &checksum);
+
+ return 0;
+}
+
+/* Initialize and tear down the server-side module, and do stat tracking. */
+static krb5_error_code
+server_init(krb5_context kcontext, krb5_preauthtype pa_type,
+ void **module_context)
+{
+ struct server_stats *stats;
+ stats = malloc(sizeof(struct server_stats));
+ if (stats == NULL)
+ return ENOMEM;
+ stats->successes = 0;
+ stats->failures = 0;
+ *module_context = stats;
+ return 0;
+}
+static void
+server_fini(krb5_context kcontext, krb5_preauthtype pa_type,
+ void *module_context)
+{
+ struct server_stats *stats;
+ stats = module_context;
+ if (stats != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "Total %d clients failed pa_type %d, %d succeeded.\n",
+ stats->failures, pa_type, stats->successes);
+#endif
+ free(stats);
+ }
+}
+
+/* Obtain and return any preauthentication data (which is destined for the
+ * client) which matches type data->pa_type. */
+static krb5_error_code
+server_get_edata(krb5_context kcontext,
+ krb5_kdc_req *request,
+ struct _krb5_db_entry_new *client,
+ struct _krb5_db_entry_new *server,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ krb5_pa_data *data)
+{
+ krb5_data *key_data;
+ krb5_keyblock *keys, *key;
+ krb5_int32 *enctypes, enctype;
+ int i;
+
+ /* Retrieve the client's keys. */
+ key_data = NULL;
+ if ((*server_get_entry_data)(kcontext, request, client,
+ krb5plugin_preauth_keys, &key_data) != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Error retrieving client keys.\n");
+#endif
+ return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+ }
+
+ /* Count which types of keys we've got, freeing the contents, which we
+ * don't need at this point. */
+ keys = (krb5_keyblock *) key_data->data;
+ key = NULL;
+ for (i = 0; keys[i].enctype != 0; i++)
+ krb5_free_keyblock_contents(kcontext, &keys[i]);
+
+ /* Return the list of encryption types. */
+ enctypes = malloc(i * 4);
+ if (enctypes == NULL) {
+ krb5_free_data(kcontext, key_data);
+ return ENOMEM;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Supported enctypes = {");
+#endif
+ for (i = 0; keys[i].enctype != 0; i++) {
+#ifdef DEBUG
+ fprintf(stderr, "%s%d", (i > 0) ? ", " : "", keys[i].enctype);
+#endif
+ enctype = htonl(keys[i].enctype);
+ memcpy(&enctypes[i], &enctype, 4);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "}.\n");
+#endif
+ data->pa_type = KRB5_PADATA_CKSUM_BODY_REQ;
+ data->length = (i * 4);
+ data->contents = (unsigned char *) enctypes;
+ krb5_free_data(kcontext, key_data);
+ return 0;
+}
+
+/* Verify a request from a client. */
+static krb5_error_code
+server_verify(krb5_context kcontext,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply,
+ krb5_pa_data *data,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ void **pa_request_context)
+{
+ krb5_int32 cksumtype;
+ krb5_checksum checksum;
+ krb5_boolean valid;
+ krb5_data *key_data, *req_body;
+ krb5_keyblock *keys, *key;
+ size_t length;
+ int i;
+ unsigned int j, cksumtypes_count;
+ krb5_cksumtype *cksumtypes;
+ krb5_error_code status;
+ struct server_stats *stats;
+
+ stats = pa_module_context;
+
+ /* Verify the preauth data. Start with the checksum type. */
+ if (data->length < 4) {
+ stats->failures++;
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ memcpy(&cksumtype, data->contents, 4);
+ memset(&checksum, 0, sizeof(checksum));
+ checksum.checksum_type = ntohl(cksumtype);
+
+ /* Verify that the amount of data we have left is what we expect. */
+ if (krb5_c_checksum_length(kcontext, checksum.checksum_type,
+ &length) != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Error determining checksum size (type = %d). "
+ "Is it supported?\n", checksum.checksum_type);
+#endif
+ stats->failures++;
+ return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+ }
+ if (data->length - 4 != length) {
+#ifdef DEBUG
+ fprintf(stderr, "Checksum size doesn't match client packet size.\n");
+#endif
+ stats->failures++;
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ checksum.length = length;
+
+ /* Pull up the client's keys. */
+ key_data = NULL;
+ if ((*server_get_entry_data)(kcontext, request, client,
+ krb5plugin_preauth_keys, &key_data) != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Error retrieving client keys.\n");
+#endif
+ stats->failures++;
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ /* Find the key which would have been used to generate the checksum. */
+ keys = (krb5_keyblock *) key_data->data;
+ key = NULL;
+ for (i = 0; keys[i].enctype != 0; i++) {
+ key = &keys[i];
+ cksumtypes_count = 0;
+ cksumtypes = NULL;
+ if (krb5_c_keyed_checksum_types(kcontext, key->enctype,
+ &cksumtypes_count, &cksumtypes) != 0)
+ continue;
+ for (j = 0; j < cksumtypes_count; j++) {
+ if (cksumtypes[j] == checksum.checksum_type)
+ break;
+ }
+ if (cksumtypes != NULL)
+ krb5_free_cksumtypes(kcontext, cksumtypes);
+ if (j < cksumtypes_count) {
+#ifdef DEBUG
+ fprintf(stderr, "Found checksum key.\n");
+#endif
+ break;
+ }
+ }
+ if ((key == NULL) || (key->enctype == 0)) {
+ for (i = 0; keys[i].enctype != 0; i++)
+ krb5_free_keyblock_contents(kcontext, &keys[i]);
+ krb5_free_data(kcontext, key_data);
+ stats->failures++;
+ return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+ }
+
+ /* Save a copy of the key. */
+ if (krb5_copy_keyblock(kcontext, &keys[i], &key) != 0) {
+ for (i = 0; keys[i].enctype != 0; i++)
+ krb5_free_keyblock_contents(kcontext, &keys[i]);
+ krb5_free_data(kcontext, key_data);
+ stats->failures++;
+ return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+ }
+ for (i = 0; keys[i].enctype != 0; i++)
+ krb5_free_keyblock_contents(kcontext, &keys[i]);
+ krb5_free_data(kcontext, key_data);
+
+ /* Rebuild a copy of the client's request-body. If we were serious
+ * about doing this with any chance of working interoperability, we'd
+ * extract the structure directly from the req_pkt structure. This
+ * will probably work if it's us on both ends, though. */
+ req_body = NULL;
+ if ((*server_get_entry_data)(kcontext, request, client,
+ krb5plugin_preauth_request_body,
+ &req_body) != 0) {
+ krb5_free_keyblock(kcontext, key);
+ stats->failures++;
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "AS key type %d, checksum type %d, %d bytes.\n",
+ key->enctype, checksum.checksum_type, req_body->length);
+#endif
+
+ /* Verify the checksum itself. */
+ checksum.contents = data->contents + 4;
+ valid = FALSE;
+ status = krb5_c_verify_checksum(kcontext, key,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+ req_body, &checksum, &valid);
+
+ /* Clean up. */
+ krb5_free_data(kcontext, req_body);
+ krb5_free_keyblock(kcontext, key);
+
+ /* Evaluate our results. */
+ if ((status != 0) || (!valid)) {
+#ifdef DEBUG
+ if (status != 0) {
+ fprintf(stderr, "Error in checksum verification.\n");
+ } else {
+ fprintf(stderr, "Checksum mismatch.\n");
+ }
+#endif
+ stats->failures++;
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+
+ /* Note that preauthentication succeeded. */
+ enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ stats->successes++;
+ return 0;
+}
+
+/* Create the response for a client. */
+static krb5_error_code
+server_return(krb5_context kcontext,
+ krb5_pa_data *padata,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *reply,
+ struct _krb5_key_data *client_key,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **send_pa,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ void **pa_request_context)
+{
+ /* We don't need to send data back on the return trip. */
+ *send_pa = NULL;
+ return 0;
+}
+
+static int
+server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
+{
+ return PA_SUFFICIENT;
+}
+
+static krb5_preauthtype supported_client_pa_types[] = {
+ KRB5_PADATA_CKSUM_BODY_REQ, 0,
+};
+static krb5_preauthtype supported_server_pa_types[] = {
+ KRB5_PADATA_CKSUM_BODY_REQ, 0,
+};
+
+struct krb5plugin_preauth_ftable_v0 preauthentication0 = {
+ "cksum_body",
+ &supported_client_pa_types[0],
+ &supported_server_pa_types[0],
+ NULL,
+ NULL,
+ NULL,
+ client_get_flags,
+ NULL,
+ client_process,
+ NULL,
+ server_init,
+ server_fini,
+ server_get_flags,
+ server_get_edata,
+ server_verify,
+ server_return,
+ NULL
+};
diff --git a/src/plugins/preauth/wpse/Makefile.in b/src/plugins/preauth/wpse/Makefile.in
new file mode 100644
index 0000000..6b18a7c
--- /dev/null
+++ b/src/plugins/preauth/wpse/Makefile.in
@@ -0,0 +1,42 @@
+thisconfigdir=.
+myfulldir=plugins/preauth/wpse
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR)
+DEFS=@DEFS@
+
+LOCALINCLUDES = -I../../../include/krb5
+
+LIBBASE=wpse
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/preauth/wpse
+# Depends on libk5crypto and libkrb5
+SHLIB_EXPDEPS = \
+ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+ $(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS)
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+STOBJLISTS=OBJS.ST
+STLIBOBJS=src/wpse.o
+
+SRCS= $(srcdir)/src/wpse.c
+
+all-unix:: $(LIBBASE)$(SO_EXT)
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+clean::
+ $(RM) lib$(LIBBASE)$(SO_EXT)
+
+@libnover_frag@
+@libobj_frag@
+
+# +++ Dependency line eater +++
diff --git a/src/plugins/preauth/wpse/configure.in b/src/plugins/preauth/wpse/configure.in
new file mode 100644
index 0000000..868dfd5
--- /dev/null
+++ b/src/plugins/preauth/wpse/configure.in
@@ -0,0 +1,14 @@
+K5_AC_INIT(configure.in)
+enable_shared=yes
+build_dynobj=yes
+CONFIG_RULES
+
+AC_CHECK_HEADERS(errno.h string.h)
+
+KRB5_RUN_FLAGS
+dnl The following is for check...
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+AC_CONFIG_HEADERS(config.h)
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/plugins/preauth/wpse/src/wpse.c b/src/plugins/preauth/wpse/src/wpse.c
new file mode 100644
index 0000000..579c63b
--- /dev/null
+++ b/src/plugins/preauth/wpse/src/wpse.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Red Hat, Inc., 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 OWNER
+ * 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.
+ */
+
+/* Worst. Preauthentication. Scheme. Ever. */
+
+#ident "$Id$"
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include <krb5/krb5.h>
+#include <krb5/preauth_plugin.h>
+
+/* This is not a standardized value. It's defined here only to make it easier
+ * to change in this module. */
+#define KRB5_PADATA_WPSE_REQ 131
+
+static int
+client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
+{
+ return PA_REAL;
+}
+
+static krb5_error_code
+client_init(krb5_context kcontext, krb5_preauthtype pa_type, void **ctx)
+{
+ int *mctx;
+
+ mctx = malloc(sizeof(int));
+ if (mctx == NULL)
+ return ENOMEM;
+ *mctx = 0;
+ *ctx = mctx;
+ return 0;
+}
+
+static void
+client_fini(krb5_context kcontext, krb5_preauthtype pa_type, void *ctx)
+{
+ int *mctx;
+
+ mctx = ctx;
+ if (mctx) {
+#ifdef DEBUG
+ fprintf(stderr, "wpse module called total of %d times\n", *mctx);
+#endif
+ free(mctx);
+ }
+}
+
+static krb5_error_code
+client_process(krb5_context kcontext,
+ void *module_context,
+ void **request_context,
+ krb5_kdc_req *request,
+ krb5_data *encoded_request_body,
+ krb5_data *encoded_previous_request,
+ krb5_pa_data *pa_data,
+ krb5_prompter_fct prompter,
+ void *prompter_data,
+ preauth_get_as_key_proc gak_fct,
+ krb5_data *salt, krb5_data *s2kparams,
+ void *gak_data,
+ krb5_keyblock *as_key,
+ krb5_pa_data **out_pa_data)
+{
+ krb5_pa_data *send_pa;
+ krb5_int32 nnonce, enctype;
+ krb5_keyblock *kb;
+ krb5_error_code status;
+ int *mctx;
+
+#ifdef DEBUG
+ fprintf(stderr, "%d bytes of preauthentication data (type %d)\n",
+ pa_data->length, pa_data->pa_type);
+#endif
+
+ mctx = module_context;
+ if (mctx) {
+ (*mctx)++;
+ }
+
+ if (pa_data->length == 0) {
+ /* Create preauth data. */
+ send_pa = malloc(sizeof(krb5_pa_data));
+ if (send_pa == NULL)
+ return ENOMEM;
+ send_pa->pa_type = KRB5_PADATA_WPSE_REQ;
+ send_pa->length = 4;
+ send_pa->contents = malloc(4);
+ if (send_pa->contents == NULL) {
+ free(send_pa);
+ return ENOMEM;
+ }
+ /* Store the preauth data. */
+ nnonce = htonl(request->nonce);
+ memcpy(send_pa->contents, &nnonce, 4);
+ *out_pa_data = send_pa;
+ /* Allocate a context. Useful for verifying that we do in fact
+ * do per-request cleanup. */
+ if (*request_context == NULL)
+ *request_context = malloc(4);
+ } else {
+ /* A reply from the KDC. Conventionally this would be
+ * indicated by a different preauthentication type, but this
+ * mechanism/implementation doesn't do that. */
+ if (pa_data->length > 4) {
+ memcpy(&enctype, pa_data->contents, 4);
+ kb = NULL;
+ status = krb5_init_keyblock(kcontext, ntohl(enctype),
+ pa_data->length - 4, &kb);
+ if (status != 0)
+ return status;
+ memcpy(kb->contents, pa_data->contents + 4, pa_data->length - 4);
+#ifdef DEBUG
+ fprintf(stderr, "Recovered key type=%d, length=%d.\n",
+ kb->enctype, kb->length);
+#endif
+ status = krb5_copy_keyblock_contents(kcontext, kb, as_key);
+ krb5_free_keyblock(kcontext, kb);
+ return status;
+ }
+ return KRB5KRB_ERR_GENERIC;
+ }
+ return 0;
+}
+
+static void
+client_cleanup(krb5_context kcontext, void *module_context,
+ void **request_context)
+{
+ if (*request_context != NULL) {
+ free(*request_context);
+ *request_context = NULL;
+ }
+ return;
+}
+
+/* Free state. */
+static krb5_error_code
+server_free_pa_request_context(krb5_context kcontext, void *module_context,
+ void **request_context)
+{
+ if (*request_context != NULL) {
+ free(*request_context);
+ *request_context = NULL;
+ }
+ return 0;
+}
+
+/* Obtain and return any preauthentication data (which is destined for the
+ * client) which matches type data->pa_type. */
+static krb5_error_code
+server_get_edata(krb5_context kcontext,
+ krb5_kdc_req *request,
+ struct _krb5_db_entry_new *client,
+ struct _krb5_db_entry_new *server,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ krb5_pa_data *data)
+{
+ /* Return zero bytes of data. */
+ data->length = 0;
+ data->contents = NULL;
+ return 0;
+}
+
+/* Verify a request from a client. */
+static krb5_error_code
+server_verify(krb5_context kcontext,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply,
+ krb5_pa_data *data,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ void **pa_request_context)
+{
+ krb5_int32 nnonce;
+ /* Verify the preauth data. */
+ if (data->length != 4)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ memcpy(&nnonce, data->contents, 4);
+ nnonce = ntohl(nnonce);
+ if (memcmp(&nnonce, &request->nonce, 4) != 0)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ /* Note that preauthentication succeeded. */
+ enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
+ /* Allocate a context. Useful for verifying that we do in fact do
+ * per-request cleanup. */
+ if (*pa_request_context == NULL)
+ *pa_request_context = malloc(4);
+ return 0;
+}
+
+/* Create the response for a client. */
+static krb5_error_code
+server_return(krb5_context kcontext,
+ krb5_pa_data *padata,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_kdc_rep *reply,
+ struct _krb5_key_data *client_key,
+ krb5_keyblock *encrypting_key,
+ krb5_pa_data **send_pa,
+ preauth_get_entry_data_proc server_get_entry_data,
+ void *pa_module_context,
+ void **pa_request_context)
+{
+ /* This module does a couple of dumb things. It tags its reply with
+ * the same type as the initial challenge (expecting the client to sort
+ * out whether there's anything useful in there). Oh, and it replaces
+ * the AS reply key with one which is sent in the clear. */
+ krb5_keyblock *kb;
+ krb5_int32 enctype;
+ int i;
+
+ *send_pa = NULL;
+
+ /* We'll want a key with the first supported enctype. */
+ for (i = 0; i < request->nktypes; i++) {
+ kb = NULL;
+ if (krb5_init_keyblock(kcontext, request->ktype[i], 0, &kb) == 0) {
+ break;
+ }
+ }
+ if (i >= request->nktypes) {
+ /* No matching cipher type found. */
+ return 0;
+ }
+
+ /* Randomize a key and save it for the client. */
+ if (krb5_c_make_random_key(kcontext, request->ktype[i], kb) != 0) {
+ krb5_free_keyblock(kcontext, kb);
+ return 0;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Generated random key, type=%d, length=%d.\n",
+ kb->enctype, kb->length);
+#endif
+
+ *send_pa = malloc(sizeof(krb5_pa_data));
+ if (*send_pa == NULL) {
+ krb5_free_keyblock(kcontext, kb);
+ return ENOMEM;
+ }
+ (*send_pa)->pa_type = KRB5_PADATA_WPSE_REQ;
+ (*send_pa)->length = 4 + kb->length;
+ (*send_pa)->contents = malloc(4 + kb->length);
+ if ((*send_pa)->contents == NULL) {
+ free(*send_pa);
+ *send_pa = NULL;
+ krb5_free_keyblock(kcontext, kb);
+ return ENOMEM;
+ }
+
+ /* Store the preauth data. */
+ enctype = htonl(kb->enctype);
+ memcpy((*send_pa)->contents, &enctype, 4);
+ memcpy((*send_pa)->contents + 4, kb->contents, kb->length);
+ krb5_copy_keyblock_contents(kcontext, kb, encrypting_key);
+
+ /* Clean up. */
+ krb5_free_keyblock(kcontext, kb);
+
+ return 0;
+}
+
+static int
+server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type)
+{
+ return PA_HARDWARE | PA_REPLACES_KEY;
+}
+
+static krb5_preauthtype supported_client_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0};
+static krb5_preauthtype supported_server_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0};
+
+struct krb5plugin_preauth_ftable_v0 preauthentication0 = {
+ "wpse",
+ &supported_client_pa_types[0],
+ &supported_server_pa_types[0],
+ NULL,
+ client_init,
+ client_fini,
+ client_get_flags,
+ client_cleanup,
+ client_process,
+ NULL,
+ NULL,
+ NULL,
+ server_get_flags,
+ server_get_edata,
+ server_verify,
+ server_return,
+ server_free_pa_request_context,
+};
diff --git a/src/plugins/preauth/wpse/wpse.exports b/src/plugins/preauth/wpse/wpse.exports
new file mode 100644
index 0000000..ff5e3f1
--- /dev/null
+++ b/src/plugins/preauth/wpse/wpse.exports
@@ -0,0 +1 @@
+preauthentication0