summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/appl/gssmask
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/appl/gssmask')
-rw-r--r--third_party/heimdal/appl/gssmask/Makefile.am13
-rw-r--r--third_party/heimdal/appl/gssmask/NTMakefile35
-rw-r--r--third_party/heimdal/appl/gssmask/common.c97
-rw-r--r--third_party/heimdal/appl/gssmask/common.h114
-rw-r--r--third_party/heimdal/appl/gssmask/gssmaestro.c962
-rw-r--r--third_party/heimdal/appl/gssmask/gssmask.c1272
-rw-r--r--third_party/heimdal/appl/gssmask/protocol.h317
7 files changed, 2810 insertions, 0 deletions
diff --git a/third_party/heimdal/appl/gssmask/Makefile.am b/third_party/heimdal/appl/gssmask/Makefile.am
new file mode 100644
index 0000000..55673a0
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/Makefile.am
@@ -0,0 +1,13 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+noinst_PROGRAMS = gssmask gssmaestro
+
+gssmask_SOURCES = gssmask.c common.c common.h protocol.h
+
+gssmaestro_SOURCES = gssmaestro.c common.c common.h protocol.h
+
+LDADD = $(top_builddir)/lib/gssapi/libgssapi.la $(LIB_roken) $(top_builddir)/lib/krb5/libkrb5.la
+
+EXTRA_DIST = NTMakefile
diff --git a/third_party/heimdal/appl/gssmask/NTMakefile b/third_party/heimdal/appl/gssmask/NTMakefile
new file mode 100644
index 0000000..4ad1dc4
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/NTMakefile
@@ -0,0 +1,35 @@
+########################################################################
+#
+# Copyright (c) 2009, Secure Endpoints 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.
+#
+# 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.
+#
+
+RELDIR=appl\gssmask
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/gssmask/common.c b/third_party/heimdal/appl/gssmask/common.c
new file mode 100644
index 0000000..733db90
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/common.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <common.h>
+RCSID("$Id$");
+
+krb5_error_code
+store_string(krb5_storage *sp, const char *str)
+{
+ size_t len = strlen(str) + 1;
+ krb5_error_code ret;
+
+ ret = krb5_store_int32(sp, len);
+ if (ret)
+ return ret;
+ ret = krb5_storage_write(sp, str, len);
+ if (ret != len)
+ return EINVAL;
+ return 0;
+}
+
+static void
+add_list(char ****list, size_t *listlen, char **str, size_t len)
+{
+ size_t i;
+ *list = erealloc(*list, sizeof(**list) * (*listlen + 1));
+
+ (*list)[*listlen] = ecalloc(len, sizeof(***list));
+ for (i = 0; i < len; i++)
+ (*list)[*listlen][i] = str[i];
+ (*listlen)++;
+}
+
+static void
+permute(char ****list, size_t *listlen,
+ char **str, const int start, const int len)
+{
+ int i, j;
+
+#define SWAP(s,i,j) { char *t = str[i]; str[i] = str[j]; str[j] = t; }
+
+ for (i = start; i < len - 1; i++) {
+ for (j = i+1; j < len; j++) {
+ SWAP(str,i,j);
+ permute(list, listlen, str, i+1, len);
+ SWAP(str,i,j);
+ }
+ }
+ add_list(list, listlen, str, len);
+}
+
+char ***
+permutate_all(struct getarg_strings *strings, size_t *size)
+{
+ char **list, ***all = NULL;
+ int i;
+
+ *size = 0;
+
+ list = ecalloc(strings->num_strings, sizeof(*list));
+ for (i = 0; i < strings->num_strings; i++)
+ list[i] = strings->strings[i];
+
+ permute(&all, size, list, 0, strings->num_strings);
+ free(list);
+ return all;
+}
diff --git a/third_party/heimdal/appl/gssmask/common.h b/third_party/heimdal/appl/gssmask/common.h
new file mode 100644
index 0000000..96d10ff
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/common.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2006 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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$ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/param.h>
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <assert.h>
+#include <krb5.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include <unistd.h>
+
+#include <roken.h>
+#include <getarg.h>
+
+#include "protocol.h"
+
+/*
+ * pthread support is disable because the pthread
+ * test have no "application pthread libflags" variable,
+ * when this is fixed pthread support can be enabled again.
+ */
+#undef ENABLE_PTHREAD_SUPPORT
+
+krb5_error_code store_string(krb5_storage *, const char *);
+
+
+#define ret16(_client, num) \
+ do { \
+ if (krb5_ret_int16((_client)->sock, &(num)) != 0) \
+ errx(1, "krb5_ret_int16 " #num); \
+ } while(0)
+
+#define ret32(_client, num) \
+ do { \
+ if (krb5_ret_int32((_client)->sock, &(num)) != 0) \
+ errx(1, "krb5_ret_int32 " #num); \
+ } while(0)
+
+#define retdata(_client, data) \
+ do { \
+ if (krb5_ret_data((_client)->sock, &(data)) != 0) \
+ errx(1, "krb5_ret_data " #data); \
+ } while(0)
+
+#define retstring(_client, data) \
+ do { \
+ if (krb5_ret_string((_client)->sock, &(data)) != 0) \
+ errx(1, "krb5_ret_data " #data); \
+ } while(0)
+
+
+#define put32(_client, num) \
+ do { \
+ if (krb5_store_int32((_client)->sock, num) != 0) \
+ errx(1, "krb5_store_int32 " #num); \
+ } while(0)
+
+#define putdata(_client, data) \
+ do { \
+ if (krb5_store_data((_client)->sock, data) != 0) \
+ errx(1, "krb5_store_data " #data); \
+ } while(0)
+
+#define putstring(_client, str) \
+ do { \
+ if (store_string((_client)->sock, str) != 0) \
+ errx(1, "krb5_store_str " #str); \
+ } while(0)
+
+char *** permutate_all(struct getarg_strings *, size_t *);
diff --git a/third_party/heimdal/appl/gssmask/gssmaestro.c b/third_party/heimdal/appl/gssmask/gssmaestro.c
new file mode 100644
index 0000000..9ccf1de
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/gssmaestro.c
@@ -0,0 +1,962 @@
+/*
+ * Copyright (c) 2006 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <common.h>
+RCSID("$Id$");
+
+static FILE *logfile;
+
+/*
+ *
+ */
+
+struct client {
+ char *name;
+ struct sockaddr *sa;
+ socklen_t salen;
+ krb5_storage *sock;
+ int32_t capabilities;
+ char *target_name;
+ char *moniker;
+ krb5_storage *logsock;
+ int have_log;
+#ifdef ENABLE_PTHREAD_SUPPORT
+ pthread_t thr;
+#else
+ pid_t child;
+#endif
+};
+
+static struct client **clients;
+static int num_clients;
+
+static int
+init_sec_context(struct client *client,
+ int32_t *hContext, int32_t *hCred,
+ int32_t flags,
+ const char *targetname,
+ const krb5_data *itoken, krb5_data *otoken)
+{
+ int32_t val;
+ krb5_data_zero(otoken);
+ put32(client, eInitContext);
+ put32(client, *hContext);
+ put32(client, *hCred);
+ put32(client, flags);
+ putstring(client, targetname);
+ putdata(client, *itoken);
+ ret32(client, *hContext);
+ ret32(client, val);
+ retdata(client, *otoken);
+ return val;
+}
+
+static int
+accept_sec_context(struct client *client,
+ int32_t *hContext,
+ int32_t flags,
+ const krb5_data *itoken,
+ krb5_data *otoken,
+ int32_t *hDelegCred)
+{
+ int32_t val;
+ krb5_data_zero(otoken);
+ put32(client, eAcceptContext);
+ put32(client, *hContext);
+ put32(client, flags);
+ putdata(client, *itoken);
+ ret32(client, *hContext);
+ ret32(client, val);
+ retdata(client, *otoken);
+ ret32(client, *hDelegCred);
+ return val;
+}
+
+static int
+acquire_cred(struct client *client,
+ const char *username,
+ const char *password,
+ int32_t flags,
+ int32_t *hCred)
+{
+ int32_t val;
+ put32(client, eAcquireCreds);
+ putstring(client, username);
+ putstring(client, password);
+ put32(client, flags);
+ ret32(client, val);
+ ret32(client, *hCred);
+ return val;
+}
+
+static int
+toast_resource(struct client *client,
+ int32_t hCred)
+{
+ int32_t val;
+ put32(client, eToastResource);
+ put32(client, hCred);
+ ret32(client, val);
+ return val;
+}
+
+static int
+goodbye(struct client *client)
+{
+ put32(client, eGoodBye);
+ return GSMERR_OK;
+}
+
+static int
+get_targetname(struct client *client,
+ char **target)
+{
+ put32(client, eGetTargetName);
+ retstring(client, *target);
+ return GSMERR_OK;
+}
+
+static int32_t
+encrypt_token(struct client *client, int32_t hContext, int32_t flags,
+ krb5_data *in, krb5_data *out)
+{
+ int32_t val;
+ put32(client, eEncrypt);
+ put32(client, hContext);
+ put32(client, flags);
+ put32(client, 0);
+ putdata(client, *in);
+ ret32(client, val);
+ retdata(client, *out);
+ return val;
+}
+
+static int32_t
+decrypt_token(struct client *client, int32_t hContext, int flags,
+ krb5_data *in, krb5_data *out)
+{
+ int32_t val;
+ put32(client, eDecrypt);
+ put32(client, hContext);
+ put32(client, flags);
+ put32(client, 0);
+ putdata(client, *in);
+ ret32(client, val);
+ retdata(client, *out);
+ return val;
+}
+
+static int32_t
+wrap_token_ext(struct client *client, int32_t hContext, int32_t flags,
+ int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,
+ krb5_data *out)
+{
+ int32_t val;
+ put32(client, eWrapExt);
+ put32(client, hContext);
+ put32(client, flags);
+ put32(client, bflags);
+ putdata(client, *header);
+ putdata(client, *in);
+ putdata(client, *trailer);
+ ret32(client, val);
+ retdata(client, *out);
+ return val;
+}
+
+static int32_t
+unwrap_token_ext(struct client *client, int32_t hContext, int32_t flags,
+ int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,
+ krb5_data *out)
+{
+ int32_t val;
+ put32(client, eUnwrapExt);
+ put32(client, hContext);
+ put32(client, flags);
+ put32(client, bflags);
+ putdata(client, *header);
+ putdata(client, *in);
+ putdata(client, *trailer);
+ ret32(client, val);
+ retdata(client, *out);
+ return val;
+}
+
+static int32_t
+get_mic(struct client *client, int32_t hContext,
+ krb5_data *in, krb5_data *mic)
+{
+ int32_t val;
+ put32(client, eSign);
+ put32(client, hContext);
+ put32(client, 0);
+ put32(client, 0);
+ putdata(client, *in);
+ ret32(client, val);
+ retdata(client, *mic);
+ return val;
+}
+
+static int32_t
+verify_mic(struct client *client, int32_t hContext,
+ krb5_data *in, krb5_data *mic)
+{
+ int32_t val;
+ put32(client, eVerify);
+ put32(client, hContext);
+ put32(client, 0);
+ put32(client, 0);
+ putdata(client, *in);
+ putdata(client, *mic);
+ ret32(client, val);
+ return val;
+}
+
+
+static int32_t
+get_version_capa(struct client *client,
+ int32_t *version, int32_t *capa,
+ char **version_str)
+{
+ put32(client, eGetVersionAndCapabilities);
+ ret32(client, *version);
+ ret32(client, *capa);
+ retstring(client, *version_str);
+ return GSMERR_OK;
+}
+
+static int32_t
+get_moniker(struct client *client,
+ char **moniker)
+{
+ put32(client, eGetMoniker);
+ retstring(client, *moniker);
+ return GSMERR_OK;
+}
+
+static int
+wait_log(struct client *c)
+{
+ int32_t port;
+ struct sockaddr_storage sast;
+ socklen_t salen = sizeof(sast);
+ krb5_socket_t sock, sock2;
+ int ret;
+
+ memset(&sast, 0, sizeof(sast));
+
+ assert(sizeof(sast) >= c->salen);
+
+ sock = socket(c->sa->sa_family, SOCK_STREAM, 0);
+ if (sock == rk_INVALID_SOCKET)
+ err(1, "failed to build socket for %s's logging port", c->moniker);
+
+ sast.ss_family = c->sa->sa_family;
+ ret = bind(sock, (struct sockaddr *)&sast, c->salen);
+ if (ret < 0)
+ err(1, "failed to bind %s's logging port", c->moniker);
+
+ if (listen(sock, SOMAXCONN) < 0)
+ err(1, "failed to listen %s's logging port", c->moniker);
+
+ salen = sizeof(sast);
+ ret = getsockname(sock, (struct sockaddr *)&sast, &salen);
+ if (ret < 0)
+ err(1, "failed to get address of local socket for %s", c->moniker);
+
+ port = socket_get_port((struct sockaddr *)&sast);
+
+ put32(c, eSetLoggingSocket);
+ put32(c, ntohs(port));
+
+ salen = sizeof(sast);
+ sock2 = accept(sock, (struct sockaddr *)&sast, &salen);
+ if (sock2 == rk_INVALID_SOCKET)
+ err(1, "failed to accept local socket for %s", c->moniker);
+ rk_closesocket(sock);
+
+ return sock2;
+}
+
+
+
+
+static int
+build_context(struct client *ipeer, struct client *apeer,
+ int32_t flags, int32_t hCred,
+ int32_t *iContext, int32_t *aContext, int32_t *hDelegCred)
+{
+ int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0;
+ krb5_data itoken, otoken;
+ int iDone = 0, aDone = 0;
+ int step = 0;
+ int first_call = 0x80;
+
+ if (apeer->target_name == NULL)
+ errx(1, "apeer %s have no target name", apeer->name);
+
+ krb5_data_zero(&itoken);
+
+ while (!iDone || !aDone) {
+
+ if (iDone) {
+ warnx("iPeer already done, aPeer want extra rtt");
+ val = GSMERR_ERROR;
+ goto out;
+ }
+
+ val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,
+ apeer->target_name, &itoken, &otoken);
+ step++;
+ switch(val) {
+ case GSMERR_OK:
+ iDone = 1;
+ if (aDone)
+ continue;
+ break;
+ case GSMERR_CONTINUE_NEEDED:
+ break;
+ default:
+ warnx("iPeer %s failed with %d (step %d)",
+ ipeer->name, (int)val, step);
+ goto out;
+ }
+
+ if (aDone) {
+ warnx("aPeer already done, iPeer want extra rtt");
+ val = GSMERR_ERROR;
+ goto out;
+ }
+
+ val = accept_sec_context(apeer, &ac, flags|first_call,
+ &otoken, &itoken, &deleg);
+ step++;
+ switch(val) {
+ case GSMERR_OK:
+ aDone = 1;
+ if (iDone)
+ continue;
+ break;
+ case GSMERR_CONTINUE_NEEDED:
+ break;
+ default:
+ warnx("aPeer %s failed with %d (step %d)",
+ apeer->name, (int)val, step);
+ val = GSMERR_ERROR;
+ goto out;
+ }
+ first_call = 0;
+ val = GSMERR_OK;
+ }
+
+ if (iContext == NULL || val != GSMERR_OK) {
+ if (ic)
+ toast_resource(ipeer, ic);
+ if (iContext)
+ *iContext = 0;
+ } else
+ *iContext = ic;
+
+ if (aContext == NULL || val != GSMERR_OK) {
+ if (ac)
+ toast_resource(apeer, ac);
+ if (aContext)
+ *aContext = 0;
+ } else
+ *aContext = ac;
+
+ if (hDelegCred == NULL || val != GSMERR_OK) {
+ if (deleg)
+ toast_resource(apeer, deleg);
+ if (hDelegCred)
+ *hDelegCred = 0;
+ } else
+ *hDelegCred = deleg;
+
+out:
+ return val;
+}
+
+static void
+test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
+{
+ krb5_data msg, mic;
+ int32_t val;
+
+ msg.data = "foo";
+ msg.length = 3;
+
+ krb5_data_zero(&mic);
+
+ val = get_mic(c1, hc1, &msg, &mic);
+ if (val)
+ errx(1, "get_mic failed to host: %s", c1->moniker);
+ val = verify_mic(c2, hc2, &msg, &mic);
+ if (val)
+ errx(1, "verify_mic failed to host: %s", c2->moniker);
+
+ krb5_data_free(&mic);
+}
+
+static int32_t
+test_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
+ int conf)
+{
+ krb5_data msg, wrapped, out;
+ int32_t val;
+
+ msg.data = "foo";
+ msg.length = 3;
+
+ krb5_data_zero(&wrapped);
+ krb5_data_zero(&out);
+
+ val = encrypt_token(c1, hc1, conf, &msg, &wrapped);
+ if (val) {
+ warnx("encrypt_token failed to host: %s", c1->moniker);
+ return val;
+ }
+ val = decrypt_token(c2, hc2, conf, &wrapped, &out);
+ if (val) {
+ krb5_data_free(&wrapped);
+ warnx("decrypt_token failed to host: %s", c2->moniker);
+ return val;
+ }
+
+ if (msg.length != out.length) {
+ warnx("decrypted'ed token have wrong length (%lu != %lu)",
+ (unsigned long)msg.length, (unsigned long)out.length);
+ val = GSMERR_ERROR;
+ } else if (memcmp(msg.data, out.data, msg.length) != 0) {
+ warnx("decryptd'ed token have wrong data");
+ val = GSMERR_ERROR;
+ }
+
+ krb5_data_free(&wrapped);
+ krb5_data_free(&out);
+ return val;
+}
+
+static int32_t
+test_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
+ int conf, int bflags)
+{
+ krb5_data header, msg, trailer, wrapped, out;
+ int32_t val;
+
+ header.data = "header";
+ header.length = sizeof("header") - 1;
+
+ msg.data = "0123456789abcdef"; /* padded for most enctypes */
+ msg.length = sizeof("0123456789abcdef") - 1;
+
+ trailer.data = "trailer";
+ trailer.length = 7;
+
+ krb5_data_zero(&wrapped);
+ krb5_data_zero(&out);
+
+ val = wrap_token_ext(c1, hc1, conf, bflags, &header, &msg, &trailer, &wrapped);
+ if (val) {
+ warnx("encrypt_token failed to host: %s", c1->moniker);
+ return val;
+ }
+ val = unwrap_token_ext(c2, hc2, conf, bflags, &header, &wrapped, &trailer, &out);
+ if (val) {
+ krb5_data_free(&wrapped);
+ warnx("decrypt_token failed to host: %s", c2->moniker);
+ return val;
+ }
+
+ if (msg.length != out.length) {
+ warnx("decrypted'ed token have wrong length (%lu != %lu)",
+ (unsigned long)msg.length, (unsigned long)out.length);
+ val = GSMERR_ERROR;
+ } else if (memcmp(msg.data, out.data, msg.length) != 0) {
+ warnx("decryptd'ed token have wrong data");
+ val = GSMERR_ERROR;
+ }
+
+ krb5_data_free(&wrapped);
+ krb5_data_free(&out);
+ return val;
+}
+
+
+static int32_t
+test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int wrap_ext)
+{
+ int32_t val;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ /* mic */
+ test_mic(c1, hc1, c2, hc2);
+ test_mic(c2, hc2, c1, hc1);
+
+ /* wrap */
+ val = test_wrap(c1, hc1, c2, hc2, 0);
+ if (val) return val;
+ val = test_wrap(c2, hc2, c1, hc1, 0);
+ if (val) return val;
+
+ val = test_wrap(c1, hc1, c2, hc2, 1);
+ if (val) return val;
+ val = test_wrap(c2, hc2, c1, hc1, 1);
+ if (val) return val;
+
+ if (wrap_ext) {
+ /* wrap ext */
+ val = test_wrap_ext(c1, hc1, c2, hc2, 1, 0);
+ if (val) return val;
+ val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0);
+ if (val) return val;
+
+ val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1);
+ if (val) return val;
+ val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1);
+ if (val) return val;
+
+ val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0);
+ if (val) return val;
+ val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0);
+ if (val) return val;
+
+ val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1);
+ if (val) return val;
+ val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1);
+ if (val) return val;
+ }
+ }
+ return GSMERR_OK;
+}
+
+static int
+log_function(void *ptr)
+{
+ struct client *c = ptr;
+ int32_t cmd, line;
+ char *file = NULL, *string = NULL;
+
+ while (1) {
+ if (krb5_ret_int32(c->logsock, &cmd))
+ goto out;
+
+ switch (cmd) {
+ case eLogSetMoniker:
+ if (krb5_ret_string(c->logsock, &file))
+ goto out;
+ break;
+ case eLogInfo:
+ case eLogFailure:
+ if (krb5_ret_string(c->logsock, &file))
+ goto out;
+ if (krb5_ret_int32(c->logsock, &line))
+ goto out;
+ if (krb5_ret_string(c->logsock, &string))
+ goto out;
+ printf("%s:%lu: %s\n",
+ file, (unsigned long)line, string);
+ fprintf(logfile, "%s:%lu: %s\n",
+ file, (unsigned long)line, string);
+ fflush(logfile);
+ if (krb5_store_int32(c->logsock, 0))
+ goto out;
+ break;
+ default:
+ errx(1, "client send bad log command: %d", (int)cmd);
+ }
+ }
+out:
+ free(file);
+ free(string);
+
+ return 0;
+}
+
+static void
+connect_client(const char *slave)
+{
+ char *name, *port;
+ struct client *c = ecalloc(1, sizeof(*c));
+ struct addrinfo hints, *res0, *res;
+ int ret;
+ krb5_socket_t sock;
+
+ name = estrdup(slave);
+ port = strchr(name, ':');
+ if (port == NULL)
+ errx(1, "port missing from %s", name);
+ *port++ = 0;
+
+ c->name = estrdup(slave);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ ret = getaddrinfo(name, port, &hints, &res0);
+ if (ret)
+ errx(1, "error resolving %s", name);
+
+ for (res = res0, sock = rk_INVALID_SOCKET; res; res = res->ai_next) {
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock == rk_INVALID_SOCKET)
+ continue;
+ if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ rk_closesocket(sock);
+ sock = rk_INVALID_SOCKET;
+ continue;
+ }
+ c->sa = ecalloc(1, res->ai_addrlen);
+ memcpy(c->sa, res->ai_addr, res->ai_addrlen);
+ c->salen = res->ai_addrlen;
+ break; /* okay we got one */
+ }
+ if (sock == rk_INVALID_SOCKET)
+ err(1, "connect to host: %s", name);
+ freeaddrinfo(res0);
+
+ c->sock = krb5_storage_from_socket(sock);
+ rk_closesocket(sock);
+ if (c->sock == NULL)
+ errx(1, "krb5_storage_from_fd");
+
+ {
+ int32_t version;
+ char *str = NULL;
+ get_version_capa(c, &version, &c->capabilities, &str);
+ if (str) {
+ free(str);
+ }
+ if (c->capabilities & HAS_MONIKER)
+ get_moniker(c, &c->moniker);
+ else
+ c->moniker = c->name;
+ if (c->capabilities & ISSERVER)
+ get_targetname(c, &c->target_name);
+ }
+
+ if (logfile) {
+ printf("starting log socket to client %s\n", c->moniker);
+
+ sock = wait_log(c);
+
+ c->logsock = krb5_storage_from_socket(sock);
+ rk_closesocket(sock);
+ if (c->logsock == NULL)
+ errx(1, "failed to create log krb5_storage");
+#ifdef ENABLE_PTHREAD_SUPPORT
+ pthread_create(&c->thr, NULL, log_function, c);
+#else
+ c->child = fork();
+ if (c->child == -1)
+ errx(1, "failed to fork");
+ else if (c->child == 0) {
+ log_function(c);
+ fclose(logfile);
+ exit(0);
+ }
+#endif
+ }
+
+
+ clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));
+
+ clients[num_clients] = c;
+ num_clients++;
+
+ free(name);
+}
+
+static struct client *
+get_client(const char *slave)
+{
+ size_t i;
+ for (i = 0; i < num_clients; i++)
+ if (strcmp(slave, clients[i]->name) == 0)
+ return clients[i];
+ errx(1, "failed to find client %s", slave);
+}
+
+/*
+ *
+ */
+
+static int version_flag;
+static int help_flag;
+static int wrap_ext = 0;
+static char *logfile_str;
+static getarg_strings principals;
+static getarg_strings slaves;
+
+struct getargs args[] = {
+ { "principals", 0, arg_strings, &principals, "Test principal",
+ NULL },
+ { "slaves", 0, arg_strings, &slaves, "Slaves",
+ NULL },
+ { "log-file", 0, arg_string, &logfile_str, "Logfile",
+ NULL },
+ { "wrap-ext", 0, arg_flag, &wrap_ext, "test wrap extended",
+ NULL },
+ { "version", 0, arg_flag, &version_flag, "Print version",
+ NULL },
+ { "help", 0, arg_flag, &help_flag, NULL,
+ NULL }
+};
+
+static void
+usage(int ret)
+{
+ arg_printusage (args,
+ sizeof(args) / sizeof(args[0]),
+ NULL,
+ "");
+ exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optidx= 0;
+ char *user;
+ char *password;
+ char ***list, **p;
+ size_t num_list, i, j, k;
+ int failed = 0;
+
+ setprogname (argv[0]);
+
+ if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
+ usage (1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ print_version (NULL);
+ return 0;
+ }
+
+ if (optidx != argc)
+ usage (1);
+
+ if (principals.num_strings == 0)
+ errx(1, "no principals");
+
+ user = estrdup(principals.strings[0]);
+ password = strchr(user, ':');
+ if (password == NULL)
+ errx(1, "password missing from %s", user);
+ *password++ = 0;
+
+ if (slaves.num_strings == 0)
+ errx(1, "no principals");
+
+ if (logfile_str) {
+ printf("open logfile %s\n", logfile_str);
+ logfile = fopen(logfile_str, "w+");
+ if (logfile == NULL)
+ err(1, "failed to open: %s", logfile_str);
+ }
+
+ /*
+ *
+ */
+
+ list = permutate_all(&slaves, &num_list);
+
+ /*
+ * Set up connection to all clients
+ */
+
+ printf("Connecting to slaves\n");
+ for (i = 0; i < slaves.num_strings; i++)
+ connect_client(slaves.strings[i]);
+
+ /*
+ * Test acquire credentials
+ */
+
+ printf("Test acquire credentials\n");
+ for (i = 0; i < slaves.num_strings; i++) {
+ int32_t hCred, val;
+
+ val = acquire_cred(clients[i], user, password, 1, &hCred);
+ if (val != GSMERR_OK) {
+ warnx("Failed to acquire_cred on host %s: %d",
+ clients[i]->moniker, (int)val);
+ failed = 1;
+ } else
+ toast_resource(clients[i], hCred);
+ }
+
+ if (failed)
+ goto out;
+
+ /*
+ * First test if all slaves can build context to them-self.
+ */
+
+ printf("Self context tests\n");
+ for (i = 0; i < num_clients; i++) {
+ int32_t hCred, val, delegCred;
+ int32_t clientC, serverC;
+ struct client *c = clients[i];
+
+ if (c->target_name == NULL)
+ continue;
+
+ printf("%s connects to self using %s\n",
+ c->moniker, c->target_name);
+
+ val = acquire_cred(c, user, password, 1, &hCred);
+ if (val != GSMERR_OK)
+ errx(1, "failed to acquire_cred: %d", (int)val);
+
+ val = build_context(c, c,
+ GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
+ GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
+ GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
+ hCred, &clientC, &serverC, &delegCred);
+ if (val == GSMERR_OK) {
+ test_token(c, clientC, c, serverC, wrap_ext);
+ toast_resource(c, clientC);
+ toast_resource(c, serverC);
+ if (delegCred)
+ toast_resource(c, delegCred);
+ } else {
+ warnx("build_context failed: %d", (int)val);
+ }
+ /*
+ *
+ */
+
+ val = build_context(c, c,
+ GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG,
+ hCred, &clientC, &serverC, &delegCred);
+ if (val == GSMERR_OK) {
+ test_token(c, clientC, c, serverC, wrap_ext);
+ toast_resource(c, clientC);
+ toast_resource(c, serverC);
+ if (delegCred)
+ toast_resource(c, delegCred);
+ } else {
+ warnx("build_context failed: %d", (int)val);
+ }
+
+ toast_resource(c, hCred);
+ }
+ /*
+ * Build contexts though all entries in each lists, including the
+ * step from the last entry to the first, ie treat the list as a
+ * circle.
+ *
+ * Only follow the delegated credential, but test "all"
+ * flags. (XXX only do deleg|mutual right now.
+ */
+
+ printf("\"All\" permutation tests\n");
+
+ for (i = 0; i < num_list; i++) {
+ int32_t hCred, val, delegCred = 0;
+ int32_t clientC = 0, serverC = 0;
+ struct client *client, *server;
+
+ p = list[i];
+
+ client = get_client(p[0]);
+
+ val = acquire_cred(client, user, password, 1, &hCred);
+ if (val != GSMERR_OK)
+ errx(1, "failed to acquire_cred: %d", (int)val);
+
+ for (j = 1; j < num_clients + 1; j++) {
+ server = get_client(p[j % num_clients]);
+
+ if (server->target_name == NULL)
+ break;
+
+ for (k = 1; k < j; k++)
+ printf("\t");
+ printf("%s -> %s\n", client->moniker, server->moniker);
+
+ val = build_context(client, server,
+ GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
+ GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
+ GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
+ hCred, &clientC, &serverC, &delegCred);
+ if (val != GSMERR_OK) {
+ warnx("build_context failed: %d", (int)val);
+ break;
+ }
+
+ val = test_token(client, clientC, server, serverC, wrap_ext);
+ if (val)
+ break;
+
+ toast_resource(client, clientC);
+ toast_resource(server, serverC);
+ if (!delegCred) {
+ warnx("no delegated cred on %s", server->moniker);
+ break;
+ }
+ toast_resource(client, hCred);
+ hCred = delegCred;
+ client = server;
+ }
+ if (hCred)
+ toast_resource(client, hCred);
+ }
+
+ /*
+ * Close all connections to clients
+ */
+
+out:
+ printf("sending goodbye and waiting for log sockets\n");
+ for (i = 0; i < num_clients; i++) {
+ goodbye(clients[i]);
+ if (clients[i]->logsock) {
+#ifdef ENABLE_PTHREAD_SUPPORT
+ pthread_join(&clients[i]->thr, NULL);
+#else
+ waitpid(clients[i]->child, NULL, 0);
+#endif
+ }
+ }
+
+ printf("done\n");
+
+ return 0;
+}
diff --git a/third_party/heimdal/appl/gssmask/gssmask.c b/third_party/heimdal/appl/gssmask/gssmask.c
new file mode 100644
index 0000000..86a6713
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/gssmask.c
@@ -0,0 +1,1272 @@
+/*
+ * Copyright (c) 2006 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 "common.h"
+RCSID("$Id$");
+
+/*
+ *
+ */
+
+enum handle_type { handle_context, handle_cred };
+
+struct handle {
+ int32_t idx;
+ enum handle_type type;
+ void *ptr;
+ struct handle *next;
+};
+
+struct client {
+ krb5_storage *sock;
+ krb5_storage *logging;
+ char *moniker;
+ int32_t nHandle;
+ struct handle *handles;
+ struct sockaddr_storage sa;
+ socklen_t salen;
+ char servername[MAXHOSTNAMELEN];
+};
+
+FILE *logfile;
+static char *targetname;
+krb5_context context;
+
+/*
+ *
+ */
+
+static void
+logmessage(struct client *c, const char *file, unsigned int lineno,
+ int level, const char *fmt, ...)
+{
+ char *message;
+ va_list ap;
+ int32_t ackid;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&message, fmt, ap);
+ va_end(ap);
+ if (ret == -1)
+ errx(1, "out of memory");
+
+ if (logfile)
+ fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
+
+ if (c->logging) {
+ if (krb5_store_int32(c->logging, eLogInfo) != 0)
+ errx(1, "krb5_store_int32: log level");
+ if (krb5_store_string(c->logging, file) != 0)
+ errx(1, "krb5_store_string: filename");
+ if (krb5_store_int32(c->logging, lineno) != 0)
+ errx(1, "krb5_store_string: filename");
+ if (krb5_store_string(c->logging, message) != 0)
+ errx(1, "krb5_store_string: message");
+ if (krb5_ret_int32(c->logging, &ackid) != 0)
+ errx(1, "krb5_ret_int32: ackid");
+ }
+ free(message);
+}
+
+/*
+ *
+ */
+
+static int32_t
+add_handle(struct client *c, enum handle_type type, void *data)
+{
+ struct handle *h;
+
+ h = ecalloc(1, sizeof(*h));
+
+ h->idx = ++c->nHandle;
+ h->type = type;
+ h->ptr = data;
+ h->next = c->handles;
+ c->handles = h;
+
+ return h->idx;
+}
+
+static void
+del_handle(struct handle **h, int32_t idx)
+{
+ OM_uint32 min_stat;
+
+ if (idx == 0)
+ return;
+
+ while (*h) {
+ if ((*h)->idx == idx) {
+ struct handle *p = *h;
+ *h = (*h)->next;
+ switch(p->type) {
+ case handle_context: {
+ gss_ctx_id_t c = p->ptr;
+ gss_delete_sec_context(&min_stat, &c, NULL);
+ break; }
+ case handle_cred: {
+ gss_cred_id_t c = p->ptr;
+ gss_release_cred(&min_stat, &c);
+ break; }
+ }
+ free(p);
+ return;
+ }
+ h = &((*h)->next);
+ }
+ errx(1, "tried to delete an unexisting handle");
+}
+
+static void *
+find_handle(struct handle *h, int32_t idx, enum handle_type type)
+{
+ if (idx == 0)
+ return NULL;
+
+ while (h) {
+ if (h->idx == idx) {
+ if (type == h->type)
+ return h->ptr;
+ errx(1, "monger switched type on handle!");
+ }
+ h = h->next;
+ }
+ return NULL;
+}
+
+
+static int32_t
+convert_gss_to_gsm(OM_uint32 maj_stat)
+{
+ switch(maj_stat) {
+ case 0:
+ return GSMERR_OK;
+ case GSS_S_CONTINUE_NEEDED:
+ return GSMERR_CONTINUE_NEEDED;
+ case GSS_S_DEFECTIVE_TOKEN:
+ return GSMERR_INVALID_TOKEN;
+ case GSS_S_BAD_MIC:
+ return GSMERR_AP_MODIFIED;
+ default:
+ return GSMERR_ERROR;
+ }
+}
+
+static int32_t
+convert_krb5_to_gsm(krb5_error_code ret)
+{
+ switch(ret) {
+ case 0:
+ return GSMERR_OK;
+ default:
+ return GSMERR_ERROR;
+ }
+}
+
+/*
+ *
+ */
+
+static int32_t
+acquire_cred(struct client *c,
+ krb5_principal principal,
+ krb5_get_init_creds_opt *opt,
+ int32_t *handle)
+{
+ krb5_error_code ret;
+ krb5_creds cred;
+ krb5_ccache id;
+ gss_cred_id_t gcred;
+ OM_uint32 maj_stat, min_stat;
+
+ *handle = 0;
+
+ krb5_get_init_creds_opt_set_forwardable (opt, 1);
+ krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
+
+ memset(&cred, 0, sizeof(cred));
+
+ ret = krb5_get_init_creds_password (context,
+ &cred,
+ principal,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ opt);
+ if (ret) {
+ logmessage(c, __FILE__, __LINE__, 0,
+ "krb5_get_init_creds failed: %d", ret);
+ return convert_krb5_to_gsm(ret);
+ }
+
+ ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_cc_initialize");
+
+ ret = krb5_cc_initialize (context, id, cred.client);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_cc_initialize");
+
+ ret = krb5_cc_store_cred (context, id, &cred);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_cc_store_cred");
+
+ krb5_free_cred_contents (context, &cred);
+
+ maj_stat = gss_krb5_import_cred(&min_stat,
+ id,
+ NULL,
+ NULL,
+ &gcred);
+ krb5_cc_close(context, id);
+ if (maj_stat) {
+ logmessage(c, __FILE__, __LINE__, 0,
+ "krb5 import creds failed with: %d", maj_stat);
+ return convert_gss_to_gsm(maj_stat);
+ }
+
+ *handle = add_handle(c, handle_cred, gcred);
+
+ return 0;
+}
+
+
+/*
+ *
+ */
+
+#define HandleOP(h) \
+handle##h(enum gssMaggotOp op, struct client *c)
+
+/*
+ *
+ */
+
+static int
+HandleOP(GetVersionInfo)
+{
+ put32(c, GSSMAGGOTPROTOCOL);
+ errx(1, "GetVersionInfo");
+}
+
+static int
+HandleOP(GoodBye)
+{
+ struct handle *h = c->handles;
+ unsigned int i = 0;
+
+ while (h) {
+ h = h->next;
+ i++;
+ }
+
+ if (i)
+ logmessage(c, __FILE__, __LINE__, 0,
+ "Did not toast all resources: %d", i);
+ return 1;
+}
+
+static int
+HandleOP(InitContext)
+{
+ OM_uint32 maj_stat, min_stat, ret_flags;
+ int32_t hContext, hCred, flags;
+ krb5_data target_name, in_token;
+ int32_t new_context_id = 0, gsm_error = 0;
+ krb5_data out_token = { 0 , NULL };
+
+ gss_ctx_id_t ctx;
+ gss_cred_id_t creds;
+ gss_name_t gss_target_name;
+ gss_buffer_desc input_token;
+ gss_buffer_desc output_token = {0, 0};
+ gss_OID oid = GSS_C_NO_OID;
+ gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
+
+ ret32(c, hContext);
+ ret32(c, hCred);
+ ret32(c, flags);
+ retdata(c, target_name);
+ retdata(c, in_token);
+
+ logmessage(c, __FILE__, __LINE__, 0,
+ "targetname: <%.*s>", (int)target_name.length,
+ (char *)target_name.data);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ hContext = 0;
+ creds = find_handle(c->handles, hCred, handle_cred);
+ if (creds == NULL)
+ abort();
+
+ input_token.length = target_name.length;
+ input_token.value = target_name.data;
+
+ maj_stat = gss_import_name(&min_stat,
+ &input_token,
+ GSS_KRB5_NT_PRINCIPAL_NAME,
+ &gss_target_name);
+ if (GSS_ERROR(maj_stat)) {
+ logmessage(c, __FILE__, __LINE__, 0,
+ "import name creds failed with: %d", maj_stat);
+ gsm_error = convert_gss_to_gsm(maj_stat);
+ goto out;
+ }
+
+ /* oid from flags */
+
+ if (in_token.length) {
+ input_token.length = in_token.length;
+ input_token.value = in_token.data;
+ input_token_ptr = &input_token;
+ if (ctx == NULL)
+ krb5_errx(context, 1, "initcreds, context NULL, but not first req");
+ } else {
+ input_token.length = 0;
+ input_token.value = NULL;
+ if (ctx)
+ krb5_errx(context, 1, "initcreds, context not NULL, but first req");
+ }
+
+ if ((flags & GSS_C_DELEG_FLAG) != 0)
+ logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
+ if ((flags & GSS_C_DCE_STYLE) != 0)
+ logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
+
+ maj_stat = gss_init_sec_context(&min_stat,
+ creds,
+ &ctx,
+ gss_target_name,
+ oid,
+ flags & 0x7f,
+ 0,
+ NULL,
+ input_token_ptr,
+ NULL,
+ &output_token,
+ &ret_flags,
+ NULL);
+ if (GSS_ERROR(maj_stat)) {
+ if (hContext != 0)
+ del_handle(&c->handles, hContext);
+ new_context_id = 0;
+ logmessage(c, __FILE__, __LINE__, 0,
+ "gss_init_sec_context returns code: %d/%d",
+ maj_stat, min_stat);
+ } else {
+ if (input_token.length == 0)
+ new_context_id = add_handle(c, handle_context, ctx);
+ else
+ new_context_id = hContext;
+ }
+
+ gsm_error = convert_gss_to_gsm(maj_stat);
+
+ if (output_token.length) {
+ out_token.data = output_token.value;
+ out_token.length = output_token.length;
+ }
+
+out:
+ logmessage(c, __FILE__, __LINE__, 0,
+ "InitContext return code: %d", gsm_error);
+
+ put32(c, new_context_id);
+ put32(c, gsm_error);
+ putdata(c, out_token);
+
+ gss_release_name(&min_stat, &gss_target_name);
+ if (output_token.length)
+ gss_release_buffer(&min_stat, &output_token);
+ krb5_data_free(&in_token);
+ krb5_data_free(&target_name);
+
+ return 0;
+}
+
+static int
+HandleOP(AcceptContext)
+{
+ OM_uint32 maj_stat, min_stat, ret_flags;
+ int32_t hContext, deleg_hcred, flags;
+ krb5_data in_token;
+ int32_t new_context_id = 0, gsm_error = 0;
+ krb5_data out_token = { 0 , NULL };
+
+ gss_ctx_id_t ctx;
+ gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
+ gss_buffer_desc input_token, output_token;
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ retdata(c, in_token);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ hContext = 0;
+
+ if (in_token.length) {
+ input_token.length = in_token.length;
+ input_token.value = in_token.data;
+ } else {
+ input_token.length = 0;
+ input_token.value = NULL;
+ }
+
+ maj_stat = gss_accept_sec_context(&min_stat,
+ &ctx,
+ GSS_C_NO_CREDENTIAL,
+ &input_token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ NULL,
+ NULL,
+ &output_token,
+ &ret_flags,
+ NULL,
+ &deleg_cred);
+ if (GSS_ERROR(maj_stat)) {
+ if (hContext != 0)
+ del_handle(&c->handles, hContext);
+ logmessage(c, __FILE__, __LINE__, 0,
+ "gss_accept_sec_context returns code: %d/%d",
+ maj_stat, min_stat);
+ new_context_id = 0;
+ } else {
+ if (hContext == 0)
+ new_context_id = add_handle(c, handle_context, ctx);
+ else
+ new_context_id = hContext;
+ }
+ if (output_token.length) {
+ out_token.data = output_token.value;
+ out_token.length = output_token.length;
+ }
+ if ((ret_flags & GSS_C_DCE_STYLE) != 0)
+ logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
+ if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
+ deleg_hcred = add_handle(c, handle_cred, deleg_cred);
+ logmessage(c, __FILE__, __LINE__, 0,
+ "accept_context delegated handle: %d", deleg_hcred);
+ } else {
+ gss_release_cred(&min_stat, &deleg_cred);
+ deleg_hcred = 0;
+ }
+
+
+ gsm_error = convert_gss_to_gsm(maj_stat);
+
+ put32(c, new_context_id);
+ put32(c, gsm_error);
+ putdata(c, out_token);
+ put32(c, deleg_hcred);
+
+ if (output_token.length)
+ gss_release_buffer(&min_stat, &output_token);
+ krb5_data_free(&in_token);
+
+ return 0;
+}
+
+static int
+HandleOP(ToastResource)
+{
+ int32_t handle;
+
+ ret32(c, handle);
+ logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
+ del_handle(&c->handles, handle);
+ put32(c, GSMERR_OK);
+
+ return 0;
+}
+
+static int
+HandleOP(AcquireCreds)
+{
+ char *name, *password;
+ int32_t gsm_error, flags, handle = 0;
+ krb5_principal principal = NULL;
+ krb5_get_init_creds_opt *opt = NULL;
+ krb5_error_code ret;
+
+ retstring(c, name);
+ retstring(c, password);
+ ret32(c, flags);
+
+ logmessage(c, __FILE__, __LINE__, 0,
+ "username: %s password: %s", name, password);
+
+ ret = krb5_parse_name(context, name, &principal);
+ if (ret) {
+ gsm_error = convert_krb5_to_gsm(ret);
+ goto out;
+ }
+
+ ret = krb5_get_init_creds_opt_alloc (context, &opt);
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
+
+ krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
+
+ gsm_error = acquire_cred(c, principal, opt, &handle);
+
+out:
+ logmessage(c, __FILE__, __LINE__, 0,
+ "AcquireCreds handle: %d return code: %d", handle, gsm_error);
+
+ if (opt)
+ krb5_get_init_creds_opt_free (context, opt);
+ if (principal)
+ krb5_free_principal(context, principal);
+ free(name);
+ free(password);
+
+ put32(c, gsm_error);
+ put32(c, handle);
+
+ return 0;
+}
+
+static int
+HandleOP(Sign)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, seqno;
+ krb5_data token;
+ gss_ctx_id_t ctx;
+ gss_buffer_desc input_token, output_token;
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ ret32(c, seqno);
+ retdata(c, token);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "sign: reference to unknown context");
+
+ input_token.length = token.length;
+ input_token.value = token.data;
+
+ maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
+ &output_token);
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_get_mic failed");
+
+ krb5_data_free(&token);
+
+ token.data = output_token.value;
+ token.length = output_token.length;
+
+ put32(c, 0); /* XXX fix gsm_error */
+ putdata(c, token);
+
+ gss_release_buffer(&min_stat, &output_token);
+
+ return 0;
+}
+
+static int
+HandleOP(Verify)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, seqno;
+ krb5_data msg, mic;
+ gss_ctx_id_t ctx;
+ gss_buffer_desc msg_token, mic_token;
+ gss_qop_t qop;
+
+ ret32(c, hContext);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "verify: reference to unknown context");
+
+ ret32(c, flags);
+ ret32(c, seqno);
+ retdata(c, msg);
+
+ msg_token.length = msg.length;
+ msg_token.value = msg.data;
+
+ retdata(c, mic);
+
+ mic_token.length = mic.length;
+ mic_token.value = mic.data;
+
+ maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
+ &mic_token, &qop);
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_verify_mic failed");
+
+ krb5_data_free(&mic);
+ krb5_data_free(&msg);
+
+ put32(c, 0); /* XXX fix gsm_error */
+
+ return 0;
+}
+
+static int
+HandleOP(GetVersionAndCapabilities)
+{
+ int32_t cap = HAS_MONIKER;
+ char *name = NULL, *str = NULL;
+ int ret;
+
+ if (targetname)
+ cap |= ISSERVER; /* is server */
+
+#ifdef HAVE_UNAME
+ {
+ struct utsname ut;
+ if (uname(&ut) == 0) {
+ if (asprintf(&name, "%s-%s-%s",
+ ut.sysname, ut.version, ut.machine) == -1) {
+ errx(1, "out of memory");
+ }
+ }
+ }
+#endif
+
+ ret = asprintf(&str, "gssmask %s %s", PACKAGE_STRING,
+ name ? name : "unknown");
+ if (ret == -1)
+ errx(1, "out of memory");
+
+ put32(c, GSSMAGGOTPROTOCOL);
+ put32(c, cap);
+ putstring(c, str);
+ free(str);
+ free(name);
+
+ return 0;
+}
+
+static int
+HandleOP(GetTargetName)
+{
+ if (targetname)
+ putstring(c, targetname);
+ else
+ putstring(c, "");
+ return 0;
+}
+
+static int
+HandleOP(SetLoggingSocket)
+{
+ int32_t portnum;
+ krb5_socket_t sock;
+ int ret;
+
+ ret32(c, portnum);
+
+ logmessage(c, __FILE__, __LINE__, 0,
+ "logging port on peer is: %d", (int)portnum);
+
+ socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
+
+ sock = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
+ if (sock == rk_INVALID_SOCKET)
+ return 0;
+
+ ret = connect(sock, (struct sockaddr *)&c->sa, c->salen);
+ if (ret < 0) {
+ logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
+ strerror(errno));
+ rk_closesocket(sock);
+ return 0;
+ }
+
+ if (c->logging)
+ krb5_storage_free(c->logging);
+ c->logging = krb5_storage_from_socket(sock);
+ rk_closesocket(sock);
+
+ krb5_store_int32(c->logging, eLogSetMoniker);
+ store_string(c->logging, c->moniker);
+
+ logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
+
+ return 0;
+}
+
+
+static int
+HandleOP(ChangePassword)
+{
+ errx(1, "ChangePassword");
+}
+
+static int
+HandleOP(SetPasswordSelf)
+{
+ errx(1, "SetPasswordSelf");
+}
+
+static int
+HandleOP(Wrap)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, seqno;
+ krb5_data token;
+ gss_ctx_id_t ctx;
+ gss_buffer_desc input_token, output_token;
+ int conf_state;
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ ret32(c, seqno);
+ retdata(c, token);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "wrap: reference to unknown context");
+
+ input_token.length = token.length;
+ input_token.value = token.data;
+
+ maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
+ &conf_state, &output_token);
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_wrap failed");
+
+ krb5_data_free(&token);
+
+ token.data = output_token.value;
+ token.length = output_token.length;
+
+ put32(c, 0); /* XXX fix gsm_error */
+ putdata(c, token);
+
+ gss_release_buffer(&min_stat, &output_token);
+
+ return 0;
+}
+
+
+static int
+HandleOP(Unwrap)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, seqno;
+ krb5_data token;
+ gss_ctx_id_t ctx;
+ gss_buffer_desc input_token, output_token;
+ int conf_state;
+ gss_qop_t qop_state;
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ ret32(c, seqno);
+ retdata(c, token);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "unwrap: reference to unknown context");
+
+ input_token.length = token.length;
+ input_token.value = token.data;
+
+ maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
+ &output_token, &conf_state, &qop_state);
+
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
+
+ krb5_data_free(&token);
+ if (maj_stat == GSS_S_COMPLETE) {
+ token.data = output_token.value;
+ token.length = output_token.length;
+ } else {
+ token.data = NULL;
+ token.length = 0;
+ }
+ put32(c, 0); /* XXX fix gsm_error */
+ putdata(c, token);
+
+ if (maj_stat == GSS_S_COMPLETE)
+ gss_release_buffer(&min_stat, &output_token);
+
+ return 0;
+}
+
+static int
+HandleOP(Encrypt)
+{
+ return handleWrap(op, c);
+}
+
+static int
+HandleOP(Decrypt)
+{
+ return handleUnwrap(op, c);
+}
+
+static int
+HandleOP(ConnectLoggingService2)
+{
+ errx(1, "ConnectLoggingService2");
+}
+
+static int
+HandleOP(GetMoniker)
+{
+ putstring(c, c->moniker);
+ return 0;
+}
+
+static int
+HandleOP(CallExtension)
+{
+ errx(1, "CallExtension");
+}
+
+static int
+HandleOP(AcquirePKInitCreds)
+{
+ int32_t flags;
+ krb5_data pfxdata;
+ char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
+ int fd;
+
+ ret32(c, flags);
+ retdata(c, pfxdata);
+
+ fd = mkstemp(fn + 5);
+ if (fd < 0)
+ errx(1, "mkstemp");
+
+ net_write(fd, pfxdata.data, pfxdata.length);
+ krb5_data_free(&pfxdata);
+ close(fd);
+
+ put32(c, -1); /* hResource */
+ put32(c, GSMERR_NOT_SUPPORTED);
+ return 0;
+}
+
+static int
+HandleOP(WrapExt)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, bflags;
+ krb5_data token, header, trailer;
+ gss_ctx_id_t ctx;
+ unsigned char *p;
+ int conf_state, iov_len;
+ gss_iov_buffer_desc iov[6];
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ ret32(c, bflags);
+ retdata(c, header);
+ retdata(c, token);
+ retdata(c, trailer);
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "wrap: reference to unknown context");
+
+ memset(&iov, 0, sizeof(iov));
+
+ iov_len = sizeof(iov)/sizeof(iov[0]);
+
+ if (bflags & WRAP_EXP_ONLY_HEADER)
+ iov_len -= 2; /* skip trailer and padding, aka dce-style */
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
+ if (header.length != 0) {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[1].buffer.length = header.length;
+ iov[1].buffer.value = header.data;
+ } else {
+ iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ }
+ iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[2].buffer.length = token.length;
+ iov[2].buffer.value = token.data;
+ if (trailer.length != 0) {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[3].buffer.length = trailer.length;
+ iov[3].buffer.value = trailer.data;
+ } else {
+ iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ }
+ iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
+ iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
+
+ maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
+ iov, iov_len);
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_wrap_iov_length failed");
+
+ maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
+ iov, iov_len);
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_wrap_iov failed");
+
+ krb5_data_free(&token);
+
+ token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
+ token.data = malloc(token.length);
+
+ p = token.data;
+ memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
+ p += iov[0].buffer.length;
+ memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
+ p += iov[2].buffer.length;
+ memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
+ p += iov[4].buffer.length;
+ memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
+#if 0 /* Would be needed to keep going, but presently unused */
+ p += iov[5].buffer.length;
+#endif
+
+ gss_release_iov_buffer(NULL, iov, iov_len);
+
+ put32(c, 0); /* XXX fix gsm_error */
+ putdata(c, token);
+
+ free(token.data);
+
+ return 0;
+}
+
+
+static int
+HandleOP(UnwrapExt)
+{
+ OM_uint32 maj_stat, min_stat;
+ int32_t hContext, flags, bflags;
+ krb5_data token, header, trailer;
+ gss_ctx_id_t ctx;
+ gss_iov_buffer_desc iov[3];
+ int conf_state, iov_len;
+ gss_qop_t qop_state;
+
+ ret32(c, hContext);
+ ret32(c, flags);
+ ret32(c, bflags);
+ retdata(c, header);
+ retdata(c, token);
+ retdata(c, trailer);
+
+ iov_len = sizeof(iov)/sizeof(iov[0]);
+
+ if (bflags & WRAP_EXP_ONLY_HEADER)
+ iov_len -= 1; /* skip trailer and padding, aka dce-style */
+
+ ctx = find_handle(c->handles, hContext, handle_context);
+ if (ctx == NULL)
+ errx(1, "unwrap: reference to unknown context");
+
+ if (header.length != 0) {
+ iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[0].buffer.length = header.length;
+ iov[0].buffer.value = header.data;
+ } else {
+ iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ }
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.length = token.length;
+ iov[1].buffer.value = token.data;
+
+ if (trailer.length != 0) {
+ iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+ iov[2].buffer.length = trailer.length;
+ iov[2].buffer.value = trailer.data;
+ } else {
+ iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+ }
+
+ maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
+ iov, iov_len);
+
+ if (maj_stat != GSS_S_COMPLETE)
+ errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
+
+ if (maj_stat == GSS_S_COMPLETE) {
+ token.data = iov[1].buffer.value;
+ token.length = iov[1].buffer.length;
+ } else {
+ token.data = NULL;
+ token.length = 0;
+ }
+ put32(c, 0); /* XXX fix gsm_error */
+ putdata(c, token);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+struct handler {
+ enum gssMaggotOp op;
+ const char *name;
+ int (*func)(enum gssMaggotOp, struct client *);
+};
+
+#define S(a) { e##a, #a, handle##a }
+
+struct handler handlers[] = {
+ S(GetVersionInfo),
+ S(GoodBye),
+ S(InitContext),
+ S(AcceptContext),
+ S(ToastResource),
+ S(AcquireCreds),
+ S(Encrypt),
+ S(Decrypt),
+ S(Sign),
+ S(Verify),
+ S(GetVersionAndCapabilities),
+ S(GetTargetName),
+ S(SetLoggingSocket),
+ S(ChangePassword),
+ S(SetPasswordSelf),
+ S(Wrap),
+ S(Unwrap),
+ S(ConnectLoggingService2),
+ S(GetMoniker),
+ S(CallExtension),
+ S(AcquirePKInitCreds),
+ S(WrapExt),
+ S(UnwrapExt),
+};
+
+#undef S
+
+/*
+ *
+ */
+
+static struct handler *
+find_op(int32_t op)
+{
+ int i;
+
+ for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
+ if (handlers[i].op == op)
+ return &handlers[i];
+ return NULL;
+}
+
+static struct client *
+create_client(krb5_socket_t sock, int port, const char *moniker)
+{
+ struct client *c;
+ int ret;
+
+ c = ecalloc(1, sizeof(*c));
+
+ if (moniker) {
+ c->moniker = estrdup(moniker);
+ } else {
+ char hostname[MAXHOSTNAMELEN];
+ gethostname(hostname, sizeof(hostname));
+ ret = asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
+ if (ret == -1)
+ c->moniker = NULL;
+ }
+
+ if (!c->moniker)
+ errx(1, "out of memory");
+
+ {
+ c->salen = sizeof(c->sa);
+ getpeername(sock, (struct sockaddr *)&c->sa, &c->salen);
+
+ getnameinfo((struct sockaddr *)&c->sa, c->salen,
+ c->servername, sizeof(c->servername),
+ NULL, 0, NI_NUMERICHOST);
+ }
+
+ c->sock = krb5_storage_from_socket(sock);
+ if (c->sock == NULL)
+ errx(1, "krb5_storage_from_socket");
+
+ rk_closesocket(sock);
+
+ return c;
+}
+
+static void
+free_client(struct client *c)
+{
+ while(c->handles)
+ del_handle(&c->handles, c->handles->idx);
+
+ free(c->moniker);
+ krb5_storage_free(c->sock);
+ if (c->logging)
+ krb5_storage_free(c->logging);
+ free(c);
+}
+
+
+static void *
+handleServer(void *ptr)
+{
+ struct handler *handler;
+ struct client *c;
+ int32_t op;
+
+ c = (struct client *)ptr;
+
+
+ while(1) {
+ ret32(c, op);
+
+ handler = find_op(op);
+ if (handler == NULL) {
+ logmessage(c, __FILE__, __LINE__, 0,
+ "op %d not supported", (int)op);
+ exit(1);
+ }
+
+ logmessage(c, __FILE__, __LINE__, 0,
+ "---> Got op %s from server %s",
+ handler->name, c->servername);
+
+ if ((handler->func)(handler->op, c))
+ break;
+ }
+
+ return NULL;
+}
+
+
+static char *port_str;
+static int version_flag;
+static int help_flag;
+static char *logfile_str;
+static char *moniker_str;
+
+static int port = 4711;
+
+struct getargs args[] = {
+ { "spn", 0, arg_string, &targetname, "This host's SPN",
+ "service/host@REALM" },
+ { "port", 'p', arg_string, &port_str, "Use this port",
+ "number-of-service" },
+ { "logfile", 0, arg_string, &logfile_str, "logfile",
+ "number-of-service" },
+ { "moniker", 0, arg_string, &moniker_str, "nickname",
+ "name" },
+ { "version", 0, arg_flag, &version_flag, "Print version",
+ NULL },
+ { "help", 0, arg_flag, &help_flag, NULL,
+ NULL }
+};
+
+static void
+usage(int ret)
+{
+ arg_printusage (args,
+ sizeof(args) / sizeof(args[0]),
+ NULL,
+ "");
+ exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+ krb5_error_code ret;
+
+ setprogname (argv[0]);
+
+ if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
+ usage (1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ print_version (NULL);
+ return 0;
+ }
+
+ if (optidx != argc)
+ usage (1);
+
+ if (port_str) {
+ char *ptr;
+
+ port = strtol (port_str, &ptr, 10);
+ if (port == 0 && ptr == port_str)
+ errx (1, "Bad port `%s'", port_str);
+ }
+
+ ret = krb5_init_context(&context);
+ if (ret)
+ errx(1, "Error initializing kerberos: %d", ret);
+
+ {
+ const char *lf = logfile_str;
+ if (lf == NULL)
+ lf = "/dev/tty";
+
+ logfile = fopen(lf, "w");
+ if (logfile == NULL)
+ err(1, "error opening %s", lf);
+ }
+
+ mini_inetd(htons(port), NULL);
+ fprintf(logfile, "connected\n");
+
+ {
+ struct client *c;
+
+ c = create_client(0, port, moniker_str);
+ /* close(0); */
+
+ handleServer(c);
+
+ free_client(c);
+ }
+
+ krb5_free_context(context);
+
+ return 0;
+}
diff --git a/third_party/heimdal/appl/gssmask/protocol.h b/third_party/heimdal/appl/gssmask/protocol.h
new file mode 100644
index 0000000..1e1f141
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/protocol.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2006 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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$
+ */
+
+/* missing from tests:
+ * - export context
+ * - import context
+ */
+
+/*
+ * wire encodings:
+ * int16: number, 2 bytes, in network order
+ * int32: number, 4 bytes, in network order
+ * length-encoded: [int32 length, data of length bytes]
+ * string: [int32 length, string of length + 1 bytes, includes trailing '\0' ]
+ */
+
+enum gssMaggotErrorCodes {
+ GSMERR_OK = 0,
+ GSMERR_ERROR,
+ GSMERR_CONTINUE_NEEDED,
+ GSMERR_INVALID_TOKEN,
+ GSMERR_AP_MODIFIED,
+ GSMERR_TEST_ISSUE,
+ GSMERR_NOT_SUPPORTED
+};
+
+/*
+ * input:
+ * int32: message OP (enum gssMaggotProtocol)
+ * ...
+ *
+ * return: -- on error
+ * int32: not support (GSMERR_NOT_SUPPORTED)
+ *
+ * return: -- on existing message OP
+ * int32: support (GSMERR_OK) -- only sent for extensions
+ * ...
+ */
+
+#define GSSMAGGOTPROTOCOL 14
+
+enum gssMaggotOp {
+ eGetVersionInfo = 0,
+ /*
+ * input:
+ * none
+ * return:
+ * int32: last version handled
+ */
+ eGoodBye,
+ /*
+ * input:
+ * none
+ * return:
+ * close socket
+ */
+ eInitContext,
+ /*
+ * input:
+ * int32: hContext
+ * int32: hCred
+ * int32: Flags
+ * the lowest 0x7f flags maps directly to GSS-API flags
+ * DELEGATE 0x001
+ * MUTUAL_AUTH 0x002
+ * REPLAY_DETECT 0x004
+ * SEQUENCE_DETECT 0x008
+ * CONFIDENTIALITY 0x010
+ * INTEGRITY 0x020
+ * ANONYMOUS 0x040
+ *
+ * FIRST_CALL 0x080
+ *
+ * NTLM 0x100
+ * SPNEGO 0x200
+ * length-encoded: targetname
+ * length-encoded: token
+ * return:
+ * int32: hNewContextId
+ * int32: gssapi status val
+ * length-encoded: output token
+ */
+ eAcceptContext,
+ /*
+ * input:
+ * int32: hContext
+ * int32: Flags -- unused ?
+ * flags are same as flags for eInitContext
+ * length-encoded: token
+ * return:
+ * int32: hNewContextId
+ * int32: gssapi status val
+ * length-encoded: output token
+ * int32: delegation cred id
+ */
+ eToastResource,
+ /*
+ * input:
+ * int32: hResource
+ * return:
+ * int32: gsm status val
+ */
+ eAcquireCreds,
+ /*
+ * input:
+ * string: principal name
+ * string: password
+ * int32: flags
+ * FORWARDABLE 0x001
+ * DEFAULT_CREDS 0x002
+ *
+ * NTLM 0x100
+ * SPNEGO 0x200
+ * return:
+ * int32: gsm status val
+ * int32: hCred
+ */
+ eEncrypt,
+ /*
+ * input:
+ * int32: hContext
+ * int32: flags
+ * int32: seqno -- unused
+ * length-encode: plaintext
+ * return:
+ * int32: gsm status val
+ * length-encode: ciphertext
+ */
+ eDecrypt,
+ /*
+ * input:
+ * int32: hContext
+ * int32: flags
+ * int32: seqno -- unused
+ * length-encode: ciphertext
+ * return:
+ * int32: gsm status val
+ * length-encode: plaintext
+ */
+ eSign,
+ /* message same as eEncrypt */
+ eVerify,
+ /*
+ * input:
+ * int32: hContext
+ * int32: flags
+ * int32: seqno -- unused
+ * length-encode: message
+ * length-encode: signature
+ * return:
+ * int32: gsm status val
+ */
+ eGetVersionAndCapabilities,
+ /*
+ * return:
+ * int32: protocol version
+ * int32: capability flags */
+#define ISSERVER 0x01
+#define ISKDC 0x02
+#define MS_KERBEROS 0x04
+#define LOGSERVER 0x08
+#define HAS_MONIKER 0x10
+ /* string: version string
+ */
+ eGetTargetName,
+ /*
+ * return:
+ * string: target principal name
+ */
+ eSetLoggingSocket,
+ /*
+ * input:
+ * int32: hostPort
+ * return to the port on the host:
+ * int32: opcode - for example eLogSetMoniker
+ */
+ eChangePassword,
+ /* here ended version 7 of the protocol */
+ /*
+ * input:
+ * string: principal name
+ * string: old password
+ * string: new password
+ * return:
+ * int32: gsm status val
+ */
+ eSetPasswordSelf,
+ /* same as eChangePassword */
+ eWrap,
+ /* message same as eEncrypt */
+ eUnwrap,
+ /* message same as eDecrypt */
+ eConnectLoggingService2,
+ /*
+ * return1:
+ * int16: log port number
+ * int32: master log prototocol version (0)
+ *
+ * wait for master to connect on the master log socket
+ *
+ * return2:
+ * int32: gsm connection status
+ * int32: maggot log prototocol version (2)
+ */
+ eGetMoniker,
+ /*
+ * return:
+ * string: moniker (Nickname the master can refer to maggot)
+ */
+ eCallExtension,
+ /*
+ * input:
+ * string: extension name
+ * int32: message id
+ * return:
+ * int32: gsm status val
+ */
+ eAcquirePKInitCreds,
+ /*
+ * input:
+ * int32: flags
+ * length-encode: certificate (pkcs12 data)
+ * return:
+ * int32: hResource
+ * int32: gsm status val (GSMERR_NOT_SUPPORTED)
+ */
+ /* here ended version 7 of the protocol */
+ eWrapExt,
+ /*
+ * input:
+ * int32: hContext
+ * int32: flags
+ * int32: bflags
+ * length-encode: protocol header
+ * length-encode: plaintext
+ * length-encode: protocol trailer
+ * return:
+ * int32: gsm status val
+ * length-encode: ciphertext
+ */
+ eUnwrapExt,
+ /*
+ * input:
+ * int32: hContext
+ * int32: flags
+ * int32: bflags
+ * length-encode: protocol header
+ * length-encode: ciphertext
+ * length-encode: protocol trailer
+ * return:
+ * int32: gsm status val
+ * length-encode: plaintext
+ */
+ /* here ended version 8 of the protocol */
+
+ eLastProtocolMessage
+};
+
+/* bflags */
+#define WRAP_EXP_ONLY_HEADER 1
+
+enum gssMaggotLogOp{
+ eLogInfo = 0,
+ /*
+ string: File
+ int32: Line
+ string: message
+ reply:
+ int32: ackid
+ */
+ eLogFailure,
+ /*
+ string: File
+ int32: Line
+ string: message
+ reply:
+ int32: ackid
+ */
+ eLogSetMoniker
+ /*
+ string: moniker
+ */
+};