summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/appl
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/appl')
-rw-r--r--third_party/heimdal/appl/Makefile.am23
-rw-r--r--third_party/heimdal/appl/NTMakefile35
-rw-r--r--third_party/heimdal/appl/afsutil/ChangeLog125
-rw-r--r--third_party/heimdal/appl/afsutil/Makefile.am19
-rw-r--r--third_party/heimdal/appl/afsutil/NTMakefile35
-rw-r--r--third_party/heimdal/appl/afsutil/afslog.1147
-rw-r--r--third_party/heimdal/appl/afsutil/afslog.c303
-rw-r--r--third_party/heimdal/appl/afsutil/pagsh.194
-rw-r--r--third_party/heimdal/appl/afsutil/pagsh.c213
-rw-r--r--third_party/heimdal/appl/dbutils/Makefile.am13
-rw-r--r--third_party/heimdal/appl/dbutils/NTMakefile35
-rw-r--r--third_party/heimdal/appl/dbutils/bsearch.1115
-rw-r--r--third_party/heimdal/appl/dbutils/bsearch.c205
-rw-r--r--third_party/heimdal/appl/dceutils/ChangeLog39
-rw-r--r--third_party/heimdal/appl/dceutils/Makefile.am37
-rw-r--r--third_party/heimdal/appl/dceutils/NTMakefile35
-rw-r--r--third_party/heimdal/appl/dceutils/README.dcedfs59
-rw-r--r--third_party/heimdal/appl/dceutils/README.original335
-rw-r--r--third_party/heimdal/appl/dceutils/dfspag.exp3
-rw-r--r--third_party/heimdal/appl/dceutils/dpagaix.c23
-rw-r--r--third_party/heimdal/appl/dceutils/k5dce.h165
-rw-r--r--third_party/heimdal/appl/dceutils/k5dcecon.c792
-rw-r--r--third_party/heimdal/appl/dceutils/testpag.c150
-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.c1268
-rw-r--r--third_party/heimdal/appl/gssmask/protocol.h317
-rw-r--r--third_party/heimdal/appl/kf/Makefile.am20
-rw-r--r--third_party/heimdal/appl/kf/NTMakefile35
-rw-r--r--third_party/heimdal/appl/kf/kf.1112
-rw-r--r--third_party/heimdal/appl/kf/kf.c349
-rw-r--r--third_party/heimdal/appl/kf/kf_locl.h81
-rw-r--r--third_party/heimdal/appl/kf/kfd.885
-rw-r--r--third_party/heimdal/appl/kf/kfd.c311
-rw-r--r--third_party/heimdal/appl/otp/ChangeLog58
-rw-r--r--third_party/heimdal/appl/otp/Makefile.am15
-rw-r--r--third_party/heimdal/appl/otp/NTMakefile35
-rw-r--r--third_party/heimdal/appl/otp/otp.190
-rw-r--r--third_party/heimdal/appl/otp/otp.c371
-rw-r--r--third_party/heimdal/appl/otp/otp_locl.h56
-rw-r--r--third_party/heimdal/appl/otp/otpprint.182
-rw-r--r--third_party/heimdal/appl/otp/otpprint.c136
-rw-r--r--third_party/heimdal/appl/test/Makefile.am46
-rw-r--r--third_party/heimdal/appl/test/NTMakefile35
-rw-r--r--third_party/heimdal/appl/test/common.c180
-rw-r--r--third_party/heimdal/appl/test/gss_common.c154
-rw-r--r--third_party/heimdal/appl/test/gss_common.h49
-rw-r--r--third_party/heimdal/appl/test/gssapi_client.c307
-rw-r--r--third_party/heimdal/appl/test/gssapi_server.c401
-rw-r--r--third_party/heimdal/appl/test/http_client.c513
-rw-r--r--third_party/heimdal/appl/test/jgssapi_server.java148
-rw-r--r--third_party/heimdal/appl/test/nt_gss_client.c167
-rw-r--r--third_party/heimdal/appl/test/nt_gss_common.c135
-rw-r--r--third_party/heimdal/appl/test/nt_gss_common.h45
-rw-r--r--third_party/heimdal/appl/test/nt_gss_server.c244
-rw-r--r--third_party/heimdal/appl/test/tcp_client.c132
-rw-r--r--third_party/heimdal/appl/test/tcp_server.c205
-rw-r--r--third_party/heimdal/appl/test/test_locl.h89
-rw-r--r--third_party/heimdal/appl/test/uu_client.c192
-rw-r--r--third_party/heimdal/appl/test/uu_server.c195
63 files changed, 10879 insertions, 0 deletions
diff --git a/third_party/heimdal/appl/Makefile.am b/third_party/heimdal/appl/Makefile.am
new file mode 100644
index 0000000..ec896ff
--- /dev/null
+++ b/third_party/heimdal/appl/Makefile.am
@@ -0,0 +1,23 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+if OTP
+dir_otp = otp
+endif
+if DCE
+dir_dce = dceutils
+endif
+if !NO_AFS
+dir_afsutil = afsutil
+endif
+SUBDIRS = \
+ $(dir_afsutil) \
+ dbutils \
+ $(dir_otp) \
+ gssmask \
+ test \
+ kf \
+ $(dir_dce)
+
+EXTRA_DIST = NTMakefile
diff --git a/third_party/heimdal/appl/NTMakefile b/third_party/heimdal/appl/NTMakefile
new file mode 100644
index 0000000..6bae479
--- /dev/null
+++ b/third_party/heimdal/appl/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
+
+!include ../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/afsutil/ChangeLog b/third_party/heimdal/appl/afsutil/ChangeLog
new file mode 100644
index 0000000..9825c55
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/ChangeLog
@@ -0,0 +1,125 @@
+2007-04-11 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * pagsh.1,afslog.1: - options must be lexicographically ordered;
+ again, options without arguments must be placed before options
+ with arguments. - manual page cross references are done using
+ the macro `.Xr', not the macro `.Nm' (used for command names
+ instead).
+
+ From Igor Sobrado.
+
+2006-10-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: Add man_MANS to EXTRA_DIST
+
+2006-01-03 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * afslog.1: Document options to allow select principal or
+ credential cache when doing afslog.
+
+ * afslog.c: Add options to allow select principal or credential
+ cache when doing afslog.
+
+2005-02-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: man_MANS += pagsh.1
+
+ * pagsh.c: add --cache-type that allows the user to control the
+ resulting credential cache type, inherit the type from the
+ invoking process
+
+ * pagsh.1: manpage for pagsh
+
+2004-09-03 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * afslog.c: use negative string help string for arg_negative_flag
+ Pointed out by Harald Barth
+
+2004-07-27 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * pagsh.c: use setprogname, if we stripped off -c, try use the
+ fallback code
+
+2003-10-14 Johan Danielsson <joda@pdc.kth.se>
+
+ * pagsh.c: mkstemp formats must end in exactly six X's
+
+2003-07-15 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * afslog.c (do_afslog): is cell is unset, set it "<default cell>"
+ for error printing
+
+ * pagsh.c: unconditionally set KRBTKFILE
+
+2003-04-23 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * afslog.c (log_func): drop the error number
+
+2003-04-14 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * afslog.c: set kafs log function if verbose is turned on
+
+2003-03-18 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am (LDADD): use LIB_kafs
+
+ * afslog.1: --no-v4, --no-v5
+
+ * Makefile.am: always build afsutils now
+
+ * afslog.c: make build without KRB4
+
+2002-11-26 Johan Danielsson <joda@pdc.kth.se>
+
+ * afslog.c: remove plural form in help string
+
+ * Makefile.am: add afslog manpage
+
+ * afslog.1: manpage
+
+ * afslog.c: try more files when trying to expand a cell name
+
+ * afslog.c: create a list of cells to get tokens for, before
+ actually doing anything, and try to get tokens via krb4 if krb5
+ fails, and give it a chance to work with krb4-only; also some bug
+ fixes, partially from Tomas Olsson.
+
+2002-08-23 Assar Westerlund <assar@kth.se>
+
+ * pagsh.c: make it handle --version/--help
+
+2001-05-17 Assar Westerlund <assar@sics.se>
+
+ * afslog.c (main): call free_getarg_strings
+
+2000-12-31 Assar Westerlund <assar@sics.se>
+
+ * afslog.c (main): handle krb5_init_context failure consistently
+
+2000-12-25 Assar Westerlund <assar@sics.se>
+
+ * afslog.c: clarify usage strings
+
+1999-08-04 Assar Westerlund <assar@sics.se>
+
+ * pagsh.c (main): use mkstemp to generate temporary file names.
+ From Miroslav Ruda <ruda@ics.muni.cz>
+
+1999-07-04 Assar Westerlund <assar@sics.se>
+
+ * afslog.c (expand_cell_name): terminate on #. From Miroslav Ruda
+ <ruda@ics.muni.cz>
+
+1999-06-27 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (bin_PROGRAMS): only include pagsh if KRB4
+
+1999-06-26 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: add pagsh
+
+ * pagsh.c: new file. contributed by Miroslav Ruda <ruda@ics.muni.cz>
+
+Sat Mar 27 12:49:43 1999 Johan Danielsson <joda@blubb.pdc.kth.se>
+
+ * afslog.c: cleanup option parsing
diff --git a/third_party/heimdal/appl/afsutil/Makefile.am b/third_party/heimdal/appl/afsutil/Makefile.am
new file mode 100644
index 0000000..705bdf1
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/Makefile.am
@@ -0,0 +1,19 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+bin_PROGRAMS = afslog pagsh
+
+afslog_SOURCES = afslog.c
+
+pagsh_SOURCES = pagsh.c
+
+man_MANS = afslog.1 pagsh.1
+
+LDADD = $(LIB_kafs) \
+ $(top_builddir)/lib/krb5/libkrb5.la \
+ $(top_builddir)/lib/asn1/libasn1.la \
+ $(LIB_hcrypto) \
+ $(LIB_roken)
+
+EXTRA_DIST = NTMakefile $(man_MANS)
diff --git a/third_party/heimdal/appl/afsutil/NTMakefile b/third_party/heimdal/appl/afsutil/NTMakefile
new file mode 100644
index 0000000..f1f696c
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/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\afsutil
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/afsutil/afslog.1 b/third_party/heimdal/appl/afsutil/afslog.1
new file mode 100644
index 0000000..779d9cd
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/afslog.1
@@ -0,0 +1,147 @@
+.\" Copyright (c) 2002 - 2007 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd November 26, 2002
+.Dt AFSLOG 1
+.Os HEIMDAL
+.Sh NAME
+.Nm afslog
+.Nd obtain AFS tokens
+.Sh SYNOPSIS
+.Nm
+.Op Fl h | Fl Fl help
+.Op Fl Fl no-v5
+.Op Fl u | Fl Fl unlog
+.Op Fl v | Fl Fl verbose
+.Op Fl Fl version
+.Oo Fl c Ar cell \*(Ba Xo
+.Fl Fl cell= Ns Ar cell
+.Xc
+.Oc
+.Oo Fl k Ar realm \*(Ba Xo
+.Fl Fl realm= Ns Ar realm
+.Xc
+.Oc
+.Oo Fl P Ar principal \*(Ba Xo
+.Fl Fl principal= Ns Ar principal
+.Xc
+.Oc
+.Bk -words
+.Oo Fl p Ar path \*(Ba Xo
+.Fl Fl file= Ns Ar path
+.Xc
+.Oc
+.Ek
+.Op Ar cell | path ...
+.Sh DESCRIPTION
+.Nm
+obtains AFS tokens for a number of cells. What cells to get tokens for
+can either be specified as an explicit list, as file paths to get
+tokens for, or be left unspecified, in which case
+.Nm
+will use whatever magic
+.Xr krb_afslog 3
+decides upon.
+.Pp
+Supported options:
+.Bl -tag -width Ds
+.It Fl Fl no-v5
+This makes
+.Nm
+not try using Kerberos 5.
+.It Xo
+.Fl P Ar principal ,
+.Fl Fl principal Ar principal
+.Xc
+select what Kerberos 5 principal to use.
+.It Fl Fl cache Ar cache
+select what Kerberos 5 credential cache to use.
+.Fl Fl principal
+overrides this option.
+.It Xo
+.Fl u ,
+.Fl Fl unlog
+.Xc
+Destroy tokens instead of obtaining new. If this is specified, all
+other options are ignored (except for
+.Fl Fl help
+and
+.Fl Fl version ) .
+.It Xo
+.Fl v ,
+.Fl Fl verbose
+.Xc
+Adds more verbosity for what is actually going on.
+.It Xo
+.Fl c Ar cell,
+.Fl Fl cell= Ns Ar cell
+.Xc
+This specified one or more cell names to get tokens for.
+.It Xo
+.Fl k Ar realm ,
+.Fl Fl realm= Ns Ar realm
+.Xc
+This is the Kerberos realm the AFS servers live in, this should
+normally not be specified.
+.It Xo
+.Fl p Ar path ,
+.Fl Fl file= Ns Ar path
+.Xc
+This specified one or more file paths for which tokens should be
+obtained.
+.El
+.Pp
+Instead of using
+.Fl c
+and
+.Fl p ,
+you may also pass a list of cells and file paths after any other
+options. These arguments are considered files if they are either
+the strings
+.Do . Dc
+or
+.Dq ..
+or they contain a slash, or if there exists a file by that name.
+.Sh EXAMPLES
+Assuming that there is no file called
+.Dq openafs.org
+in the current directory, and that
+.Pa /afs/openafs.org
+points to that cell, the follwing should be identical:
+.Bd -literal -offset indent
+$ afslog -c openafs.org
+$ afslog openafs.org
+$ afslog /afs/openafs.org/some/file
+.Ed
+.Sh SEE ALSO
+.Xr krb_afslog 3
diff --git a/third_party/heimdal/appl/afsutil/afslog.c b/third_party/heimdal/appl/afsutil/afslog.c
new file mode 100644
index 0000000..05078ee
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/afslog.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1997-2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id$");
+#endif
+#include <ctype.h>
+#ifdef KRB5
+#include <krb5.h>
+#endif
+#include <kafs.h>
+#include <roken.h>
+#include <getarg.h>
+#include <err.h>
+
+static int help_flag;
+static int version_flag;
+static getarg_strings cells;
+static char *realm;
+static getarg_strings files;
+static int unlog_flag;
+static int verbose;
+#ifdef KRB5
+static char *client_string;
+static char *cache_string;
+static int use_krb5 = 1;
+#endif
+
+struct getargs args[] = {
+ { "cell", 'c', arg_strings, &cells, "cells to get tokens for", "cell" },
+ { "file", 'p', arg_strings, &files, "files to get tokens for", "path" },
+ { "realm", 'k', arg_string, &realm, "realm for afs cell", "realm" },
+ { "unlog", 'u', arg_flag, &unlog_flag, "remove tokens", NULL },
+#ifdef KRB5
+ { "principal",'P',arg_string,&client_string,"principal to use","principal"},
+ { "cache", 0, arg_string, &cache_string, "ccache to use", "cache"},
+ { "v5", 0, arg_negative_flag, &use_krb5, "don't use Kerberos 5",
+ NULL },
+#endif
+ { "verbose",'v', arg_flag, &verbose, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+#ifdef KRB5
+krb5_context context;
+krb5_ccache id;
+#endif
+
+static const char *
+expand_one_file(FILE *f, const char *cell)
+{
+ static char buf[1024];
+ char *p;
+
+ while (fgets (buf, sizeof(buf), f) != NULL) {
+ if(buf[0] == '>') {
+ for(p = buf; *p && !isspace((unsigned char)*p) && *p != '#'; p++)
+ ;
+ *p = '\0';
+ if(strncmp(buf + 1, cell, strlen(cell)) == 0)
+ return buf + 1;
+ }
+ buf[0] = '\0';
+ }
+ return NULL;
+}
+
+static const char *
+expand_cell_name(const char *cell)
+{
+ FILE *f;
+ const char *c;
+ const char **fn, *fns[] = { _PATH_CELLSERVDB,
+ _PATH_ARLA_CELLSERVDB,
+ _PATH_OPENAFS_DEBIAN_CELLSERVDB,
+ _PATH_ARLA_DEBIAN_CELLSERVDB,
+ NULL };
+ for(fn = fns; *fn; fn++) {
+ f = fopen(*fn, "r");
+ if(f == NULL)
+ continue;
+ c = expand_one_file(f, cell);
+ fclose(f);
+ if(c)
+ return c;
+ }
+ return NULL;
+}
+
+static void
+usage(int ecode)
+{
+ arg_printusage(args, num_args, NULL, "[cell|path]...");
+ exit(ecode);
+}
+
+struct cell_list {
+ char *cell;
+ struct cell_list *next;
+} *cell_list;
+
+static int
+afslog_cell(const char *cell, int expand)
+{
+ struct cell_list *p, **q;
+ const char *c = cell;
+ if(expand){
+ c = expand_cell_name(cell);
+ if(c == NULL){
+ warnx("No cell matching \"%s\" found.", cell);
+ return -1;
+ }
+ if(verbose && strcmp(c, cell) != 0)
+ warnx("Cell \"%s\" expanded to \"%s\"", cell, c);
+ }
+ /* add to list of cells to get tokens for, and also remove
+ duplicates; the actual afslog takes place later */
+ for(p = cell_list, q = &cell_list; p; q = &p->next, p = p->next)
+ if(strcmp(p->cell, c) == 0)
+ return 0;
+ p = malloc(sizeof(*p));
+ if(p == NULL)
+ return -1;
+ p->cell = strdup(c);
+ if(p->cell == NULL) {
+ free(p);
+ return -1;
+ }
+ p->next = NULL;
+ *q = p;
+ return 0;
+}
+
+static int
+afslog_file(const char *path)
+{
+ char cell[64];
+ if(k_afs_cell_of_file(path, cell, sizeof(cell))){
+ warnx("No cell found for file \"%s\".", path);
+ return -1;
+ }
+ if(verbose)
+ warnx("File \"%s\" lives in cell \"%s\"", path, cell);
+ return afslog_cell(cell, 0);
+}
+
+static int
+do_afslog(const char *cell)
+{
+ int k5ret;
+
+ k5ret = 0;
+
+#ifdef KRB5
+ if(context != NULL && id != NULL && use_krb5) {
+ k5ret = krb5_afslog(context, id, cell, realm);
+ if(k5ret == 0)
+ return 0;
+ }
+#endif
+ if (cell == NULL)
+ cell = "<default cell>";
+#ifdef KRB5
+ if (k5ret)
+ krb5_warn(context, k5ret, "krb5_afslog(%s)", cell);
+#endif
+ if (k5ret)
+ return 1;
+ return 0;
+}
+
+static void
+log_func(void *ctx, const char *str)
+{
+ fprintf(stderr, "%s\n", str);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+ int i;
+ int num;
+ int ret = 0;
+ int failed = 0;
+ struct cell_list *p;
+
+ setprogname(argv[0]);
+
+ if(getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+ if(help_flag)
+ usage(0);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(!k_hasafs())
+ errx(1, "AFS does not seem to be present on this machine");
+
+ if(unlog_flag){
+ k_unlog();
+ exit(0);
+ }
+#ifdef KRB5
+ ret = krb5_init_context(&context);
+ if (ret) {
+ context = NULL;
+ } else {
+ if (client_string) {
+ krb5_principal client;
+
+ ret = krb5_parse_name(context, client_string, &client);
+ if (ret == 0)
+ ret = krb5_cc_cache_match(context, client, &id);
+ if (ret)
+ id = NULL;
+ }
+ if (id == NULL && cache_string) {
+ if(krb5_cc_resolve(context, cache_string, &id) != 0) {
+ krb5_warnx(context, "failed to open kerberos 5 cache '%s'",
+ cache_string);
+ id = NULL;
+ }
+ }
+ if (id == NULL)
+ if(krb5_cc_default(context, &id) != 0)
+ id = NULL;
+ }
+#endif
+
+ if (verbose)
+ kafs_set_verbose(log_func, NULL);
+
+ num = 0;
+ for(i = 0; i < files.num_strings; i++){
+ afslog_file(files.strings[i]);
+ num++;
+ }
+ free_getarg_strings (&files);
+ for(i = 0; i < cells.num_strings; i++){
+ afslog_cell(cells.strings[i], 1);
+ num++;
+ }
+ free_getarg_strings (&cells);
+ for(i = optidx; i < argc; i++){
+ num++;
+ if(strcmp(argv[i], ".") == 0 ||
+ strcmp(argv[i], "..") == 0 ||
+ strchr(argv[i], '/') ||
+ access(argv[i], F_OK) == 0)
+ afslog_file(argv[i]);
+ else
+ afslog_cell(argv[i], 1);
+ }
+ if(num == 0) {
+ if(do_afslog(NULL))
+ failed++;
+ } else
+ for(p = cell_list; p; p = p->next) {
+ if(verbose)
+ warnx("Getting tokens for cell \"%s\"", p->cell);
+ if(do_afslog(p->cell))
+ failed++;
+ }
+
+ return failed;
+}
diff --git a/third_party/heimdal/appl/afsutil/pagsh.1 b/third_party/heimdal/appl/afsutil/pagsh.1
new file mode 100644
index 0000000..3c1fd96
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/pagsh.1
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2005 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd February 12, 2005
+.Dt PAGSH 1
+.Os
+.Sh NAME
+.Nm pagsh
+.Nd creates a new credential cache sandbox
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar command-string
+.Op Fl h | Fl Fl help
+.Op Fl Fl version
+.Op Fl Fl cache-type= Ns Ar string
+.Ar command [args...]
+.Sh DESCRIPTION
+Supported options:
+.Bl -tag -width Ds
+.It Xo
+.Fl c Ar command-string
+Executes command(s) contained in
+.Ar command-string .
+.Xc
+.It Xo
+.Fl Fl cache-type= Ns Ar string
+.Xc
+.It Xo
+.Fl h ,
+.Fl Fl help
+.Xc
+.It Xo
+.Fl Fl version
+.Xc
+.El
+.Pp
+.Nm
+creates a new credential cache sandbox for the user to live in.
+If AFS is installed on the computer, the user is put in a newly
+created Process Authentication Group (PAG).
+.Pp
+For Kerberos 5, the credential cache type that is used is the same as
+the credential cache type that was used at the time of
+.Nm
+invocation.
+The credential cache type can be controlled by the option
+.Fl Fl cache-type .
+.Sh EXAMPLES
+Create a new sandbox where new credentials can be used, while the old
+credentials can be used by other processes.
+.Bd -literal -offset indent
+$ klist
+Credentials cache: FILE:/tmp/krb5cc_913
+ Principal: lha@E.KTH.SE
+
+ Issued Expires Principal
+Feb 12 10:08:31 Feb 12 20:06:36 krbtgt/E.KTH.SE@E.KTH.SE
+$ pagsh
+$ klist
+klist: No ticket file: /tmp/krb5cc_03014a
+.Ed
+.Sh SEE ALSO
+.Xr afslog 1 ,
+.Xr kinit 1
diff --git a/third_party/heimdal/appl/afsutil/pagsh.c b/third_party/heimdal/appl/afsutil/pagsh.c
new file mode 100644
index 0000000..377ac61
--- /dev/null
+++ b/third_party/heimdal/appl/afsutil/pagsh.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+RCSID("$Id$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <time.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef KRB5
+#include <krb5.h>
+#endif
+#include <kafs.h>
+
+#include <err.h>
+#include <roken.h>
+#include <getarg.h>
+
+#ifndef TKT_ROOT
+#define TKT_ROOT "/tmp/tkt"
+#endif
+
+static int help_flag;
+static int version_flag;
+static int c_flag;
+#ifdef KRB5
+static char *typename_arg;
+#endif
+
+struct getargs getargs[] = {
+ { NULL, 'c', arg_flag, &c_flag, NULL, NULL },
+#ifdef KRB5
+ { "cache-type", 0, arg_string, &typename_arg, NULL, NULL },
+#endif
+ { "version", 0, arg_flag, &version_flag, NULL, NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+};
+
+static int num_args = sizeof(getargs) / sizeof(getargs[0]);
+
+static void
+usage(int ecode)
+{
+ arg_printusage(getargs, num_args, NULL, "command [args...]");
+ exit(ecode);
+}
+
+/*
+ * Run command with a new ticket file / credentials cache / token
+ */
+
+int
+main(int argc, char **argv)
+{
+ int f;
+ char tf[1024];
+ char shellbuf[MAX_PATH];
+ char *p;
+
+ char *path;
+ char **args;
+ unsigned int i;
+ int optidx = 0;
+
+ setprogname(argv[0]);
+ if(getarg(getargs, num_args, argc, argv, &optidx))
+ usage(1);
+ if(help_flag)
+ usage(0);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ argc -= optidx;
+ argv += optidx;
+
+#ifdef KRB5
+ {
+ krb5_error_code ret;
+ krb5_context context;
+ krb5_ccache id;
+ const char *name;
+
+ ret = krb5_init_context(&context);
+ if (ret) /* XXX should this really call exit ? */
+ errx(1, "no kerberos 5 support");
+
+ ret = krb5_cc_new_unique(context, typename_arg, NULL, &id);
+ if (ret)
+ krb5_err(context, 1, ret, "Failed generating credential cache");
+
+ name = krb5_cc_get_name(context, id);
+ if (name == NULL)
+ krb5_errx(context, 1, "Generated credential cache have no name");
+
+ snprintf(tf, sizeof(tf), "%s:%s", krb5_cc_get_type(context, id), name);
+
+ ret = krb5_cc_close(context, id);
+ if (ret)
+ krb5_err(context, 1, ret, "Failed closing credential cache");
+
+ krb5_free_context(context);
+
+ esetenv("KRB5CCNAME", tf, 1);
+ }
+#endif
+
+ snprintf (tf, sizeof(tf), "%s_XXXXXX", TKT_ROOT);
+ f = mkstemp (tf);
+ if (f < 0)
+ err(1, "mkstemp failed");
+ close (f);
+ unlink (tf);
+ esetenv("KRBTKFILE", tf, 1);
+
+ i = 0;
+
+ args = (char **) malloc((argc + 10)*sizeof(char *));
+ if (args == NULL)
+ errx (1, "Out of memory allocating %lu bytes",
+ (unsigned long)((argc + 10)*sizeof(char *)));
+
+ if(*argv == NULL) {
+ if (roken_get_shell(shellbuf, sizeof(shellbuf)) != NULL)
+ path = strdup(shellbuf);
+ else
+ path = strdup("/bin/sh");
+ } else {
+ path = strdup(*argv++);
+ }
+ if (path == NULL)
+ errx (1, "Out of memory copying path");
+
+ p=strrchr(path, '/');
+ if(p)
+ args[i] = strdup(p+1);
+ else
+ args[i] = strdup(path);
+
+ if (args[i++] == NULL)
+ errx (1, "Out of memory copying arguments");
+
+ while(*argv)
+ args[i++] = *argv++;
+
+ args[i++] = NULL;
+
+ if(k_hasafs())
+ k_setpag();
+
+ unsetenv("PAGPID");
+ execvp(path, args);
+ if (errno == ENOENT || c_flag) {
+ char **sh_args = malloc ((i + 2) * sizeof(char *));
+ unsigned int j;
+
+ if (sh_args == NULL)
+ errx (1, "Out of memory copying sh arguments");
+ for (j = 1; j < i; ++j)
+ sh_args[j + 2] = args[j];
+ sh_args[0] = "sh";
+ sh_args[1] = "-c";
+ sh_args[2] = path;
+ execv ("/bin/sh", sh_args);
+ }
+ err (1, "execvp");
+}
diff --git a/third_party/heimdal/appl/dbutils/Makefile.am b/third_party/heimdal/appl/dbutils/Makefile.am
new file mode 100644
index 0000000..a1fc384
--- /dev/null
+++ b/third_party/heimdal/appl/dbutils/Makefile.am
@@ -0,0 +1,13 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+bin_PROGRAMS = bsearch
+
+bsearch_SOURCES = bsearch.c
+
+man_MANS = bsearch.1
+
+EXTRA_DIST = NTMakefile $(man_MANS)
+
+LDADD = $(LIB_roken) $(LIB_vers) $(LIB_heimbase)
diff --git a/third_party/heimdal/appl/dbutils/NTMakefile b/third_party/heimdal/appl/dbutils/NTMakefile
new file mode 100644
index 0000000..73ea816
--- /dev/null
+++ b/third_party/heimdal/appl/dbutils/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\dbutils
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/dbutils/bsearch.1 b/third_party/heimdal/appl/dbutils/bsearch.1
new file mode 100644
index 0000000..0ea919c
--- /dev/null
+++ b/third_party/heimdal/appl/dbutils/bsearch.1
@@ -0,0 +1,115 @@
+.\"
+.\" Copyright (c) 2011, 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.
+.\"
+.Dd November 30, 2011
+.Dt BSEARCH 1
+.Os KTH-KRB
+.Sh NAME
+.Nm bsearch
+.Nd manages one-time passwords
+.Sh SYNOPSIS
+.Nm bsearch
+.Op Fl KVvh
+.Op Fl b Ar block-size
+.Op Fl m Ar max-cache-size
+.Ar file
+.Ar [key ...]
+.Sh DESCRIPTION
+The
+.Nm
+program performs binary searches of
+.Ar file
+which must be a sorted flat text file.
+.Pp
+Each line is a record. Each record starts with a key
+that is optionally followed by whitespace and a value.
+Whitespace may be quoted with a backslash, but newline
+and carriage-return characters must be quoted in some
+other manner (e.g., as backslash-n and backslash-r).
+Escapes are not interpreted nor removed.
+.Pp
+If no key arguments are given on the comman-line, then
+keys will be read from standard input.
+.Pp
+By default only values are printed to standard output.
+Use the -K option to also print keys. The exit status
+will be non-zero if any key lookups fail.
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl K
+Print keys.
+.It Fl V
+Don't print values.
+.It Fl h
+Print usage and exit.
+.It Fl v
+Print statistic and debug information to standard
+error.
+.Ar file
+A sorted flat text file. NOTE: use the "C" locale for
+sorting this file, as in "LC_ALL=C sort -u -o file
+file".
+.It Fl h
+For getting a help message.
+.It Fl m
+Set
+.Ar max-cache-size
+as the maximum cache size. If the
+.Ar file
+is smaller than this size then the whole file will be
+read into memory, else the program will read blocks.
+Defaults to 1MB.
+.It Fl b
+Set
+.Ar block-size
+as the block size for block-wise I/O. This must be a
+power of 2, must be no smaller than 512 and no larger
+than 1MB. Defaults to the
+.Ar file's
+filesystem's preferred blocksize.
+.El
+.Sh EXAMPLES
+.Bd -literal -offset indent
+$ env LC_ALL=C sort -o /tmp/words /usr/share/dict/words
+$ bsearch -Kv /tmp/words day
+Using whole-file method
+Key day found at offset 327695 in 12 loops and 0 reads
+day
+$
+.Ed
+.Sh NOTES
+.Pp
+Records must not be longer than one block's size.
+.Pp
+Flat text files must be sorted in the "C" locale. In
+some systems the default locale may result in
+case-insensitive sorting by the sort command.
+.Sh SEE ALSO
+.Xr sort 1
diff --git a/third_party/heimdal/appl/dbutils/bsearch.c b/third_party/heimdal/appl/dbutils/bsearch.c
new file mode 100644
index 0000000..da37251
--- /dev/null
+++ b/third_party/heimdal/appl/dbutils/bsearch.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <roken.h>
+#include <heimbase.h>
+#include <getarg.h>
+#include <vers.h>
+
+int help_flag;
+int version_flag;
+int verbose_flag;
+int print_keys_flag;
+int no_values_flag;
+int block_size_int;
+int max_size_int;
+
+struct getargs args[] = {
+ { "print-keys", 'K', arg_flag, &print_keys_flag,
+ "print keys", NULL },
+ { "no-values", 'V', arg_flag, &no_values_flag,
+ "don't print values", NULL },
+ { "verbose", 'v', arg_flag, &verbose_flag,
+ "print statistics and informative messages", NULL },
+ { "help", 'h', arg_flag, &help_flag,
+ "print usage message", NULL },
+ { "block-size", 'b', arg_integer, &block_size_int,
+ "block size", "integer" },
+ { "max-cache-size", 'm', arg_integer, &max_size_int,
+ "maximum cache size", "integer" },
+ { "version", '\0', arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int status)
+{
+ arg_printusage(args, num_args, NULL, "file [key ...]");
+ exit(status);
+}
+
+#define MAX_BLOCK_SIZE (1024 * 1024)
+#define DEFAULT_MAX_FILE_SIZE (1024 * 1024)
+
+int
+main(int argc, char **argv)
+{
+ char keybuf[1024];
+ char *fname;
+ char *key = keybuf;
+ char *value;
+ char *p;
+ bsearch_file_handle bfh = NULL;
+ size_t num;
+ size_t loc; /* index where record is located or to be inserted */
+ size_t loops; /* number of loops/comparisons needed for lookup */
+ size_t reads = 0; /* number of reads needed for a lookup */
+ size_t failures = 0; /* number of lookup failures -- for exit status */
+ size_t block_size = 0;
+ size_t max_size = 0;
+ int optidx = 0;
+ int blockwise;
+ int ret = 0;
+
+ setprogname(argv[0]);
+ if (getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+
+ if (version_flag) {
+ print_version(NULL);
+ return 0;
+ }
+
+ if (help_flag)
+ usage(0);
+
+ if (block_size_int != 0 && block_size_int < 512) {
+ fprintf(stderr, "Invalid block size: too small\n");
+ return 1;
+ }
+ if (block_size_int > 0) {
+ /* Check that block_size is a power of 2 */
+ num = block_size_int;
+ while (num) {
+ if ((num % 2) && (num >> 1)) {
+ fprintf(stderr, "Invalid block size: must be power "
+ "of two\n");
+ return 1;
+ }
+ num >>= 1;
+ }
+ if (block_size_int > MAX_BLOCK_SIZE)
+ fprintf(stderr, "Invalid block size: too large\n");
+ block_size = block_size_int;
+ }
+ if (max_size_int < 0)
+ usage(1);
+ max_size = max_size_int;
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage(1);
+
+ fname = argv[0];
+ argc--;
+ argv++;
+
+ ret = _bsearch_file_open(fname, max_size, block_size, &bfh, &reads);
+ if (ret != 0) {
+ perror("bsearch_file_open");
+ return 1;
+ }
+
+ _bsearch_file_info(bfh, &block_size, &max_size, &blockwise);
+ if (verbose_flag && blockwise) {
+ fprintf(stderr, "Using block-wise method with block size %lu and "
+ "cache size %lu\n",
+ (long unsigned)block_size, (long unsigned)max_size);
+ } else if (verbose_flag) {
+ fprintf(stderr, "Using whole-file method\n");
+ }
+
+ for (;;) {
+ loops = 0; /* reset stats */
+ /* Eww */
+ if (argc) {
+ key = *(argv++);
+ if (!key)
+ break;
+ } else {
+ if (!fgets(keybuf, sizeof (keybuf), stdin))
+ break;
+ p = strchr(key, '\n');
+ if (!p)
+ break;
+ *p = '\0';
+ if (!*key)
+ continue;
+ }
+ ret = _bsearch_file(bfh, key, &value, &loc, &loops, &reads);
+ if (ret != 0) {
+ if (ret > 0) {
+ fprintf(stderr, "Error: %s\n", strerror(ret));
+ _bsearch_file_close(&bfh);
+ return 1;
+ }
+ if (verbose_flag)
+ fprintf(stderr, "Key %s not found in %lu loops and %lu reads; "
+ "insert at %lu\n", key, (long unsigned)loops,
+ (long unsigned)reads, (long unsigned)loc);
+ failures++;
+ continue;
+ }
+ if (verbose_flag)
+ fprintf(stderr, "Key %s found at offset %lu in %lu loops and "
+ "%lu reads\n", key, (long unsigned)loc,
+ (long unsigned)loops, (long unsigned)reads);
+ if (print_keys_flag && !no_values_flag && value)
+ printf("%s %s\n", key, value);
+ else if (print_keys_flag)
+ printf("%s\n", key);
+ else if (no_values_flag && value)
+ printf("%s\n", value);
+ free(value);
+ }
+ if (failures)
+ return 2;
+ _bsearch_file_close(&bfh);
+ return 0;
+}
diff --git a/third_party/heimdal/appl/dceutils/ChangeLog b/third_party/heimdal/appl/dceutils/ChangeLog
new file mode 100644
index 0000000..f583aeb
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/ChangeLog
@@ -0,0 +1,39 @@
+2007-12-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: Add missing files, from Buchan Milne.
+
+2006-08-08 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * k5dcecon.c: Check for seteuid failure, prompted by MIT advisory.
+
+2005-04-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * testpag.c: use NULL as last argument to execl, not 0
+
+2002-08-12 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: rename dpagaix_LDFLAGS etc to appease automake
+
+2001-08-24 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (dpagaix): make sure of using $(EXEEXT) just to
+ please automake (this is aix-only code)
+
+2001-02-07 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (dpagaix): needs to be linked with ld, add an
+ explicit command for it. from Ake Sandgren <ake@cs.umu.se>
+
+2000-10-02 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: link with roken on everything except irix, where
+ apperently it fails. reported by Ake Sandgren <ake@cs.umu.se>
+
+2000-07-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: set compiler flags
+
+2000-07-01 Assar Westerlund <assar@sics.se>
+
+ * imported stuff from Ake Sandgren <ake@cs.umu.se>
+
diff --git a/third_party/heimdal/appl/dceutils/Makefile.am b/third_party/heimdal/appl/dceutils/Makefile.am
new file mode 100644
index 0000000..6fa9d1a
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/Makefile.am
@@ -0,0 +1,37 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+
+DFSPROGS = k5dcecon
+if AIX
+AIX_DFSPROGS = dpagaix
+endif
+
+libexec_PROGRAMS = $(DFSPROGS) $(AIX_DFSPROGS)
+
+dpagaix_CFLAGS = $(dpagaix_cflags)
+dpagaix_LDFLAGS = $(dpagaix_ldflags)
+dpagaix_LDADD = $(dpagaix_ldadd)
+
+dpagaix$(EXEEXT): $(dpagaix_OBJECTS)
+ ld -edpagaix -o dpagaix$(EXEEXT) $(dpagaix_OBJECTS) $(srcdir)/dfspag.exp
+
+LIB_dce = -ldce
+
+k5dcecon_SOURCES = k5dcecon.c k5dce.h
+
+dpagaix_SOURCES = dpagaix.c
+
+EXTRA_DIST = \
+ NTMakefile \
+ dfspag.exp \
+ README.dcedfs \
+ README.original \
+ testpag.c
+
+if IRIX
+LDADD = $(LIB_dce)
+else
+LDADD = $(LIB_roken) $(LIB_dce)
+endif
diff --git a/third_party/heimdal/appl/dceutils/NTMakefile b/third_party/heimdal/appl/dceutils/NTMakefile
new file mode 100644
index 0000000..eb27eb4
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/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\dceutils
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/dceutils/README.dcedfs b/third_party/heimdal/appl/dceutils/README.dcedfs
new file mode 100644
index 0000000..5849ad6
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/README.dcedfs
@@ -0,0 +1,59 @@
+This is a set of patches and files to get a DFS ticket from a k5 ticket.
+This code comes from Doug Engert, Argonne Nat. Lab (See dce/README.original
+for more info)
+
+The files in dce are;
+testpag: for testing if this is at all possible.
+k5dfspag: included in libkrb5
+k5dcecon: Creates (or searches for) the actual DFSPAG ticketfile.
+dpagaix: An AIX syscall stub.
+README.original: Original README file from Doug Engert
+
+
+Certain applications (rshd/telnetd) have been patched to call the
+functions in k5dfspag when the situation is right. They are ifdef
+with DCE. The patches are also originally from Doug but they
+where against MIT krb5 code and have been merged into heimdal by me.
+I will try to fix ftpd soon...
+
+There is also an ifdefs for DCE && AIX that can be used to make AIX
+use DCE for getting group/passwd entries. This is needed if one is running
+with a bare bones passwd/group file and AUTHSTATE set to DCE (This will be
+more or less clear to people doing this...) I have forced this on for now.
+
+k5dfspag.c is in lib/krb5
+k5dfspag.c is dependent on DCE only.
+It is also POSIX systems only. There are defines for the location of
+k5dcecon and dpagaix that needs a correct configure setting.
+
+k5dcecon needs no special things for the compile except whatever is needed
+on the target system to compile dce programs.
+(On aix the dce compile flags are: -D_THREAD_SAFE -D_AIX32_THREADS=1 -D_AIX41 -D_AES_SOURCE or one can use xlc_r4 if it is version 3.6.4 or later)
+
+k5dcecon wants the following libs (on aix 4.3):
+-ldce (and setenv from somewhere)
+
+dpagaix is only needed on AIX (see k5dfspag.c).
+dpagaix needs dfspag.exp and is linked with
+ld -edpagaix -o dpagaix dpagaix.o dfspag.exp
+
+
+Hope to get this into heimdal soon :-) although I know that you will have to
+change some things to get it cleanly into configure. Since I don't know the
+structure of the code (heimdal), nor enough of configure, good enough I
+just won't try it myself.
+
+One more thing, to get this to work one has to put fcache_version = x in
+krb5.conf where x = whatever the DCE implementation understands, (usually
+1 or 2).
+Thanks for adding that...
+
+
+Åke Sandgren (ake@hpc2n.umu.se)
+HPC2N
+Umeå University
+Sweden
+
+PS
+I have now added patches for configure.in and some Makefile.am's to get this
+all cleanly (I hope) into heimdal.
diff --git a/third_party/heimdal/appl/dceutils/README.original b/third_party/heimdal/appl/dceutils/README.original
new file mode 100644
index 0000000..0887023
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/README.original
@@ -0,0 +1,335 @@
+KERBEROS and DCE INTEROPERABILITY ROUTINES
+
+WHAT'S NEW
+
+When k5dcecon was examining the ticket caches looking to
+update one with a newer TGT, it might update the wrong
+one for the correct user. This problem was reported by PNNL,
+and is now fixed.
+
+Any Kerberized application can now use a forwarded TGT to establish a
+DCE context, or can use a previously established DCE context. This is
+both a functional improvement and a performance improvement.
+
+BACKGROUND
+
+The MIT Kerberos 5 Release 1.x and DCE 1.1 can interoperate in a
+number of ways. This is possible because:
+
+ o DCE used Kerberos 5 internally. Based on the MIT code as of beta 4
+ or so, with additional changes.
+
+ o The DCE security server can act as a K5 KDC, as defined in RFC 1510
+ and responds on port 88.
+
+ o On the clients, DCE and Kerberos use the same format for the ticket
+ cache, and then can share it. The KRB5CCNAME environment variable points
+ at the cache.
+
+ o On the clients, DCE and Kerberos use the same format for the srvtab
+ file. DCE refers to is a /krb5/v5srvtab and Kerberos as
+ /etc/krb5.keytab. They can be symlinked.
+
+ o MIT has added many options to the krb5.conf configuration file
+ which allows newer features of Release 1.0 to be turned off to match
+ the earlier version of Kerberos upon which DCE is based.
+
+ o DCE will accept a externally obtained Kerberos TGT in place of a
+ password when establishing a DCE context.
+
+There are some areas where they differ, including the following:
+
+ o Administration of the database and the keytab files is done by the
+ DCE routines, rather the the Kerberos kadmin.
+
+ o User password changes must be done using the DCE commands. Kpasswd
+ does not work. (But there are mods to Kerberos to use the v5passwd
+ with DCE.
+
+ o DCE goes beyond authentication only, and provides authorization via
+ the PAC, and the dce-ptgt tickets stored in the cache. Thus a
+ Kerberos KDC can not act as a DCE security server.
+
+ o A DCE cell and Kerberos realm can cross-realm authenticate, but
+ there can be no intermediate realms. (There are other problems
+ in this area as well. But directly connected realms/cells do work.)
+
+ o You can't link a module with the DCE library and the Kerberos
+ library. They have conflicting routines, static data and structures.
+
+One of the main features of DCE is the Distributed File System
+DFS. Access to DFS requires authentication and authorization, and when
+one uses a Kerberized network utility such as telnet, a forwarded
+Kerberos ticket can be used to establish the DCE context to allow
+access to DFS.
+
+
+NEW TO THIS RELEASE
+
+This release introduces sharing of a DCE context, and PAG, and allows
+any Kerberized application to establish or share the context. This is
+made possible by using an undocumented feature of DCE which is on at
+least the Transarc and IBM releases of DCE 1.1.
+
+I am in the process of trying to get this contributed to the general
+DCE 1.2.2 release as a patch, so it could be included in other vendors
+products. HP has expressed interest in doing this, as well as the
+OpenGroup if the modification is contributed. You can help by
+requesting Transarc and/or IBM to submit this modification to the
+OpenGroup and ask your vendor to adopt this modification.
+
+The feature is a modification to the setpag() system call which will
+allow an authorized process to set the PAG to a specific value, and
+thus allow unrelated processes to share the same PAG.
+
+This then allows the Kerberized daemons such as kshd, to exec a DCE
+module which established the DCE context. Kshd then sets the
+KRB5CCNAME environment variable and then issues the setpag() to use
+this context. This solves the linking problem. This is done via the
+k5dfspag.c routine.
+
+The k5dfspag.c code is compiled with the lib/krb5/os routines and
+included in the libkrb5. A daemon calls krb5_dfs_pag after the
+krb5_kuserok has determined that the Kerberos principal and local
+userid pair are acceptable. This should be done early so as to give
+the daemon access to the home directory which may be located on DFS.
+If the .k5login file is used by krb5_kuserok it will need to be
+accessed by the daemon and will need special ACL handling.
+
+The krb5_dfs_pag routine will exec the k5dcecon module to do all the
+real work. Upon return, if a PAG is obtained, krb5_dfs_pag with set
+the PAG for the current process to the returned PAG value. It will
+also set the KRB5CCNAME environment as well. Under DCE the PAG value
+is the nnnnnnn part of the name of the cache:
+FILE:/opt/dcelocal/var/security/creds/dcecred_nnnnnnnn.
+
+The k5dcecon routine will attempt to use TGT which may have been
+forwarded, to convert it to a DCE context. If there is no TGT, an
+attempt will be made to join an existing PAG for the local userid, and
+Kerberos principal. If there are existing PAGs, and a forwarded TGT,
+k5dcecon will check the lifetime of the forwarded TGT, and if it is
+less than the lifetime of the PAG, it will just join the PAG. If it
+is greater, it will refresh the PAG using the forwarded TGT.
+This approach has the advantage of not requiring many new tickets from
+having to be obtained, and allows one to refresh a DCE context, or use
+an already established context.
+
+If the system also has AFS, the AFS krb5_afs_pag should be called
+after the krb5_dfs_pag, since cache pointed at via the KRB5CCNAME may
+have changed, such as if a DFS PAG has been joined. The AFS code does
+not have the capability to join an existing AFS PAG, but can use the
+same cache which might already had a
+afsx/<afs.cell.name>@<k5.realm.name> service ticket.
+
+
+WHAT'S IN THIS RELEASE
+
+The k5prelogin, k5dcelogin, k5afslogin (with ak5log) were designed to
+be slipped in between telnetd or klogind and login.krb5. They would
+use a forwarded Kerberos ticket to establish a DCE context. They are
+the older programs which are included here. They work on all DCE
+platforms, and don't take advantage of the undocumented setpag
+feature. (A version of k5dcelogin is being included with DCE 1.2.2)
+
+K5dcecon is the new program which can be used to create, update or
+join a DCE context. k5dcecon returns KRB5CCNAME string which contains
+the PAG.
+
+k5dfspag.c is to be built in the MIT Kerberos 5 release 1.0 patchlevel
+1 and added to the libkrb5. It will exec k5dcecon and upon return set
+the KRB5CCNAME and PAG. Mods to Kerberized klogind, rshd, telnetd,
+ftpd are available to use the k5dfspag.
+
+Testpag.c is a test programs to see if the PAG can be set.
+
+The cpwkey.c routine can be used to change a key in the DCE registry,
+by adding the key directly, or by setting the salt/pepper and password
+or by providing the key and the pepper. This could be useful when
+coping keys from a K4 or AFS database to DCE. It can also be used when
+setting a DCE to K5 cross-cell key. This program is a test program
+For mass inserts, it should be rewritten to read from stdin.
+
+K5dcelogin can also be called directly, much like dce_login.
+I use the following commands in effect do the same thing as dce_login
+and get a forwardable ticket, DCE context and an AFS token:
+
+ #!/bin/csh
+ # simulate a dce_login using krb5 kinit and k5dcelogin
+ #
+ setenv KRB5CCNAME FILE:/tmp/krb5cc_p$$
+ /krb5/bin/kinit -f
+ exec /krb5/sbin/k5dcelogin /krb5/sbin/k5afslogin /bin/csh
+ #exec /krb5/sbin/k5dcelogin /bin/csh
+
+This could be useful in a mixed cell where "AS_REQ" messages are
+handled by a K5 KDC, but DCE RPCs are handled by the DCE security
+server.
+
+TESTING THE SETPAG
+
+The krb5_dfs_pag routine relies on an undocumented feature which is
+in the AIX and Transarc Solaris ports of DCE and has been recently
+added to the SGI version. To test if this feature is present
+on some other DFS implementation use the testpag routine.
+
+The testpag routine attempts to set a PAG value to one you supply. It
+uses the afs_syscall with the afs_setpag, and passes the supplied
+PAG value as the next parameter. On an unmodifed system, this
+will be ignored, and a new will be set. You should also check that
+if run as a user, you cannot join a PAG owned by another user.
+When run as root, any PAG should be usable.
+
+On a machine with DFS running, do a dce_login to get a DCE context and
+PAG. ECHO the KRB5CCNAME and look at the nnnnnnnn at the end. It
+should look like an 8 char hex value, which may be 41ffxxxx on some
+systems.
+
+Su to root and unsetenv KRB5CCNAME. Do a testpag -n nnnnnnnn where
+nnnnnnnn is the PAG obtained for the above name.
+
+It should look like this example on an AIX 4.1.4 system:
+
+ pembroke# ./testpag -n 63dc9997
+ calling k5dcepag newpag=63dc9997
+ PAG returned = 63dc9997
+
+You will be running under a new shell with the PAG and KRB5CCNAME set.
+If the PAG returned is the same as the newpag, then it worked. You can
+further verify this by doing a DCE klist, cd to DFS and a DCE klist
+again. The klist should show some tickets for DFS servers.
+
+If the PAG returned is not the same, and repeated attempts show a
+returned PAG decremented by 1 from the previous returned PAG, then
+this system does not have the modification For example:
+
+ # ./testpag -n 41fffff9
+ calling k5dcepag newpag=41fffff9
+ PAG returned = 41fffff8
+ # ./testpag -n 41fffff9
+ calling k5dcepag newpag=41fffff9
+ PAG returned = 41fffff7
+
+In this case the syscall is ignoring the newpag parameter.
+
+Running it with -n 0 should get the next PAG value with or without
+this modification.
+
+If the DFS kernel extensions are not installed, you would get
+something like this:
+
+ caliban.ctd.anl.gov% ./testpag -n 012345678
+ calling k5dcepag newpag=012345678
+ Setpag failed with a system error
+ PAG returned = ffffffff
+ Not a good pag value
+
+If you DFS implementation does not have this modification, you could
+attempt to install it yourself. But this requires source and requires
+modifications to the kernel extensions. At the end of this note is an
+untested sample using the DCE 1.2.2 source code. You can also contact
+your system vendor and ask for this modification.
+
+UNICOS has a similar function setppag(newpag) which can be used to set
+the PAG of the parent. Contact me if you are interested.
+
+HOW TO INSTALL
+
+Examine the k5dfspag.c file to make sure the DFS syscalls are correct
+for your platform. See the /opt/dcelocal/share/include/dcedfs/syscall.h
+on Solaris for example.
+
+You should build the testpag routine and make sure it works before
+adding all the other mods. If it fails you can still use the klogind
+and telnetd with the k5prelogin and k5dcelogin code.
+
+If you intend to install with a prefix other than /krb5, change:
+DPAGAIX and K5DCECON in k5dfspag.c; the three references in
+k5prelogin.c; and the DESTDIR in the Makefile.
+
+Get k5101.cdiff.xxxxxx.tar file and install the mods for ANL_DFS_PAG
+and ANL_DCE to the MIT Kerberos 5 source. These mods turn on some DCE
+related changes and the calls to krb5_dfs_pag.
+
+Symlink or copy the k5dfspag.c to the src/lib/krb5/os directory.
+
+Add the -DANL_DFS_PAG and -DANL_DCE flags to the configuration.
+
+Configure and Build the Kerberos v5.
+
+Modify the k5dce Makefile for your system.
+
+Build the k5dcecon and related programs.
+
+Install both the MIT Kerberos v5 and the k5dcecon and dpagaix if AIX.
+
+The makefile can also build k5dcelogin and k5prelogin. The install
+can install k5dcelogin, k5prelogin and update the links for login.krb5
+-> k5prelogin and moving login.krb5 to login.k5. If you will be using
+the k5dcecon/k5dfspag with the Kerberos mods, you don't need
+k5prelogin, or the links changed, and may not need k5dcelogin.
+
+Note that Transarc has obfuscated the entries to the lib, and
+the 1.0.3a is different from the 1.1. You may need to build two
+versions of the k5dcelogin and/or k5dcecon one for each.
+
+AIX ONLY
+
+The dpagaix routine is needed for AIX because of the way they do the
+syscalls.
+
+The following fix.aix.libdce.mk is not needed if dce 2.1.0.21
+has been installed. This PTF exposed the needed entrypoints.
+
+The fix.aix.libdce.mk is a Makefile for AIX 4.x to add the required
+external entry points to the libdce.a. These are needed by k5dcecon
+and k5dcelogin. A bug report was submitted to IBM on this, and it was
+rejected. But since DCE 1.2.2 will have a k5dcelogin, this should not
+be needed with 1.2.2
+
+Copy /usr/lib/libdce.a to /usr/libdce.a.orig before starting. Copy the
+makefile to its own directory. It will create a new libdce.a which you
+need to copy back to /usr/lib/libdce.a You will need to reboot the
+machine. See the /usr/lpp/dce/examples/inst/README.AIX for a similar
+procedure. IBM was not responsive in a request to have these added.
+
+UNTESTED KERNEL EXTENSION FOR SETPAG
+
+*** src/file/osi/,osi_pag.c Wed Oct 2 13:03:05 1996
+--- src/file/osi/osi_pag.c Mon Jul 28 13:53:13 1997
+***************
+*** 293,298 ****
+--- 293,302 ----
+ int code;
+
+ osi_MakePreemptionRight();
++ /* allow sharing of a PAG by non child processes DEE- 6/6/97 */
++ if (unused && osi_GetUID(osi_getucred()) == 0) {
++ newpag = unused;
++ } else {
+ osi_mutex_enter(&osi_pagLock);
+ now = osi_Time();
+ soonest = osi_firstPagTime +
+***************
+*** 309,314 ****
+--- 313,319 ----
+ }
+ osi_mutex_exit(&osi_pagLock);
+ newpag = osi_genpag();
++ }
+ osi_pcred_lock(p);
+ credp = crcopy(osi_getucred());
+ code = osi_SetPagInCred(credp, newpag);
+
+Created 07/08/96
+Modified 09/30/96
+Modified 11/19/96
+Modified 12/19/96
+Modified 06/20/97
+Modified 07/28/97
+Modified 02/18/98
+
+ Douglas E. Engert <DEEngert@anl.gov>
+ Argonne National Laboratory
+ 9700 South Cass Avenue
+ Argonne, Illinois 60439
+ (630) 252-5444
diff --git a/third_party/heimdal/appl/dceutils/dfspag.exp b/third_party/heimdal/appl/dceutils/dfspag.exp
new file mode 100644
index 0000000..ed39788
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/dfspag.exp
@@ -0,0 +1,3 @@
+#!/unix
+* kernel extentions used to get the pag
+kafs_syscall syscall
diff --git a/third_party/heimdal/appl/dceutils/dpagaix.c b/third_party/heimdal/appl/dceutils/dpagaix.c
new file mode 100644
index 0000000..304a9a2
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/dpagaix.c
@@ -0,0 +1,23 @@
+/*
+ * dpagaix.c
+ * On AIX we need to get the kernel extentions
+ * with the DFS kafs_syscall in it.
+ * We might be running on a system
+ * where DFS is not active.
+ * So we use this dummy routine which
+ * might not load to do the dirty work
+ *
+ * DCE does this with the /usr/lib/drivers/dfsloadobj
+ *
+ */
+
+ int dpagaix(parm1, parm2, parm3, parm4, parm5, parm6)
+ int parm1;
+ int parm2;
+ int parm3;
+ int parm4;
+ int parm5;
+ int parm6;
+ {
+ return(kafs_syscall(parm1, parm2, parm3, parm4, parm5, parm6));
+ }
diff --git a/third_party/heimdal/appl/dceutils/k5dce.h b/third_party/heimdal/appl/dceutils/k5dce.h
new file mode 100644
index 0000000..dd32865
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/k5dce.h
@@ -0,0 +1,165 @@
+/* dummy K5 routines which are needed to get this to
+ * compile without having access ti the DCE versions
+ * of the header files.
+ * Thiis is very crude, and OSF needs to expose the K5
+ * API.
+ */
+
+#ifdef sun
+/* Transarc obfuscates these routines */
+#ifdef DCE_1_1
+
+#define krb5_init_ets _dce_PkjKqOaklP
+#define krb5_copy_creds _dce_LuFxPiITzD
+#define krb5_unparse_name _dce_LWHtAuNgRV
+#define krb5_get_default_realm _dce_vDruhprWGh
+#define krb5_build_principal _dce_qwAalSzTtF
+#define krb5_build_principal_ext _dce_vhafIQlejW
+#define krb5_build_principal_va _dce_alsqToMmuJ
+#define krb5_cc_default _dce_KZRshhTXhE
+#define krb5_cc_default_name _dce_bzJVAjHXVQ
+#define sec_login_krb5_add_cred _dce_ePDtOJTZvU
+
+#else /* DCE 1.0.3a */
+
+#define krb5_init_ets _dce_BmLRpOVsBo
+#define krb5_copy_creds _dce_VGwSEBNwaf
+#define krb5_unparse_name _dce_PgAOkJoMXA
+#define krb5_get_default_realm _dce_plVOzStKyK
+#define krb5_build_principal _dce_uAKSsluIFy
+#define krb5_build_principal_ext _dce_tRMpPiRada
+#define krb5_build_principal_va _dce_SxnLejZemH
+#define krb5_cc_default _dce_SeKosWFnsv
+#define krb5_cc_default_name _dce_qJeaphJWVc
+#define sec_login_krb5_add_cred _dce_uHwRasumsN
+
+#endif
+#endif
+
+/* Define the bare minimum k5 structures which are needed
+ * by this program. Since the krb5 includes are not supplied
+ * with DCE, these were based on the MIT Kerberos 5 beta 3
+ * which should match the DCE as of 1.0.3 at least.
+ * The tricky one is the krb5_creds, since one is allocated
+ * by this program, and it needs access to the client principal
+ * in it.
+ * Note that there are no function prototypes, so there is no
+ * compile time checking.
+ * DEE 07/11/95
+ */
+#define NPROTOTYPE(x) ()
+typedef int krb5_int32; /* assuming all DCE systems are 32 bit */
+typedef short krb5short; /* assuming short is 16 bit */
+typedef krb5_int32 krb5_error_code;
+typedef unsigned char krb5_octet;
+typedef krb5_octet krb5_boolean;
+typedef krb5short krb5_keytype; /* in k5.2 it's a short */
+typedef krb5_int32 krb5_flags;
+typedef krb5_int32 krb5_timestamp; /* is a time_t in krb5.h */
+
+typedef char * krb5_pointer; /* pointer to unexposed data */
+
+typedef struct _krb5_ccache {
+ struct _krb5_cc_ops *ops;
+ krb5_pointer data;
+} *krb5_ccache;
+
+typedef struct _krb5_cc_ops {
+ char *prefix;
+ char *(*get_name) NPROTOTYPE((krb5_ccache));
+ krb5_error_code (*resolve) NPROTOTYPE((krb5_ccache *, char *));
+ krb5_error_code (*gen_new) NPROTOTYPE((krb5_ccache *));
+ krb5_error_code (*init) NPROTOTYPE((krb5_ccache, krb5_principal));
+ krb5_error_code (*destroy) NPROTOTYPE((krb5_ccache));
+ krb5_error_code (*close) NPROTOTYPE((krb5_ccache));
+ krb5_error_code (*store) NPROTOTYPE((krb5_ccache, krb5_creds *));
+ krb5_error_code (*retrieve) NPROTOTYPE((krb5_ccache, krb5_flags,
+ krb5_creds *, krb5_creds *));
+ krb5_error_code (*get_princ) NPROTOTYPE((krb5_ccache,
+ krb5_principal *));
+ krb5_error_code (*get_first) NPROTOTYPE((krb5_ccache,
+ krb5_cc_cursor *));
+ krb5_error_code (*get_next) NPROTOTYPE((krb5_ccache, krb5_cc_cursor *,
+ krb5_creds *));
+ krb5_error_code (*end_get) NPROTOTYPE((krb5_ccache, krb5_cc_cursor *));
+ krb5_error_code (*remove_cred) NPROTOTYPE((krb5_ccache, krb5_flags,
+ krb5_creds *));
+ krb5_error_code (*set_flags) NPROTOTYPE((krb5_ccache, krb5_flags));
+} krb5_cc_ops;
+
+typedef struct _krb5_keyblock {
+ krb5_keytype keytype;
+ int length;
+ krb5_octet *contents;
+} krb5_keyblock;
+
+typedef struct _krb5_ticket_times {
+ krb5_timestamp authtime;
+ krb5_timestamp starttime;
+ krb5_timestamp endtime;
+ krb5_timestamp renew_till;
+} krb5_ticket_times;
+
+typedef krb5_pointer krb5_cc_cursor;
+
+typedef struct _krb5_data {
+ int length;
+ char *data;
+} krb5_data;
+
+typedef struct _krb5_authdata {
+ int ad_type;
+ int length;
+ krb5_octet *contents;
+} krb5_authdata;
+
+typedef struct _krb5_creds {
+ krb5_pointer client;
+ krb5_pointer server;
+ krb5_keyblock keyblock;
+ krb5_ticket_times times;
+ krb5_boolean is_skey;
+ krb5_flags ticket_flags;
+ krb5_pointer **addresses;
+ krb5_data ticket;
+ krb5_data second_ticket;
+ krb5_pointer **authdata;
+} krb5_creds;
+
+typedef krb5_pointer krb5_principal;
+
+#define KRB5_CC_END 336760974
+#define KRB5_TC_OPENCLOSE 0x00000001
+
+/* Ticket flags */
+/* flags are 32 bits; each host is responsible to put the 4 bytes
+ representing these bits into net order before transmission */
+/* #define TKT_FLG_RESERVED 0x80000000 */
+#define TKT_FLG_FORWARDABLE 0x40000000
+#define TKT_FLG_FORWARDED 0x20000000
+#define TKT_FLG_PROXIABLE 0x10000000
+#define TKT_FLG_PROXY 0x08000000
+#define TKT_FLG_MAY_POSTDATE 0x04000000
+#define TKT_FLG_POSTDATED 0x02000000
+#define TKT_FLG_INVALID 0x01000000
+#define TKT_FLG_RENEWABLE 0x00800000
+#define TKT_FLG_INITIAL 0x00400000
+#define TKT_FLG_PRE_AUTH 0x00200000
+#define TKT_FLG_HW_AUTH 0x00100000
+#ifdef PK_INIT
+#define TKT_FLG_PUBKEY_PREAUTH 0x00080000
+#define TKT_FLG_DIGSIGN_PREAUTH 0x00040000
+#define TKT_FLG_PRIVKEY_PREAUTH 0x00020000
+#endif
+
+
+#define krb5_cc_get_principal(cache, principal) (*(cache)->ops->get_princ)(cache, principal)
+#define krb5_cc_set_flags(cache, flags) (*(cache)->ops->set_flags)(cache, flags)
+#define krb5_cc_get_name(cache) (*(cache)->ops->get_name)(cache)
+#define krb5_cc_start_seq_get(cache, cursor) (*(cache)->ops->get_first)(cache, cursor)
+#define krb5_cc_next_cred(cache, cursor, creds) (*(cache)->ops->get_next)(cache, cursor, creds)
+#define krb5_cc_destroy(cache) (*(cache)->ops->destroy)(cache)
+#define krb5_cc_end_seq_get(cache, cursor) (*(cache)->ops->end_get)(cache, cursor)
+
+/* end of k5 dummy typedefs */
+
diff --git a/third_party/heimdal/appl/dceutils/k5dcecon.c b/third_party/heimdal/appl/dceutils/k5dcecon.c
new file mode 100644
index 0000000..c905625
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/k5dcecon.c
@@ -0,0 +1,792 @@
+/*
+ * (c) Copyright 1995 HEWLETT-PACKARD COMPANY
+ *
+ * To anyone who acknowledges that this file is provided
+ * "AS IS" without any express or implied warranty:
+ * permission to use, copy, modify, and distribute this
+ * file for any purpose is hereby granted without fee,
+ * provided that the above copyright notice and this
+ * notice appears in all copies, and that the name of
+ * Hewlett-Packard Company not be used in advertising or
+ * publicity pertaining to distribution of the software
+ * without specific, written prior permission. Hewlett-
+ * Packard Company makes no representations about the
+ * suitability of this software for any purpose.
+ *
+ */
+/*
+ * k5dcecon - Program to convert a K5 TGT to a DCE context,
+ * for use with DFS and its PAG.
+ *
+ * The program is designed to be called as a sub process,
+ * and return via stdout the name of the cache which implies
+ * the PAG which should be used. This program itself does not
+ * use the cache or PAG itself, so the PAG in the kernel for
+ * this program may not be set.
+ *
+ * The calling program can then use the name of the cache
+ * to set the KRB5CCNAME and PAG for itself and its children.
+ *
+ * If no ticket was passed, an attemplt to join an existing
+ * PAG will be made.
+ *
+ * If a forwarded K5 TGT is passed in, either a new DCE
+ * context will be created, or an existing one will be updated.
+ * If the same ticket was already used to create an existing
+ * context, it will be joined instead.
+ *
+ * Parts of this program are based on k5dceauth,c which was
+ * given to me by HP and by the k5dcelogin.c which I developed.
+ * A slightly different version of k5dcelogin.c, was added to
+ * DCE 1.2.2
+ *
+ * D. E. Engert 6/17/97 ANL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <locale.h>
+#include <pwd.h>
+#include <string.h>
+#include <time.h>
+
+#include <errno.h>
+#include "k5dce.h"
+
+#include <dce/sec_login.h>
+#include <dce/dce_error.h>
+#include <dce/passwd.h>
+
+/* #define DEBUG */
+#if defined(DEBUG)
+#define DEEDEBUG(A) fprintf(stderr,A); fflush(stderr)
+#define DEEDEBUG2(A,B) fprintf(stderr,A,B); fflush(stderr)
+#else
+#define DEEDEBUG(A)
+#define DEEDEBUG2(A,B)
+#endif
+
+#ifdef __hpux
+#define seteuid(A) setresuid(-1,A,-1)
+#endif
+
+
+int k5dcecreate (uid_t, char *, char*, krb5_creds **);
+int k5dcecon (uid_t, char *, char *);
+int k5dcegettgt (krb5_ccache *, char *, char *, krb5_creds **);
+int k5dcematch (uid_t, char *, char *, off_t *, krb5_creds **);
+int k5dcesession (uid_t, char *, krb5_creds **, int *,krb5_flags);
+
+
+char *progname = "k5dcecon";
+static time_t now;
+
+#ifdef notdef
+#ifdef _AIX
+/*---------------------------------------------*/
+ /* AIX with DCE 1.1 does not have the com_err in the libdce.a
+ * do a half hearted job of substituting for it.
+ */
+void com_err(char *p1, int code, ...)
+{
+ int lst;
+ dce_error_string_t err_string;
+ dce_error_inq_text(code, err_string, &lst);
+ fprintf(stderr,"Error %d in %s: %s\n", code, p1, err_string );
+}
+
+/*---------------------------------------------*/
+void krb5_init_ets()
+{
+
+}
+#endif
+#endif
+
+
+/*------------------------------------------------*/
+/* find a cache to use for our new pag */
+/* Since there is no simple way to determine which
+ * caches are associated with a pag, we will have
+ * do look around and see what makes most sense on
+ * different systems.
+ * on a Solaris system, and in the DCE source,
+ * the pags always start with a 41.
+ * this is not true on the IBM, where there does not
+ * appear to be any pattern.
+ *
+ * But since we are always certifing our creds when
+ * they are received, we can us that fact, and look
+ * at the first word of the associated data file
+ * to see that it has a "5". If not don't use.
+ */
+
+int k5dcesession(luid, pname, tgt, ppag, tflags)
+ uid_t luid;
+ char *pname;
+ krb5_creds **tgt;
+ int *ppag;
+ krb5_flags tflags;
+{
+ DIR *dirp;
+ struct dirent *direntp;
+ off_t size;
+ krb5_timestamp endtime;
+ int better = 0;
+ krb5_creds *xtgt;
+
+ char prev_name[17] = "";
+ krb5_timestamp prev_endtime;
+ off_t prev_size;
+ u_long prev_pag = 0;
+
+ char ccname[64] = "FILE:/opt/dcelocal/var/security/creds/";
+
+ error_status_t st;
+ sec_login_handle_t lcontext = 0;
+ dce_error_string_t err_string;
+ int lst;
+
+ DEEDEBUG2("k5dcesession looking for flags %8.8x\n",tflags);
+
+ dirp = opendir("/opt/dcelocal/var/security/creds/");
+ if (dirp == NULL) {
+ return 1;
+ }
+
+ while ( (direntp = readdir( dirp )) != NULL ) {
+
+/*
+ * (but root has the ffffffff which we are not interested in)
+ */
+ if (strncmp(direntp->d_name,"dcecred_",8) == 0 &&
+ (strlen(direntp->d_name) == 16)) {
+
+ /* looks like a cache name, lets do the stat, etc */
+
+ strcpy(ccname+38,direntp->d_name);
+ if (!k5dcematch(luid, pname, ccname, &size, &xtgt)) {
+
+ /* it's one of our caches, see if it is better
+ * i.e. the endtime is farther, and if the endtimes
+ * are the same, take the larger, as he who has the
+ * most tickets wins.
+ * it must also had the same set of flags at least
+ * i.e. if the forwarded TGT is forwardable, this one must
+ * be as well.
+ */
+
+ DEEDEBUG2("Cache:%s",direntp->d_name);
+ DEEDEBUG2(" size:%d",size);
+ DEEDEBUG2(" flags:%8.8x",xtgt->ticket_flags);
+ DEEDEBUG2(" %s",ctime((time_t *)&xtgt->times.endtime));
+
+ if ((xtgt->ticket_flags & tflags) == tflags ) {
+ if (prev_name[0]) {
+ if (xtgt->times.endtime > prev_endtime) {
+ better = 1;
+ } else if ((xtgt->times.endtime = prev_endtime)
+ && (size > prev_size)){
+ better = 1;
+ }
+ } else { /* the first */
+ if (xtgt->times.endtime >= now) {
+ better = 1;
+ }
+ }
+ if (better) {
+ strcpy(prev_name, direntp->d_name);
+ prev_endtime = xtgt->times.endtime;
+ prev_size = size;
+ sscanf(prev_name+8,"%8X",&prev_pag);
+ *tgt = xtgt;
+ better = 0;
+ }
+ }
+ }
+ }
+ }
+ (void)closedir( dirp );
+
+ if (!prev_name[0])
+ return 1; /* failed to find one */
+
+ DEEDEBUG2("Best: %s\n",prev_name);
+
+ if (ppag)
+ *ppag = prev_pag;
+
+ strcpy(ccname+38,prev_name);
+ setenv("KRB5CCNAME",ccname,1);
+
+ return(0);
+}
+
+
+/*----------------------------------------------*/
+/* see if this cache is for this this principal */
+
+int k5dcematch(luid, pname, ccname, sizep, tgt)
+ uid_t luid;
+ char *pname;
+ char *ccname;
+ off_t *sizep; /* size of the file */
+ krb5_creds **tgt;
+{
+
+ krb5_ccache cache;
+ struct stat stbuf;
+ char ccdata[256];
+ int fd;
+ int status;
+
+ /* DEEDEBUG2("k5dcematch called: cache=%s\n",ccname+38); */
+
+ if (strncmp(ccname,"FILE:",5) == 0) {
+
+ strcpy(ccdata,ccname+5);
+ strcat(ccdata,".data");
+
+ /* DEEDEBUG2("Checking the .data file for %s\n",ccdata); */
+
+ if (stat(ccdata, &stbuf))
+ return(1);
+
+ if (stbuf.st_uid != luid)
+ return(1);
+
+ if ((fd = open(ccdata,O_RDONLY)) == -1)
+ return(1);
+
+ if ((read(fd,&status,4)) != 4) {
+ close(fd);
+ return(1);
+ }
+
+ /* DEEDEBUG2(".data file status = %d\n", status); */
+
+ if (status != 5)
+ return(1);
+
+ if (stat(ccname+5, &stbuf))
+ return(1);
+
+ if (stbuf.st_uid != luid)
+ return(1);
+
+ *sizep = stbuf.st_size;
+ }
+
+ return(k5dcegettgt(&cache, ccname, pname, tgt));
+}
+
+
+/*----------------------------------------*/
+/* k5dcegettgt - get the tgt from a cache */
+
+int k5dcegettgt(pcache, ccname, pname, tgt)
+ krb5_ccache *pcache;
+ char *ccname;
+ char *pname;
+ krb5_creds **tgt;
+
+{
+ krb5_ccache cache;
+ krb5_cc_cursor cur;
+ krb5_creds creds;
+ int code;
+ int found = 1;
+ krb5_principal princ;
+ char *kusername;
+ krb5_flags flags;
+ char *sname, *realm, *tgtname = NULL;
+
+ /* Since DCE does not expose much of the Kerberos interface,
+ * we will have to use what we can. This means setting the
+ * KRB5CCNAME for each file we want to test
+ * We will also not worry about freeing extra cache structures
+ * as this this routine is also not exposed, and this should not
+ * effect this module.
+ * We should also free the creds contents, but that is not exposed
+ * either.
+ */
+
+ setenv("KRB5CCNAME",ccname,1);
+ cache = NULL;
+ *tgt = NULL;
+
+ if (code = krb5_cc_default(pcache)) {
+ com_err(progname, code, "while getting ccache");
+ goto return2;
+ }
+
+ DEEDEBUG("Got cache\n");
+ flags = 0;
+ if (code = krb5_cc_set_flags(*pcache, flags)) {
+ com_err(progname, code,"While setting flags");
+ goto return2;
+ }
+ DEEDEBUG("Set flags\n");
+ if (code = krb5_cc_get_principal(*pcache, &princ)) {
+ com_err(progname, code, "While getting princ");
+ goto return1;
+ }
+ DEEDEBUG("Got principal\n");
+ if (code = krb5_unparse_name(princ, &kusername)) {
+ com_err(progname, code, "While unparsing principal");
+ goto return1;
+ }
+
+ DEEDEBUG2("Unparsed to \"%s\"\n", kusername);
+ DEEDEBUG2("pname is \"%s\"\n", pname);
+ if (strcmp(kusername, pname) != 0) {
+ DEEDEBUG("Principals not equal\n");
+ goto return1;
+ }
+ DEEDEBUG("Principals equal\n");
+
+ realm = strchr(pname,'@');
+ realm++;
+
+ if ((tgtname = malloc(9 + 2 * strlen(realm))) == 0) {
+ fprintf(stderr,"Malloc failed for tgtname\n");
+ goto return1;
+ }
+
+ strcpy(tgtname,"krbtgt/");
+ strcat(tgtname,realm);
+ strcat(tgtname,"@");
+ strcat(tgtname,realm);
+
+ DEEDEBUG2("Getting tgt %s\n", tgtname);
+ if (code = krb5_cc_start_seq_get(*pcache, &cur)) {
+ com_err(progname, code, "while starting to retrieve tickets");
+ goto return1;
+ }
+
+ while (!(code = krb5_cc_next_cred(*pcache, &cur, &creds))) {
+ krb5_creds *cred = &creds;
+
+ if (code = krb5_unparse_name(cred->server, &sname)) {
+ com_err(progname, code, "while unparsing server name");
+ continue;
+ }
+
+ if (strncmp(sname, tgtname, strlen(tgtname)) == 0) {
+ DEEDEBUG("FOUND\n");
+ if (code = krb5_copy_creds(&creds, tgt)) {
+ com_err(progname, code, "while copying TGT");
+ goto return1;
+ }
+ found = 0;
+ break;
+ }
+ /* we should do a krb5_free_cred_contents(creds); */
+ }
+
+ if (code = krb5_cc_end_seq_get(*pcache, &cur)) {
+ com_err(progname, code, "while finishing retrieval");
+ goto return2;
+ }
+
+return1:
+ flags = KRB5_TC_OPENCLOSE;
+ krb5_cc_set_flags(*pcache, flags); /* force a close */
+
+return2:
+ if (tgtname)
+ free(tgtname);
+
+ return(found);
+}
+
+
+/*------------------------------------------*/
+/* Convert a forwarded TGT to a DCE context */
+int k5dcecon(luid, luser, pname)
+ uid_t luid;
+ char *luser;
+ char *pname;
+{
+
+ krb5_creds *ftgt = NULL;
+ krb5_creds *tgt = NULL;
+ unsigned32 dfspag;
+ boolean32 reset_passwd = 0;
+ int lst;
+ dce_error_string_t err_string;
+ char *shell_prog;
+ krb5_ccache fcache;
+ char *ccname;
+ char *kusername;
+ char *urealm;
+ char *cp;
+ int pag;
+ int code;
+ krb5_timestamp endtime;
+
+
+ /* If there is no cache to be converted, we should not be here */
+
+ if ((ccname = getenv("KRB5CCNAME")) == NULL) {
+ DEEDEBUG("No KRB5CCNAME\n");
+ return(1);
+ }
+
+ if (k5dcegettgt(&fcache, ccname, pname, &ftgt)) {
+ fprintf(stderr, "%s: Did not find TGT\n", progname);
+ return(1);
+ }
+
+
+ DEEDEBUG2("flags=%x\n",ftgt->ticket_flags);
+ if (!(ftgt->ticket_flags & TKT_FLG_FORWARDABLE)){
+ fprintf(stderr,"Ticket not forwardable\n");
+ return(0); /* but OK to continue */
+ }
+
+ setenv("KRB5CCNAME","",1);
+
+#define TKT_ACCEPTABLE (TKT_FLG_FORWARDABLE | TKT_FLG_PROXIABLE \
+ | TKT_FLG_MAY_POSTDATE | TKT_FLG_RENEWABLE | TKT_FLG_HW_AUTH \
+ | TKT_FLG_PRE_AUTH)
+
+ if (!k5dcesession(luid, pname, &tgt, &pag,
+ (ftgt->ticket_flags & TKT_ACCEPTABLE))) {
+ if (ftgt->times.endtime > tgt->times.endtime) {
+ DEEDEBUG("Updating existing cache\n");
+ return(k5dceupdate(&ftgt, pag));
+ } else {
+ DEEDEBUG("Using existing cache\n");
+ return(0); /* use the original one */
+ }
+ }
+ /* see if the tgts match up */
+
+ if ((code = k5dcecreate(luid, luser, pname, &ftgt))) {
+ return (code);
+ }
+
+ /*
+ * Destroy the Kerberos5 cred cache file.
+ * but don't care about the return code.
+ */
+
+ DEEDEBUG("Destroying the old cache\n");
+ if ((code = krb5_cc_destroy(fcache))) {
+ com_err(progname, code, "while destroying Kerberos5 ccache");
+ }
+ return (0);
+}
+
+
+/*--------------------------------------------------*/
+/* k5dceupdate - update the cache with a new TGT */
+/* Assumed that the KRB5CCNAME has been set */
+
+int k5dceupdate(krbtgt, pag)
+ krb5_creds **krbtgt;
+ int pag;
+{
+
+ krb5_ccache ccache;
+ int code;
+
+ if (code = krb5_cc_default(&ccache)) {
+ com_err(progname, code, "while opening cache for update");
+ return(2);
+ }
+
+ if (code = ccache->ops->init(ccache,(*krbtgt)->client)) {
+ com_err(progname, code, "while reinitilizing cache");
+ return(3);
+ }
+
+ /* krb5_cc_store_cred */
+ if (code = ccache->ops->store(ccache, *krbtgt)) {
+ com_err(progname, code, "while updating cache");
+ return(2);
+ }
+
+ sec_login_pag_new_tgt(pag, (*krbtgt)->times.endtime);
+ return(0);
+}
+/*--------------------------------------------------*/
+/* k5dcecreate - create a new DCE context */
+
+int k5dcecreate(luid, luser, pname, krbtgt)
+ uid_t luid;
+ char *luser;
+ char *pname;
+ krb5_creds **krbtgt;
+{
+
+ char *cp;
+ char *urealm;
+ char *username;
+ char *defrealm;
+ uid_t uid;
+
+ error_status_t st;
+ sec_login_handle_t lcontext = 0;
+ sec_login_auth_src_t auth_src = 0;
+ boolean32 reset_passwd = 0;
+ int lst;
+ dce_error_string_t err_string;
+
+ setenv("KRB5CCNAME","",1); /* make sure it not misused */
+
+ uid = getuid();
+ DEEDEBUG2("uid=%d\n",uid);
+
+ /* if run as root, change to user, so as to have the
+ * cache created for the local user even if cross-cell
+ * If run as a user, let standard file protection work.
+ */
+
+ if (uid == 0) {
+ if (seteuid(luid) < 0)
+ goto abort;
+ }
+
+ cp = strchr(pname,'@');
+ *cp = '\0';
+ urealm = ++cp;
+
+ DEEDEBUG2("basename=%s\n",cp);
+ DEEDEBUG2("realm=%s\n",urealm);
+
+ /* now build the username as a single string or a /.../cell/user
+ * if this is a cross cell
+ */
+
+ if ((username = malloc(7+strlen(pname)+strlen(urealm))) == 0) {
+ fprintf(stderr,"Malloc failed for username\n");
+ goto abort;
+ }
+ if (krb5_get_default_realm(&defrealm)) {
+ DEEDEBUG("krb5_get_default_realm failed\n");
+ goto abort;
+ }
+
+
+ if (strcmp(urealm,defrealm) == 0) {
+ strcpy(username,pname);
+ } else {
+ strcpy(username,"/.../");
+ strcat(username,urealm);
+ strcat(username,"/");
+ strcat(username,pname);
+ }
+
+ /*
+ * Setup a DCE login context
+ */
+
+ if (sec_login_setup_identity((unsigned_char_p_t)username,
+ (sec_login_external_tgt|sec_login_proxy_cred),
+ &lcontext, &st)) {
+ /*
+ * Add our TGT.
+ */
+ DEEDEBUG("Adding our new TGT\n");
+ sec_login_krb5_add_cred(lcontext, *krbtgt, &st);
+ if (st) {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Error while adding credentials for %s because %s\n",
+ username, err_string);
+ goto abort;
+ }
+ DEEDEBUG("validating and certifying\n");
+ /*
+ * Now "validate" and certify the identity,
+ * usually we would pass a password here, but...
+ * sec_login_valid_and_cert_ident
+ * sec_login_validate_identity
+ */
+
+ if (sec_login_validate_identity(lcontext, 0, &reset_passwd,
+ &auth_src, &st)) {
+ DEEDEBUG2("validate_identity st=%d\n",st);
+ if (st) {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr, "Validation error for %s because %s\n",
+ username, err_string);
+ goto abort;
+ }
+ if (!sec_login_certify_identity(lcontext,&st)) {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Credentials not certified because %s\n",err_string);
+ }
+ if (reset_passwd) {
+ fprintf(stderr,
+ "Password must be changed for %s\n", username);
+ }
+ if (auth_src == sec_login_auth_src_local) {
+ fprintf(stderr,
+ "Credentials obtained from local registry for %s\n",
+ username);
+ }
+ if (auth_src == sec_login_auth_src_overridden) {
+ fprintf(stderr, "Validated %s from local override entry, no network credentials obtained\n", username);
+ goto abort;
+
+ }
+ /*
+ * Actually create the cred files.
+ */
+ DEEDEBUG("Ceating new cred files.\n");
+ sec_login_set_context(lcontext, &st);
+ if (st) {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Unable to set context for %s because %s\n",
+ username, err_string);
+ goto abort;
+ }
+
+ /*
+ * Now free up the local context and leave the
+ * network context with its pag
+ */
+#if 0
+ sec_login_release_context(&lcontext, &st);
+ if (st) {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Unable to release context for %s because %s\n",
+ username, err_string);
+ goto abort;
+ }
+#endif
+ }
+ else {
+ DEEDEBUG2("validate failed %d\n",st);
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Unable to validate %s because %s\n", username,
+ err_string);
+ goto abort;
+ }
+ }
+ else {
+ dce_error_inq_text(st, err_string, &lst);
+ fprintf(stderr,
+ "Unable to setup login entry for %s because %s\n",
+ username, err_string);
+ goto abort;
+ }
+
+ done:
+ /* if we were root, get back to root */
+
+ DEEDEBUG2("sec_login_inq_pag %8.8x\n",
+ sec_login_inq_pag(lcontext, &st));
+
+ if (uid == 0) {
+ seteuid(0);
+ }
+
+ DEEDEBUG("completed\n");
+ return(0);
+
+ abort:
+ if (uid == 0) {
+ seteuid(0);
+ }
+
+ DEEDEBUG("Aborting\n");
+ return(2);
+}
+
+
+
+/*-------------------------------------------------*/
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int status;
+ extern int optind;
+ extern char *optarg;
+ int rv;
+
+ char *lusername = NULL;
+ char *pname = NULL;
+ int fflag = 0;
+ struct passwd *pw;
+ uid_t luid;
+ uid_t myuid;
+ char *ccname;
+ krb5_creds *tgt = NULL;
+
+#ifdef DEBUG
+ close(2);
+ open("/tmp/k5dce.debug",O_WRONLY|O_CREAT|O_APPEND, 0600);
+#endif
+
+ if (myuid = getuid()) {
+ DEEDEBUG2("UID = %d\n",myuid);
+ exit(33); /* must be root to run this, get out now */
+ }
+
+ while ((rv = getopt(argc,argv,"l:p:fs")) != -1) {
+ DEEDEBUG2("Arg = %c\n", rv);
+ switch(rv) {
+ case 'l': /* user name */
+ lusername = optarg;
+ DEEDEBUG2("Optarg = %s\n", optarg);
+ break;
+ case 'p': /* principal name */
+ pname = optarg;
+ DEEDEBUG2("Optarg = %s\n", optarg);
+ break;
+ case 'f': /* convert a forwarded TGT to a context */
+ fflag++;
+ break;
+ case 's': /* old test parameter, ignore it */
+ break;
+ }
+ }
+
+ setlocale(LC_ALL, "");
+ krb5_init_ets();
+ time(&now); /* set time to check expired tickets */
+
+ /* if lusername == NULL, Then user is passed as the USER= variable */
+
+ if (!lusername) {
+ lusername = getenv("USER");
+ if (!lusername) {
+ fprintf(stderr, "USER not in environment\n");
+ return(3);
+ }
+ }
+
+ if ((pw = getpwnam(lusername)) == NULL) {
+ fprintf(stderr, "Who are you?\n");
+ return(44);
+ }
+
+ luid = pw->pw_uid;
+
+ if (fflag) {
+ status = k5dcecon(luid, lusername, pname);
+ } else {
+ status = k5dcesession(luid, pname, &tgt, NULL, 0);
+ }
+
+ if (!status) {
+ printf("%s",getenv("KRB5CCNAME")); /* return via stdout to caller */
+ DEEDEBUG2("KRB5CCNAME=%s\n",getenv("KRB5CCNAME"));
+ }
+
+ DEEDEBUG2("Returning status %d\n",status);
+ return (status);
+}
diff --git a/third_party/heimdal/appl/dceutils/testpag.c b/third_party/heimdal/appl/dceutils/testpag.c
new file mode 100644
index 0000000..8c9bf4a
--- /dev/null
+++ b/third_party/heimdal/appl/dceutils/testpag.c
@@ -0,0 +1,150 @@
+/* Test the k5dcepag routine by setting a pag, and
+ * and execing a shell under this pag.
+ *
+ * This allows you to join a PAG which was created
+ * earlier by some other means.
+ * for example k5dcecon
+ *
+ * Must be run as root for testing only.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <errno.h>
+
+#define POSIX_SETJMP
+#define POSIX_SIGNALS
+
+#ifdef POSIX_SIGNALS
+typedef struct sigaction handler;
+#define handler_init(H,F) (sigemptyset(&(H).sa_mask), \
+ (H).sa_flags=0, \
+ (H).sa_handler=(F))
+#define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD)
+#define handler_set(S,OLD) sigaction(S, &OLD, NULL)
+#else
+typedef sigtype (*handler)();
+#define handler_init(H,F) ((H) = (F))
+#define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW)))
+
+#define handler_set(S,OLD) (signal ((S), (OLD)))
+#endif
+
+typedef void sigtype;
+
+/*
+ * We could include the dcedfs/syscall.h which should have these
+ * numbers, but it has extra baggage. So for
+ * simplicity sake now, we define these here.
+ */
+
+
+#define AFSCALL_SETPAG 2
+#define AFSCALL_GETPAG 11
+
+#if defined(sun)
+#define AFS_SYSCALL 72
+
+#elif defined(hpux)
+/* assume HPUX 10 + or is it 50 */
+#define AFS_SYSCALL 326
+
+#elif defined(_AIX)
+#define DPAGAIX "dpagaix"
+/* #define DPAGAIX "/krb5/sbin/dpagaix" */
+
+#elif defined(sgi) || defined(_sgi)
+#define AFS_SYSCALL 206+1000
+
+#else
+#define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL)
+#endif
+
+static sigjmp_buf setpag_buf;
+
+static sigtype mysig()
+{
+ siglongjmp(setpag_buf, 1);
+}
+
+
+int krb5_dfs_newpag(new_pag)
+ int new_pag;
+{
+ handler sa1, osa1;
+ handler sa2, osa2;
+ int pag = -1;
+
+ handler_init (sa1, mysig);
+ handler_init (sa2, mysig);
+ handler_swap (SIGSYS, sa1, osa1);
+ handler_swap (SIGSEGV, sa2, osa2);
+
+ if (sigsetjmp(setpag_buf, 1) == 0) {
+#if defined(_AIX)
+ int (*dpagaix)(int, int, int, int, int, int);
+
+ if (dpagaix = load(DPAGAIX, 0, 0))
+ pag = (*dpagaix)(AFSCALL_SETPAG, new_pag, 0, 0, 0, 0);
+#else
+ pag = syscall(AFS_SYSCALL,AFSCALL_SETPAG, new_pag, 0, 0, 0, 0);
+#endif
+ handler_set (SIGSYS, osa1);
+ handler_set (SIGSEGV, osa2);
+ return(pag);
+ }
+
+ fprintf(stderr,"Setpag failed with a system error\n");
+ /* syscall failed! return 0 */
+ handler_set (SIGSYS, osa1);
+ handler_set (SIGSEGV, osa2);
+ return(-1);
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int rv;
+ int rc;
+ unsigned int pag;
+ unsigned int newpag = 0;
+ char ccname[256];
+ int nflag = 0;
+
+ while((rv = getopt(argc,argv,"n:")) != -1) {
+ switch(rv) {
+ case 'n':
+ nflag++;
+ sscanf(optarg,"%8x",&newpag);
+ break;
+ default:
+ printf("Usage: k5dcepagt -n pag \n");
+ exit(1);
+ }
+ }
+
+ if (nflag) {
+ fprintf (stderr,"calling k5dcepag newpag=%8.8x\n",newpag);
+ pag = krb5_dfs_newpag(newpag);
+
+ fprintf (stderr,"PAG returned = %8.8x\n",pag);
+ if ((pag != 0) && (pag != -1)) {
+ sprintf (ccname,
+ "FILE:/opt/dcelocal/var/security/creds/dcecred_%8.8x",
+ pag);
+ esetenv("KRB5CCNAME",ccname,1);
+ execl("/bin/csh", "csh", NULL);
+ }
+ else {
+ fprintf(stderr," Not a good pag value\n");
+ }
+ }
+}
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..8d7d8fa
--- /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..44b59fe
--- /dev/null
+++ b/third_party/heimdal/appl/gssmask/gssmask.c
@@ -0,0 +1,1268 @@
+/*
+ * 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[256] = "unknown", *str;
+ int ret;
+
+ if (targetname)
+ cap |= ISSERVER; /* is server */
+
+#ifdef HAVE_UNAME
+ {
+ struct utsname ut;
+ if (uname(&ut) == 0) {
+ snprintf(name, sizeof(name), "%s-%s-%s",
+ ut.sysname, ut.version, ut.machine);
+ }
+ }
+#endif
+
+ ret = asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
+ if (ret == -1)
+ errx(1, "out of memory");
+
+ put32(c, GSSMAGGOTPROTOCOL);
+ put32(c, cap);
+ putstring(c, str);
+ free(str);
+
+ 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
+ */
+};
diff --git a/third_party/heimdal/appl/kf/Makefile.am b/third_party/heimdal/appl/kf/Makefile.am
new file mode 100644
index 0000000..0b38057
--- /dev/null
+++ b/third_party/heimdal/appl/kf/Makefile.am
@@ -0,0 +1,20 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+bin_PROGRAMS = kf
+
+libexec_PROGRAMS = kfd
+
+man_MANS = kf.1 kfd.8
+
+kf_SOURCES = kf.c kf_locl.h
+
+kfd_SOURCES = kfd.c kf_locl.h
+
+LDADD = $(top_builddir)/lib/krb5/libkrb5.la \
+ $(LIB_hcrypto) \
+ $(top_builddir)/lib/asn1/libasn1.la \
+ $(LIB_roken)
+
+EXTRA_DIST = NTMakefile $(man_MANS)
diff --git a/third_party/heimdal/appl/kf/NTMakefile b/third_party/heimdal/appl/kf/NTMakefile
new file mode 100644
index 0000000..6ade4ab
--- /dev/null
+++ b/third_party/heimdal/appl/kf/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\kf
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/kf/kf.1 b/third_party/heimdal/appl/kf/kf.1
new file mode 100644
index 0000000..290e6bb
--- /dev/null
+++ b/third_party/heimdal/appl/kf/kf.1
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd July 2, 2000
+.Dt KF 1
+.Os
+.Sh NAME
+.Nm kf
+.Nd securely forward tickets
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl p Ar port |
+.Fl Fl port Ns = Ns Ar port
+.Oc
+.Oo
+.Fl l Ar login |
+.Fl Fl login Ns = Ns Ar login
+.Oc
+.Oo
+.Fl c Ar ccache |
+.Fl Fl ccache Ns = Ns Ar ccache
+.Oc
+.Op Fl F | -forwardable
+.Op Fl G | -no-forwardable
+.Op Fl h | -help
+.Op Fl Fl version
+.Ar host ...
+.Sh DESCRIPTION
+The
+.Nm
+program forwards tickets to a remote host through an authenticated
+and encrypted stream.
+Options supported are:
+.Bl -tag -width indent
+.It Xo
+.Fl p Ar port ,
+.Fl Fl port Ns = Ns Ar port
+.Xc
+port to connect to
+.It Xo
+.Fl l Ar login ,
+.Fl Fl login Ns = Ns Ar login
+.Xc
+remote login name
+.It Xo
+.Fl c Ar ccache ,
+.Fl Fl ccache Ns = Ns Ar ccache
+.Xc
+remote cred cache
+.It Fl F , -forwardable
+forward forwardable credentials
+.It Fl G , -no-forwardable
+do not forward forwardable credentials
+.It Fl h , -help
+.It Fl Fl version
+.El
+.Pp
+.Nm
+is useful when you do not want to enter your password on a remote host
+but want to have your tickets one for example AFS.
+.Pp
+In order for
+.Nm
+to work you will need to acquire your initial ticket with forwardable
+flag, i.e.
+.Nm kinit Fl Fl forwardable .
+.Pp
+.Nm telnet
+is able to forward tickets by itself.
+.\".Sh ENVIRONMENT
+.\".Sh FILES
+.\".Sh EXAMPLES
+.\".Sh DIAGNOSTICS
+.Sh SEE ALSO
+.Xr kinit 1 ,
+.Xr telnet 1 ,
+.Xr kfd 8
+.\".Sh STANDARDS
+.\".Sh HISTORY
+.\".Sh AUTHORS
+.\".Sh BUGS
diff --git a/third_party/heimdal/appl/kf/kf.c b/third_party/heimdal/appl/kf/kf.c
new file mode 100644
index 0000000..fd4f174
--- /dev/null
+++ b/third_party/heimdal/appl/kf/kf.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 1997 - 2000, 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kf_locl.h"
+RCSID("$Id$");
+
+krb5_context context;
+static int help_flag;
+static int version_flag;
+static char *port_str;
+const char *service = KF_SERVICE;
+const char *remote_name = NULL;
+int forwardable = 0;
+const char *ccache_name = NULL;
+
+static struct getargs args[] = {
+ { "port", 'p', arg_string, &port_str, "port to connect to", "port" },
+ { "login", 'l',arg_string, &remote_name,"remote login name","login"},
+ { "ccache", 'c',arg_string, &ccache_name, "remote cred cache","ccache"},
+ { "forwardable",'F',arg_flag,&forwardable,
+ "Forward forwardable credentials", NULL },
+ { "forwardable",'G',arg_negative_flag,&forwardable,
+ "Don't forward forwardable credentials", NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code, struct getargs *inargs, int num_inargs)
+{
+ arg_printusage(inargs, num_inargs, NULL, "hosts");
+ exit(code);
+}
+
+static int
+client_setup(krb5_context *ctx, int *argc, char **argv)
+{
+ int optidx = 0;
+ int port = 0;
+ int status;
+
+ setprogname (argv[0]);
+
+ status = krb5_init_context (ctx);
+ if (status)
+ errx(1, "krb5_init_context failed: %d", status);
+
+ forwardable = krb5_config_get_bool (*ctx, NULL,
+ "libdefaults",
+ "forwardable",
+ NULL);
+
+ if (getarg (args, num_args, *argc, argv, &optidx))
+ usage(1, args, num_args);
+
+ if(help_flag)
+ usage (0, args, num_args);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(port_str) {
+ struct servent *s = roken_getservbyname(port_str, "tcp");
+ if(s)
+ port = s->s_port;
+ else {
+ char *ptr;
+
+ port = strtol (port_str, &ptr, 10);
+ if (port == 0 && ptr == port_str)
+ errx (1, "Bad port `%s'", port_str);
+ port = htons(port);
+ }
+ }
+
+ if (port == 0)
+ port = krb5_getportbyname (*ctx, KF_PORT_NAME, "tcp", KF_PORT_NUM);
+
+ if(*argc - optidx < 1)
+ usage(1, args, num_args);
+ *argc = optidx;
+
+ return port;
+}
+
+/*
+ * forward creds to `hostname'/`service' over `sock'
+ * return 0 iff OK
+ */
+
+static int
+proto (int sock, const char *hostname, const char *svc,
+ char *message, size_t len)
+{
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_principal server;
+ krb5_data data;
+ krb5_data data_send;
+
+ krb5_ccache ccache;
+ krb5_creds creds;
+ krb5_kdc_flags flags;
+ krb5_principal principal;
+
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status) {
+ krb5_warn (context, status, "krb5_auth_con_init");
+ return 1;
+ }
+
+ status = krb5_auth_con_setaddrs_from_fd (context,
+ auth_context,
+ &sock);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_auth_con_setaddr");
+ return 1;
+ }
+
+ status = krb5_sname_to_principal (context,
+ hostname,
+ svc,
+ KRB5_NT_SRV_HST,
+ &server);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_sname_to_principal");
+ return 1;
+ }
+
+ status = krb5_sendauth (context,
+ &auth_context,
+ &sock,
+ KF_VERSION_1,
+ NULL,
+ server,
+ AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn(context, status, "krb5_sendauth");
+ return 1;
+ }
+
+ if (ccache_name == NULL)
+ ccache_name = "";
+
+ data_send.data = (void *)remote_name;
+ data_send.length = strlen(remote_name) + 1;
+ status = krb5_write_priv_message(context, auth_context, &sock, &data_send);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_write_message");
+ return 1;
+ }
+ data_send.data = (void *)ccache_name;
+ data_send.length = strlen(ccache_name)+1;
+ status = krb5_write_priv_message(context, auth_context, &sock, &data_send);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_write_message");
+ return 1;
+ }
+
+ memset (&creds, 0, sizeof(creds));
+
+ status = krb5_cc_default (context, &ccache);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_cc_default");
+ return 1;
+ }
+
+ status = krb5_cc_get_principal (context, ccache, &principal);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_cc_get_principal");
+ return 1;
+ }
+
+ creds.client = principal;
+
+ status = krb5_make_principal (context,
+ &creds.server,
+ principal->realm,
+ KRB5_TGS_NAME,
+ principal->realm,
+ NULL);
+
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_make_principal");
+ return 1;
+ }
+
+ creds.times.endtime = 0;
+
+ flags.i = 0;
+ flags.b.forwarded = 1;
+ flags.b.forwardable = forwardable;
+
+ status = krb5_get_forwarded_creds (context,
+ auth_context,
+ ccache,
+ flags.i,
+ hostname,
+ &creds,
+ &data);
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_get_forwarded_creds");
+ return 1;
+ }
+
+ status = krb5_write_priv_message(context, auth_context, &sock, &data);
+
+ if (status) {
+ krb5_auth_con_free(context, auth_context);
+ krb5_warn (context, status, "krb5_mk_priv");
+ return 1;
+ }
+
+ krb5_data_free (&data);
+
+ status = krb5_read_priv_message(context, auth_context, &sock, &data);
+ krb5_auth_con_free(context, auth_context);
+ if (status) {
+ krb5_warn (context, status, "krb5_mk_priv");
+ return 1;
+ }
+ if(data.length >= len) {
+ krb5_warnx (context, "returned string is too long, truncating");
+ memcpy(message, data.data, len);
+ message[len - 1] = '\0';
+ } else {
+ memcpy(message, data.data, data.length);
+ message[data.length] = '\0';
+ }
+ krb5_data_free (&data);
+
+ return strcmp(message, "ok") != 0;
+}
+
+static int
+doit (const char *hostname, int port, const char *svc,
+ char *message, size_t len)
+{
+ struct addrinfo *ai, *a;
+ struct addrinfo hints;
+ int error;
+ char portstr[NI_MAXSERV];
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
+
+ error = getaddrinfo (hostname, portstr, &hints, &ai);
+ if (error) {
+ errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error));
+ }
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ int s;
+
+ s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+ if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
+ warn ("connect(%s)", hostname);
+ close (s);
+ continue;
+ }
+ freeaddrinfo (ai);
+ error = proto(s, hostname, svc, message, len);
+ close(s);
+ return error;
+ }
+ warnx ("failed to contact %s", hostname);
+ freeaddrinfo (ai);
+ return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+ char userbuf[128];
+ int argcc,port,i;
+ int ret=0;
+
+ argcc = argc;
+ port = client_setup(&context, &argcc, argv);
+
+ if (remote_name == NULL) {
+ remote_name = roken_get_username(userbuf, sizeof(userbuf));
+ if (remote_name == NULL)
+ errx (1, "who are you?");
+ }
+
+ for (i = argcc;i < argc; i++) {
+ char message[128];
+ ret = doit (argv[i], port, service, message, sizeof(message));
+ if(ret == 0)
+ warnx ("%s: ok", argv[i]);
+ else
+ warnx ("%s: failed: %s", argv[i], message);
+ }
+ return(ret);
+}
diff --git a/third_party/heimdal/appl/kf/kf_locl.h b/third_party/heimdal/appl/kf/kf_locl.h
new file mode 100644
index 0000000..3ddee48
--- /dev/null
+++ b/third_party/heimdal/appl/kf/kf_locl.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997 - 1999, 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <errno.h>
+#include <roken.h>
+#include <getarg.h>
+#include <err.h>
+#include <krb5.h>
+
+#define KF_SERVICE "host"
+
+#define KF_PORT_NAME "kf"
+#define KF_PORT_NUM 2110
+#define KF_VERSION_1 "KFWDV0.1"
diff --git a/third_party/heimdal/appl/kf/kfd.8 b/third_party/heimdal/appl/kf/kfd.8
new file mode 100644
index 0000000..4b8b822
--- /dev/null
+++ b/third_party/heimdal/appl/kf/kfd.8
@@ -0,0 +1,85 @@
+.\" Copyright (c) 2000 - 2002 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd July 2, 2000
+.Dt KFD 8
+.Os
+.Sh NAME
+.Nm kfd
+.Nd receive forwarded tickets
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl p Ar port |
+.Fl Fl port Ns = Ns Ar port
+.Oc
+.Op Fl i | -inetd
+.Oo
+.Fl R Ar regpag |
+.Fl Fl regpag Ns = Ns Ar regpag
+.Oc
+.Op Fl h | -help
+.Op Fl Fl version
+.Sh DESCRIPTION
+This is the daemon for
+.Xr kf 1 .
+Supported options:
+.Bl -tag -width indent
+.It Xo
+.Fl p Ar port ,
+.Fl Fl port Ns = Ns Ar port
+.Xc
+port to listen to
+.It Fl i , -inetd
+not started from inetd
+.It Xo
+.Fl R Ar regpag ,
+.Fl Fl regpag= Ns Ar regpag
+.Xc
+path to regpag binary
+.El
+.\".Sh ENVIRONMENT
+.\".Sh FILES
+.Sh EXAMPLES
+Put the following in
+.Pa /etc/inetd.conf :
+.Bd -literal
+kf stream tcp nowait root /usr/heimdal/libexec/kfd kfd
+.Ed
+.\".Sh DIAGNOSTICS
+.Sh SEE ALSO
+.Xr kf 1
+.\".Sh STANDARDS
+.\".Sh HISTORY
+.\".Sh AUTHORS
+.\".Sh BUGS
diff --git a/third_party/heimdal/appl/kf/kfd.c b/third_party/heimdal/appl/kf/kfd.c
new file mode 100644
index 0000000..9099bab
--- /dev/null
+++ b/third_party/heimdal/appl/kf/kfd.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kf_locl.h"
+RCSID("$Id$");
+
+krb5_context context;
+char krb5_tkfile[MAXPATHLEN];
+
+static int help_flag;
+static int version_flag;
+static char *port_str;
+char *service = KF_SERVICE;
+int do_inetd = 0;
+static char *regpag_str=NULL;
+
+static struct getargs args[] = {
+ { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
+ { "inetd",'i',arg_flag, &do_inetd,
+ "Not started from inetd", NULL },
+ { "regpag",'R',arg_string,&regpag_str,"path to regpag binary","regpag"},
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code, struct getargs *inargs, int num_inargs)
+{
+ arg_printusage(inargs, num_inargs, NULL, "");
+ exit(code);
+}
+
+static int
+server_setup(krb5_context *ctx, int argc, char **argv)
+{
+ int port = 0;
+ int local_argc;
+
+ local_argc = krb5_program_setup(ctx, argc, argv, args, num_args, usage);
+
+ if(help_flag)
+ (*usage)(0, args, num_args);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(port_str){
+ struct servent *s = roken_getservbyname(port_str, "tcp");
+ if(s)
+ port = s->s_port;
+ else {
+ char *ptr;
+
+ port = strtol (port_str, &ptr, 10);
+ if (port == 0 && ptr == port_str)
+ errx (1, "Bad port `%s'", port_str);
+ port = htons(port);
+ }
+ }
+
+ if (port == 0)
+ port = krb5_getportbyname (*ctx, KF_PORT_NAME, "tcp", KF_PORT_NUM);
+
+ if(argv[local_argc] != NULL)
+ usage(1, args, num_args);
+
+ return port;
+}
+
+static int protocol_version;
+
+static krb5_boolean
+kfd_match_version(const void *arg, const char *version)
+{
+ if(strcmp(version, KF_VERSION_1) == 0) {
+ protocol_version = 1;
+ return TRUE;
+ } else if (strlen(version) == 4 &&
+ version[0] == '0' &&
+ version[1] == '.' &&
+ (version[2] == '4' || version[2] == '3') &&
+ islower((unsigned char)version[3])) {
+ protocol_version = 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int
+proto (int sock, const char *svc)
+{
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_principal server;
+ krb5_ticket *ticket;
+ char *name;
+ char ret_string[10];
+ char hostname[MAXHOSTNAMELEN];
+ krb5_data data;
+ krb5_data remotename;
+ krb5_data tk_file;
+ krb5_ccache ccache;
+ char ccname[MAXPATHLEN];
+ struct passwd *pwd;
+
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_init");
+
+ status = krb5_auth_con_setaddrs_from_fd (context,
+ auth_context,
+ &sock);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_setaddr");
+
+ if(gethostname (hostname, sizeof(hostname)) < 0)
+ krb5_err(context, 1, errno, "gethostname");
+
+ status = krb5_sname_to_principal (context,
+ hostname,
+ svc,
+ KRB5_NT_SRV_HST,
+ &server);
+ if (status)
+ krb5_err(context, 1, status, "krb5_sname_to_principal");
+
+ status = krb5_recvauth_match_version (context,
+ &auth_context,
+ &sock,
+ kfd_match_version,
+ NULL,
+ server,
+ 0,
+ NULL,
+ &ticket);
+ if (status)
+ krb5_err(context, 1, status, "krb5_recvauth");
+
+ status = krb5_unparse_name (context,
+ ticket->client,
+ &name);
+ if (status)
+ krb5_err(context, 1, status, "krb5_unparse_name");
+
+ if(protocol_version == 0) {
+ data.data = "old clnt"; /* XXX old clients only had room for
+ 10 bytes of message, and also
+ didn't show it to the user */
+ data.length = strlen(data.data) + 1;
+ krb5_write_message(context, &sock, &data);
+ sleep(2); /* XXX give client time to finish */
+ krb5_errx(context, 1, "old client; exiting");
+ }
+
+ status=krb5_read_priv_message (context, auth_context,
+ &sock, &remotename);
+ if (status)
+ krb5_err(context, 1, status, "krb5_read_message");
+ status=krb5_read_priv_message (context, auth_context,
+ &sock, &tk_file);
+ if (status)
+ krb5_err(context, 1, status, "krb5_read_message");
+
+ krb5_data_zero (&data);
+
+ if(((char*)remotename.data)[remotename.length-1] != '\0')
+ krb5_errx(context, 1, "unterminated received");
+ if(((char*)tk_file.data)[tk_file.length-1] != '\0')
+ krb5_errx(context, 1, "unterminated received");
+
+ status = krb5_read_priv_message(context, auth_context, &sock, &data);
+
+ if (status) {
+ krb5_err(context, 1, errno, "krb5_read_priv_message");
+ goto out;
+ }
+
+ pwd = getpwnam ((char *)(remotename.data));
+ if (pwd == NULL) {
+ status=1;
+ krb5_warnx(context, "getpwnam: %s failed",(char *)(remotename.data));
+ goto out;
+ }
+
+ if(!krb5_kuserok (context,
+ ticket->client,
+ (char *)(remotename.data))) {
+ status=1;
+ krb5_warnx(context, "krb5_kuserok: permission denied");
+ goto out;
+ }
+
+ if (setgid(pwd->pw_gid) < 0) {
+ krb5_warn(context, errno, "setgid");
+ goto out;
+ }
+ if (setuid(pwd->pw_uid) < 0) {
+ krb5_warn(context, errno, "setuid");
+ goto out;
+ }
+
+ if (tk_file.length != 1)
+ snprintf (ccname, sizeof(ccname), "%s", (char *)(tk_file.data));
+ else
+ snprintf (ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%lu",
+ (unsigned long)pwd->pw_uid);
+
+ status = krb5_cc_resolve (context, ccname, &ccache);
+ if (status) {
+ krb5_warn(context, status, "krb5_cc_resolve");
+ goto out;
+ }
+ status = krb5_cc_initialize (context, ccache, ticket->client);
+ if (status) {
+ krb5_warn(context, status, "krb5_cc_initialize");
+ goto out;
+ }
+ status = krb5_rd_cred2 (context, auth_context, ccache, &data);
+ krb5_cc_close (context, ccache);
+ if (status) {
+ krb5_warn(context, status, "krb5_rd_cred");
+ goto out;
+
+ }
+ strlcpy(krb5_tkfile,ccname,sizeof(krb5_tkfile));
+ krb5_warnx(context, "%s forwarded ticket to %s,%s",
+ name,
+ (char *)(remotename.data),ccname);
+ out:
+ if (status) {
+ strlcpy(ret_string, "no", sizeof(ret_string));
+ krb5_warnx(context, "failed");
+ } else {
+ strlcpy(ret_string, "ok", sizeof(ret_string));
+ }
+
+ krb5_data_free (&tk_file);
+ krb5_data_free (&remotename);
+ krb5_data_free (&data);
+ free(name);
+
+ data.data = ret_string;
+ data.length = strlen(ret_string) + 1;
+ status = krb5_write_priv_message(context, auth_context, &sock, &data);
+ krb5_auth_con_free(context, auth_context);
+
+ return status;
+}
+
+static int
+doit (int port, const char *svc)
+{
+ if (do_inetd)
+ mini_inetd(port, NULL);
+ return proto (STDIN_FILENO, svc);
+}
+
+int
+main(int argc, char **argv)
+{
+ int port;
+ int ret;
+ krb5_log_facility *fac;
+
+ setprogname (argv[0]);
+ roken_openlog (argv[0], LOG_ODELAY | LOG_PID,LOG_AUTH);
+ port = server_setup(&context, argc, argv);
+ ret = krb5_openlog(context, "kfd", &fac);
+ if(ret) krb5_err(context, 1, ret, "krb5_openlog");
+ ret = krb5_set_warn_dest(context, fac);
+ if(ret) krb5_err(context, 1, ret, "krb5_set_warn_dest");
+
+ ret = doit (port, service);
+ closelog();
+ if (ret == 0 && regpag_str != NULL)
+ ret = execl(regpag_str, "regpag", "-t", krb5_tkfile, "-r", NULL);
+ return ret;
+}
diff --git a/third_party/heimdal/appl/otp/ChangeLog b/third_party/heimdal/appl/otp/ChangeLog
new file mode 100644
index 0000000..76df17c
--- /dev/null
+++ b/third_party/heimdal/appl/otp/ChangeLog
@@ -0,0 +1,58 @@
+2006-10-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: Add man_MANS to EXTRA_DIST
+
+2005-05-29 Love Hörquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: add LIB_roken as a explit dependency
+
+2003-09-03 Love Hörquist Åstrand <lha@it.su.se>
+
+ * otpprint.c: s/des_read_pw_string/UI_UTIL_read_pw_string/
+
+ * otp.c: s/des_read_pw_string/UI_UTIL_read_pw_string/
+
+2003-02-25 Love Hörquist Åstrand <lha@it.su.se>
+
+ * otp.c: remove \n from errx, from NetBSD
+
+2000-11-29 Johan Danielsson <joda@pdc.kth.se>
+
+ * otpprint.1: sort parameters and close a list
+
+ * otp.1: sort parameters and close a list
+
+1999-09-14 Assar Westerlund <assar@sics.se>
+
+ * otp.c (verify_user_otp): check return value from
+ des_read_pw_string
+
+Thu Apr 1 16:51:07 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * otpprint.c: use getarg
+
+ * otp.c: use getarg
+
+Thu Mar 18 12:08:58 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: include Makefile.am.common
+
+Thu Mar 4 19:45:40 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: DESTDIR
+
+Sat Feb 27 19:44:25 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: add
+
+Sun Nov 22 10:32:50 1998 Assar Westerlund <assar@sics.se>
+
+ * otpprint.c: more braces
+
+ * Makefile.in (WFLAGS): set
+
+Sun Dec 21 09:31:30 1997 Assar Westerlund <assar@sics.se>
+
+ * otp.c (renew): don't set the OTP if the reading of the string
+ fails.
+
diff --git a/third_party/heimdal/appl/otp/Makefile.am b/third_party/heimdal/appl/otp/Makefile.am
new file mode 100644
index 0000000..d8e5d51
--- /dev/null
+++ b/third_party/heimdal/appl/otp/Makefile.am
@@ -0,0 +1,15 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+bin_PROGRAMS = otp otpprint
+bin_SUIDS = otp
+otp_SOURCES = otp.c otp_locl.h
+otp_LDADD = $(LIB_hcrypto) $(LIB_roken) $(top_builddir)/lib/otp/libotp.la
+otpprint_SOURCES = otpprint.c otp_locl.h
+
+otpprint_LDADD = $(LIB_hcrypto) $(LIB_roken) $(top_builddir)/lib/otp/libotp.la
+
+man_MANS = otp.1 otpprint.1
+
+EXTRA_DIST = NTMakefile $(man_MANS)
diff --git a/third_party/heimdal/appl/otp/NTMakefile b/third_party/heimdal/appl/otp/NTMakefile
new file mode 100644
index 0000000..6256309
--- /dev/null
+++ b/third_party/heimdal/appl/otp/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\otp
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/otp/otp.1 b/third_party/heimdal/appl/otp/otp.1
new file mode 100644
index 0000000..8676948
--- /dev/null
+++ b/third_party/heimdal/appl/otp/otp.1
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1996, 2000 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd November 17, 1996
+.Dt OTP 1
+.Os KTH-KRB
+.Sh NAME
+.Nm otp
+.Nd manages one-time passwords
+.Sh SYNOPSIS
+.Nm otp
+.Op Fl dhlor
+.Op Fl f Ar algorithm
+.Op Fl u Ar user
+.Ar sequence-number
+.Ar seed
+.Sh DESCRIPTION
+The
+.Nm
+program initializes and updates your current series of one-time
+passwords (OTPs).
+.Pp
+Use this to set a new series of one-time passwords. Only perform this
+on the console or over an encrypted link as you will have to supply
+your pass-phrase. The other two parameters are
+.Ar sequence-number
+and
+.Ar seed .
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl d
+To delete a one-time password.
+.It Fl f
+Choose a different
+.Ar algorithm
+from the default md5. Pick any of: md4, md5, and sha.
+.It Fl h
+For getting a help message.
+.It Fl l
+List the current table of one-time passwords.
+.It Fl o
+To open (unlock) the otp-entry for a user.
+.It Fl r
+To renew a one-time password series. This operation can be performed
+over an potentially eavesdropped link because you do not supply the
+pass-phrase. First you need to supply the current one-time password
+and then the new one corresponding to the supplied
+.Ar sequence-number
+and
+.Ar seed .
+.It Fl u
+To choose a different
+.Ar user
+to set one-time passwords for. This only works when running
+.Nm
+as root.
+.El
+.Sh SEE ALSO
+.Xr otpprint 1
diff --git a/third_party/heimdal/appl/otp/otp.c b/third_party/heimdal/appl/otp/otp.c
new file mode 100644
index 0000000..deb7d30
--- /dev/null
+++ b/third_party/heimdal/appl/otp/otp.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 1995-1997, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "otp_locl.h"
+#include <getarg.h>
+
+RCSID("$Id$");
+
+static int listp;
+static int deletep;
+static int openp;
+static int renewp;
+static char* alg_string;
+static char *user;
+static int version_flag;
+static int help_flag;
+
+struct getargs args[] = {
+ { "list", 'l', arg_flag, &listp, "list OTP status", NULL },
+ { "delete", 'd', arg_flag, &deletep, "delete OTP", NULL },
+ { "open", 'o', arg_flag, &openp, "open a locked OTP", NULL },
+ { "renew", 'r', arg_flag, &renewp, "securely renew OTP", NULL },
+ { "hash", 'f', arg_string, &alg_string,
+ "hash algorithm (md4, md5, or sha)", "algorithm"},
+ { "user", 'u', arg_string, &user,
+ "user other than current user (root only)", "user" },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL }
+};
+
+int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code)
+{
+ arg_printusage(args, num_args, NULL, "[num seed]");
+ exit(code);
+}
+
+/*
+ * Renew the OTP for a user.
+ * The pass-phrase is not required (RFC 1938/8.0)
+ */
+
+static int
+renew (int argc, char **argv, OtpAlgorithm *alg, char *inuser)
+{
+ OtpContext newctx, *ctx;
+ char prompt[128];
+ char pw[64];
+ void *dbm;
+ int ret;
+
+ newctx.alg = alg;
+ newctx.user = inuser;
+ newctx.n = atoi (argv[0]);
+ strlcpy (newctx.seed, argv[1], sizeof(newctx.seed));
+ strlwr(newctx.seed);
+ snprintf (prompt, sizeof(prompt),
+ "[ otp-%s %u %s ]",
+ newctx.alg->name,
+ newctx.n,
+ newctx.seed);
+ if (UI_UTIL_read_pw_string (pw, sizeof(pw), prompt, 0) == 0 &&
+ otp_parse (newctx.key, pw, alg) == 0) {
+ ctx = &newctx;
+ ret = 0;
+ } else
+ return 1;
+
+ dbm = otp_db_open ();
+ if (dbm == NULL) {
+ warnx ("otp_db_open failed");
+ return 1;
+ }
+ otp_put (dbm, ctx);
+ otp_db_close (dbm);
+ return ret;
+}
+
+/*
+ * Return 0 if the user could enter the next OTP.
+ * I would rather have returned !=0 but it's shell-like here around.
+ */
+
+static int
+verify_user_otp(char *username)
+{
+ OtpContext ctx;
+ char passwd[OTP_MAX_PASSPHRASE + 1];
+ char ss[256];
+ char *prompt = NULL;
+
+ if (otp_challenge (&ctx, username, ss, sizeof(ss)) != 0) {
+ warnx("no otp challenge found for %s", username);
+ return 1;
+ }
+
+ if (asprintf(&prompt, "%s's %s Password: ", username, ss) == -1 ||
+ prompt == NULL)
+ err(1, "out of memory");
+ if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) {
+ free(prompt);
+ return 1;
+ }
+ free(prompt);
+ return otp_verify_user (&ctx, passwd);
+}
+
+/*
+ * Set the OTP for a user
+ */
+
+static int
+set (int argc, char **argv, OtpAlgorithm *alg, char *inuser)
+{
+ void *db;
+ OtpContext ctx;
+ char pw[OTP_MAX_PASSPHRASE + 1];
+ int ret;
+ int i;
+
+ ctx.alg = alg;
+ ctx.user = strdup (inuser);
+ if (ctx.user == NULL)
+ err (1, "out of memory");
+
+ ctx.n = atoi (argv[0]);
+ strlcpy (ctx.seed, argv[1], sizeof(ctx.seed));
+ strlwr(ctx.seed);
+ do {
+ if (UI_UTIL_read_pw_string (pw, sizeof(pw), "Pass-phrase: ",
+ UI_UTIL_FLAG_VERIFY))
+ return 1;
+ if (strlen (pw) < OTP_MIN_PASSPHRASE)
+ printf ("Too short pass-phrase. Use at least %d characters\n",
+ OTP_MIN_PASSPHRASE);
+ } while(strlen(pw) < OTP_MIN_PASSPHRASE);
+ ctx.alg->init (ctx.key, pw, ctx.seed);
+ for (i = 0; i < ctx.n; ++i)
+ ctx.alg->next (ctx.key);
+ db = otp_db_open ();
+ if(db == NULL) {
+ free (ctx.user);
+ err (1, "otp_db_open failed");
+ }
+ ret = otp_put (db, &ctx);
+ otp_db_close (db);
+ free (ctx.user);
+ return ret;
+}
+
+/*
+ * Delete otp of user from the database
+ */
+
+static int
+delete_otp (int argc, char **argv, char *inuser)
+{
+ void *db;
+ OtpContext ctx;
+ int ret;
+
+ db = otp_db_open ();
+ if(db == NULL)
+ errx (1, "otp_db_open failed");
+
+ ctx.user = inuser;
+ ret = otp_delete(db, &ctx);
+ otp_db_close (db);
+ return ret;
+}
+
+/*
+ * Tell whether the user has an otp
+ */
+
+static int
+has_an_otp(char *inuser)
+{
+ void *db;
+ OtpContext ctx;
+ int ret;
+
+ db = otp_db_open ();
+ if(db == NULL) {
+ warnx ("otp_db_open failed");
+ return 0; /* if no db no otp! */
+ }
+
+ ctx.user = inuser;
+ ret = otp_simple_get(db, &ctx);
+
+ otp_db_close (db);
+ return !ret;
+}
+
+/*
+ * Get and print out the otp entry for some user
+ */
+
+static void
+print_otp_entry_for_name (void *db, char *inuser)
+{
+ OtpContext ctx;
+
+ ctx.user = inuser;
+ if (!otp_simple_get(db, &ctx)) {
+ fprintf(stdout,
+ "%s\totp-%s %d %s",
+ ctx.user, ctx.alg->name, ctx.n, ctx.seed);
+ if (ctx.lock_time)
+ fprintf(stdout,
+ "\tlocked since %s",
+ ctime(&ctx.lock_time));
+ else
+ fprintf(stdout, "\n");
+ }
+}
+
+static int
+open_otp (int argc, char **argv, char *inuser)
+{
+ void *db;
+ OtpContext ctx;
+ int ret;
+
+ db = otp_db_open ();
+ if (db == NULL)
+ errx (1, "otp_db_open failed");
+
+ ctx.user = inuser;
+ ret = otp_simple_get (db, &ctx);
+ if (ret == 0)
+ ret = otp_put (db, &ctx);
+ otp_db_close (db);
+ return ret;
+}
+
+/*
+ * Print otp entries for one or all users
+ */
+
+static int
+list_otps (int argc, char **argv, char *inuser)
+{
+ void *db;
+ struct passwd *pw;
+
+ db = otp_db_open ();
+ if(db == NULL)
+ errx (1, "otp_db_open failed");
+
+ if (inuser)
+ print_otp_entry_for_name(db, inuser);
+ else
+ /* scans all users... so as to get a deterministic order */
+ while ((pw = getpwent()))
+ print_otp_entry_for_name(db, pw->pw_name);
+
+ otp_db_close (db);
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ int defaultp = 0;
+ int uid = getuid();
+ OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT);
+ int optidx = 0;
+ char userbuf[128];
+
+ setprogname (argv[0]);
+ if(getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+ if(help_flag)
+ usage(0);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(deletep && uid != 0)
+ errx (1, "Only root can delete OTPs");
+ if(alg_string) {
+ alg = otp_find_alg (alg_string);
+ if (alg == NULL)
+ errx (1, "Unknown algorithm: %s", alg_string);
+ }
+ if (user && uid != 0)
+ errx (1, "Only root can use `-u'");
+ argc -= optidx;
+ argv += optidx;
+
+ if (!(listp || deletep || renewp || openp))
+ defaultp = 1;
+
+ if ( listp + deletep + renewp + defaultp + openp != 1)
+ usage(1); /* one of -d or -l or -r or none */
+
+ if(deletep || openp || listp) {
+ if(argc != 0)
+ errx(1, "delete, open, and list requires no arguments");
+ } else {
+ if(argc != 2)
+ errx(1, "setup, and renew requires `num', and `seed'");
+ }
+ if (listp)
+ return list_otps (argc, argv, user);
+
+ if (user == NULL) {
+ user = roken_get_username(userbuf, sizeof(userbuf));
+ if (user == NULL)
+ err (1, "You don't exist");
+ }
+
+ /*
+ * users other that root must provide the next OTP to update the sequence.
+ * it avoids someone to use a pending session to change an OTP sequence.
+ * see RFC 1938/8.0.
+ */
+ if (uid != 0 && (defaultp || renewp)) {
+ if (!has_an_otp(user)) {
+ errx (1, "Only root can set an initial OTP");
+ } else { /* Check the next OTP (RFC 1938/8.0: SHOULD) */
+ if (verify_user_otp(user) != 0) {
+ errx (1, "User authentication failed");
+ }
+ }
+ }
+
+ if (deletep)
+ return delete_otp (argc, argv, user);
+ else if (renewp)
+ return renew (argc, argv, alg, user);
+ else if (openp)
+ return open_otp (argc, argv, user);
+ else
+ return set (argc, argv, alg, user);
+}
diff --git a/third_party/heimdal/appl/otp/otp_locl.h b/third_party/heimdal/appl/otp/otp_locl.h
new file mode 100644
index 0000000..76f0ac4
--- /dev/null
+++ b/third_party/heimdal/appl/otp/otp_locl.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <roken.h>
+#include <err.h>
+#include "crypto-headers.h" /* for des_read_pw_string */
+#include <otp.h>
diff --git a/third_party/heimdal/appl/otp/otpprint.1 b/third_party/heimdal/appl/otp/otpprint.1
new file mode 100644
index 0000000..8045933
--- /dev/null
+++ b/third_party/heimdal/appl/otp/otpprint.1
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1996, 2000 - 2001 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Institute nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id$
+.\"
+.Dd November 17, 1996
+.Dt OTP 1
+.Os KTH-KRB
+.Sh NAME
+.Nm otpprint
+.Nd print lists of one-time passwords
+.Sh SYNOPSIS
+.Nm otp
+.Op Fl n Ar count
+.Op Fl e
+.Op Fl h
+.Op Fl f Ar algorithm
+.Ar sequence-number
+.Ar seed
+.Sh DESCRIPTION
+The
+.Nm
+program prints lists of OTPs.
+.Pp
+Use this to print out a series of one-time passwords. You will have
+to supply the
+.Ar sequence number
+and the
+.Ar seed
+as arguments and then the program will prompt you for your pass-phrase.
+.Pp
+There are several different print formats. The default is to print
+each password with six short english words.
+.Pp
+Options are:
+.Bl -tag -width Ds
+.It Fl e
+Print the passwords in ``extended'' format. In this format a prefix
+that says ``hex:'' or ``word:'' is included.
+.It Fl f
+To choose a different
+.Ar algorithm
+from the default md5. Pick any of: md4, md5, and sha.
+.It Fl h
+Print the passwords in hex.
+.It Fl n
+Print
+.Ar count
+one-time passwords, starting at
+.Ar sequence-number
+and going backwards. The default is 10.
+.El
+.Sh SEE ALSO
+.Xr otp 1
diff --git a/third_party/heimdal/appl/otp/otpprint.c b/third_party/heimdal/appl/otp/otpprint.c
new file mode 100644
index 0000000..1c9c339
--- /dev/null
+++ b/third_party/heimdal/appl/otp/otpprint.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "otp_locl.h"
+#include <getarg.h>
+
+RCSID("$Id$");
+
+static int extendedp;
+static int count = 10;
+static int hexp;
+static char* alg_string;
+static int version_flag;
+static int help_flag;
+
+struct getargs args[] = {
+ { "extended", 'e', arg_flag, &extendedp, "print keys in extended format",
+ NULL },
+ { "count", 'n', arg_integer, &count, "number of keys to print", NULL },
+ { "hexadecimal", 'h', arg_flag, &hexp, "output in hexadecimal", NULL },
+ { "hash", 'f', arg_string, &alg_string,
+ "hash algorithm (md4, md5, or sha)", "algorithm"},
+ { "version", 0, arg_flag, &version_flag, NULL, NULL },
+ { "help", 0, arg_flag, &help_flag, NULL, NULL }
+};
+
+int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage(int code)
+{
+ arg_printusage(args, num_args, NULL, "num seed");
+ exit(code);
+}
+
+static int
+print (int argc,
+ char **argv,
+ int incount,
+ OtpAlgorithm *alg,
+ void (*print_fn)(OtpKey, char *, size_t))
+{
+ char pw[64];
+ OtpKey key;
+ int n;
+ int i;
+ char *seed;
+
+ if (argc != 2)
+ usage (1);
+ n = atoi(argv[0]);
+ seed = argv[1];
+ if (UI_UTIL_read_pw_string (pw, sizeof(pw), "Pass-phrase: ", 0))
+ return 1;
+ alg->init (key, pw, seed);
+ for (i = 0; i < n; ++i) {
+ char s[64];
+
+ alg->next (key);
+ if (i >= n - incount) {
+ (*print_fn)(key, s, sizeof(s));
+ printf ("%d: %s\n", i + 1, s);
+ }
+ }
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ int optidx = 0;
+ void (*fn)(OtpKey, char *, size_t);
+ OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT);
+
+ setprogname (argv[0]);
+ if(getarg(args, num_args, argc, argv, &optidx))
+ usage(1);
+ if(help_flag)
+ usage(0);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(alg_string) {
+ alg = otp_find_alg (alg_string);
+ if (alg == NULL)
+ errx(1, "Unknown algorithm: %s", alg_string);
+ }
+ argc -= optidx;
+ argv += optidx;
+
+ if (hexp) {
+ if (extendedp)
+ fn = otp_print_hex_extended;
+ else
+ fn = otp_print_hex;
+ } else {
+ if (extendedp)
+ fn = otp_print_stddict_extended;
+ else
+ fn = otp_print_stddict;
+ }
+
+ return print (argc, argv, count, alg, fn);
+}
diff --git a/third_party/heimdal/appl/test/Makefile.am b/third_party/heimdal/appl/test/Makefile.am
new file mode 100644
index 0000000..15ed68f
--- /dev/null
+++ b/third_party/heimdal/appl/test/Makefile.am
@@ -0,0 +1,46 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+WFLAGS += $(WFLAGS_LITE)
+
+noinst_PROGRAMS = tcp_client tcp_server gssapi_server gssapi_client \
+ uu_server uu_client nt_gss_server nt_gss_client http_client
+
+tcp_client_SOURCES = tcp_client.c common.c test_locl.h
+
+tcp_server_SOURCES = tcp_server.c common.c test_locl.h
+
+gssapi_server_SOURCES = gssapi_server.c gss_common.c common.c \
+ gss_common.h test_locl.h
+
+gssapi_client_SOURCES = gssapi_client.c gss_common.c common.c \
+ gss_common.h test_locl.h
+
+http_client_SOURCES = http_client.c gss_common.c common.c \
+ gss_common.h test_locl.h
+
+uu_server_SOURCES = uu_server.c common.c test_locl.h
+
+uu_client_SOURCES = uu_client.c common.c test_locl.h
+
+gssapi_server_LDADD = $(top_builddir)/lib/gssapi/libgssapi.la $(LDADD)
+
+gssapi_client_LDADD = $(gssapi_server_LDADD)
+
+http_client_LDADD = $(top_builddir)/lib/gssapi/libgssapi.la $(LDADD)
+
+nt_gss_client_SOURCES = nt_gss_client.c nt_gss_common.c nt_gss_common.h common.c
+
+nt_gss_server_SOURCES = nt_gss_server.c nt_gss_common.c nt_gss_common.h
+
+nt_gss_client_LDADD = $(gssapi_server_LDADD)
+
+nt_gss_server_LDADD = $(nt_gss_client_LDADD)
+
+LDADD = $(top_builddir)/lib/krb5/libkrb5.la \
+ $(LIB_hcrypto) \
+ $(top_builddir)/lib/asn1/libasn1.la \
+ $(LIB_roken)
+
+EXTRA_DIST = NTMakefile jgssapi_server.java
diff --git a/third_party/heimdal/appl/test/NTMakefile b/third_party/heimdal/appl/test/NTMakefile
new file mode 100644
index 0000000..15bea96
--- /dev/null
+++ b/third_party/heimdal/appl/test/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\test
+
+!include ../../windows/NTMakefile.w32
+
diff --git a/third_party/heimdal/appl/test/common.c b/third_party/heimdal/appl/test/common.c
new file mode 100644
index 0000000..3f0fc23
--- /dev/null
+++ b/third_party/heimdal/appl/test/common.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+
+static int help_flag;
+static int version_flag;
+static char *port_str;
+char *keytab_str;
+krb5_keytab keytab;
+char *service = SERVICE;
+char *mech = "krb5";
+int fork_flag;
+char *password = NULL;
+
+static struct getargs args[] = {
+ { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
+ { "service", 's', arg_string, &service, "service to use", "service" },
+ { "keytab", 'k', arg_string, &keytab_str, "keytab to use", "keytab" },
+ { "mech", 'm', arg_string, &mech, "gssapi mech to use", "mech" },
+ { "password", 'P', arg_string, &password, "password to use", "password" },
+ { "fork", 'f', arg_flag, &fork_flag, "do fork", NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+server_usage(int code, struct getargs *args, int num_args)
+{
+ arg_printusage(args, num_args, NULL, "");
+ exit(code);
+}
+
+static void
+client_usage(int code, struct getargs *args, int num_args)
+{
+ arg_printusage(args, num_args, NULL, "host");
+ exit(code);
+}
+
+
+static int
+common_setup(krb5_context *context, int *argc, char **argv,
+ void (*usage)(int, struct getargs*, int))
+{
+ int port = 0;
+ *argc = krb5_program_setup(context, *argc, argv, args, num_args, usage);
+
+ if(help_flag)
+ (*usage)(0, args, num_args);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(port_str){
+ struct servent *s = roken_getservbyname(port_str, "tcp");
+ if(s)
+ port = s->s_port;
+ else {
+ char *ptr;
+
+ port = strtol (port_str, &ptr, 10);
+ if (port == 0 && ptr == port_str)
+ errx (1, "Bad port `%s'", port_str);
+ port = htons(port);
+ }
+ }
+
+ if (port == 0)
+ port = krb5_getportbyname (*context, PORT, "tcp", 4711);
+
+ return port;
+}
+
+int
+server_setup(krb5_context *context, int argc, char **argv)
+{
+ int port = common_setup(context, &argc, argv, server_usage);
+ krb5_error_code ret;
+
+ if(argv[argc] != NULL)
+ server_usage(1, args, num_args);
+ if (keytab_str != NULL) {
+ ret = krb5_kt_resolve (*context, keytab_str, &keytab);
+ if (ret)
+ krb5_err (*context, 1, ret, "krb5_kt_resolve");
+ } else {
+ ret = krb5_kt_default (*context, &keytab);
+ if (ret)
+ krb5_err (*context, 1, ret, "krb5_kt_default");
+ }
+ return port;
+}
+
+int
+client_setup(krb5_context *context, int *argc, char **argv)
+{
+ int optind = *argc;
+ int port = common_setup(context, &optind, argv, client_usage);
+ if(*argc - optind != 1)
+ client_usage(1, args, num_args);
+ *argc = optind;
+ return port;
+}
+
+int
+client_doit (const char *hostname, int port, const char *service,
+ int (*func)(int, const char *hostname, const char *service))
+{
+ struct addrinfo *ai, *a;
+ struct addrinfo hints;
+ int error;
+ char portstr[NI_MAXSERV];
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
+
+ error = getaddrinfo (hostname, portstr, &hints, &ai);
+ if (error) {
+ errx (1, "%s: %s", hostname, gai_strerror(error));
+ return -1;
+ }
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ int s;
+
+ s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+
+ socket_set_ipv6only(s, 1);
+
+ if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
+ warn ("connect(%s)", hostname);
+ close (s);
+ continue;
+ }
+ freeaddrinfo (ai);
+ return (*func) (s, hostname, service);
+ }
+ warnx ("failed to contact %s", hostname);
+ freeaddrinfo (ai);
+ return 1;
+}
diff --git a/third_party/heimdal/appl/test/gss_common.c b/third_party/heimdal/appl/test/gss_common.c
new file mode 100644
index 0000000..6a0eb77
--- /dev/null
+++ b/third_party/heimdal/appl/test/gss_common.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include "gss_common.h"
+RCSID("$Id$");
+
+void
+write_token (int sock, gss_buffer_t buf)
+{
+ uint32_t len, net_len;
+ OM_uint32 min_stat;
+
+ len = buf->length;
+
+ net_len = htonl(len);
+
+ if (net_write (sock, &net_len, 4) != 4)
+ err (1, "write");
+ if (net_write (sock, buf->value, len) != len)
+ err (1, "write");
+
+ gss_release_buffer (&min_stat, buf);
+}
+
+static void
+enet_read(int fd, void *buf, size_t len)
+{
+ ssize_t ret;
+
+ ret = net_read (fd, buf, len);
+ if (ret == 0)
+ errx (1, "EOF in read");
+ else if (ret < 0)
+ errx (1, "read");
+}
+
+void
+read_token (int sock, gss_buffer_t buf)
+{
+ uint32_t len, net_len;
+
+ enet_read (sock, &net_len, 4);
+ len = ntohl(net_len);
+ buf->length = len;
+ buf->value = emalloc(len);
+ enet_read (sock, buf->value, len);
+}
+
+void
+gss_print_errors (int min_stat)
+{
+ OM_uint32 new_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ OM_uint32 ret;
+
+ do {
+ ret = gss_display_status (&new_stat,
+ min_stat,
+ GSS_C_MECH_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf (stderr, "%.*s\n", (int)status_string.length,
+ (char *)status_string.value);
+ gss_release_buffer (&new_stat, &status_string);
+ } while (!GSS_ERROR(ret) && msg_ctx != 0);
+}
+
+void
+gss_verr(int exitval, int status, const char *fmt, va_list ap)
+{
+ vwarnx (fmt, ap);
+ gss_print_errors (status);
+ exit (exitval);
+}
+
+void
+gss_err(int exitval, int status, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ gss_verr (exitval, status, fmt, args);
+ va_end(args);
+}
+
+gss_OID
+select_mech(const char *mech)
+{
+ if (strcasecmp(mech, "krb5") == 0)
+ return GSS_KRB5_MECHANISM;
+ else if (strcasecmp(mech, "spnego") == 0)
+ return GSS_SPNEGO_MECHANISM;
+ else if (strcasecmp(mech, "no-oid") == 0)
+ return GSS_C_NO_OID;
+ else
+ errx (1, "Unknown mechanism '%s' (spnego, krb5, no-oid)", mech);
+}
+
+void
+print_gss_name(const char *prefix, gss_name_t name)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc name_token;
+
+ maj_stat = gss_display_name (&min_stat,
+ name,
+ &name_token,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_display_name");
+
+ fprintf (stderr, "%s `%.*s'\n", prefix,
+ (int)name_token.length,
+ (char *)name_token.value);
+
+ gss_release_buffer (&min_stat, &name_token);
+
+}
diff --git a/third_party/heimdal/appl/test/gss_common.h b/third_party/heimdal/appl/test/gss_common.h
new file mode 100644
index 0000000..eaab550
--- /dev/null
+++ b/third_party/heimdal/appl/test/gss_common.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+void write_token (int sock, gss_buffer_t buf);
+void read_token (int sock, gss_buffer_t buf);
+
+void gss_print_errors (int min_stat);
+
+void gss_verr(int exitval, int status, const char *fmt, va_list ap)
+ __attribute__ ((format (printf, 3, 0)));
+
+void gss_err(int exitval, int status, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+gss_OID select_mech(const char *);
+
+void print_gss_name(const char *, gss_name_t);
diff --git a/third_party/heimdal/appl/test/gssapi_client.c b/third_party/heimdal/appl/test/gssapi_client.c
new file mode 100644
index 0000000..13049c8
--- /dev/null
+++ b/third_party/heimdal/appl/test/gssapi_client.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include "gss_common.h"
+RCSID("$Id$");
+
+static int
+do_trans (int sock, gss_ctx_id_t context_hdl)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc real_input_token, real_output_token;
+ gss_buffer_t input_token = &real_input_token,
+ output_token = &real_output_token;
+ int conf_flag;
+
+ /* get_mic */
+
+ input_token->length = 3;
+ input_token->value = strdup("hej");
+
+ maj_stat = gss_get_mic(&min_stat,
+ context_hdl,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_get_mic");
+
+ write_token (sock, input_token);
+ write_token (sock, output_token);
+
+ gss_release_buffer(&min_stat, output_token);
+
+ /* verify mic */
+
+ read_token (sock, input_token);
+ read_token (sock, output_token);
+
+ maj_stat = gss_verify_mic(&min_stat,
+ context_hdl,
+ input_token,
+ output_token,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_verify_mic");
+
+ gss_release_buffer (&min_stat, input_token);
+ gss_release_buffer (&min_stat, output_token);
+
+ /* wrap */
+
+ input_token->length = 7;
+ input_token->value = "hemligt";
+
+ maj_stat = gss_wrap (&min_stat,
+ context_hdl,
+ 0,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_wrap");
+
+ write_token (sock, output_token);
+
+ maj_stat = gss_wrap (&min_stat,
+ context_hdl,
+ 1,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_wrap");
+
+ write_token (sock, output_token);
+
+ read_token (sock, input_token);
+
+ maj_stat = gss_unwrap (&min_stat,
+ context_hdl,
+ input_token,
+ output_token,
+ &conf_flag,
+ NULL);
+ if(GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_unwrap");
+
+ write_token (sock, output_token);
+
+ gss_release_buffer(&min_stat, output_token);
+
+ return 0;
+}
+
+extern char *password;
+
+static int
+proto (int sock, const char *hostname, const char *service)
+{
+ struct sockaddr_storage remote, local;
+ socklen_t addrlen;
+
+ int context_established = 0;
+ gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
+ gss_buffer_desc real_input_token, real_output_token;
+ gss_buffer_t input_token = &real_input_token,
+ output_token = &real_output_token;
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t server;
+ gss_buffer_desc name_token;
+ gss_OID mech_oid;
+ char *str;
+
+ mech_oid = select_mech(mech);
+
+ name_token.length = asprintf (&str,
+ "%s@%s", service, hostname);
+ if (str == NULL)
+ errx(1, "malloc - out of memory");
+ name_token.value = str;
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &server);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat,
+ "Error importing name `%s@%s':\n", service, hostname);
+
+ if (password) {
+ gss_buffer_desc pw;
+
+ pw.value = password;
+ pw.length = strlen(password);
+
+ maj_stat = gss_acquire_cred_with_password(&min_stat,
+ GSS_C_NO_NAME,
+ &pw,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET,
+ GSS_C_INITIATE,
+ &cred,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat,
+ "Error acquiring default initiator credentials");
+ }
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen > sizeof(local))
+ err (1, "getsockname(%s)", hostname);
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen > sizeof(remote))
+ err (1, "getpeername(%s)", hostname);
+
+ input_token->length = 0;
+ output_token->length = 0;
+
+#if 0
+ struct gss_channel_bindings_struct input_chan_bindings;
+ u_char init_buf[4];
+ u_char acct_buf[4];
+
+ input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
+ input_chan_bindings.initiator_address.length = 4;
+ init_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
+ init_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
+ init_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF;
+ init_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF;
+ input_chan_bindings.initiator_address.value = init_buf;
+
+ input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
+ input_chan_bindings.acceptor_address.length = 4;
+ acct_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
+ acct_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
+ acct_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF;
+ acct_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF;
+ input_chan_bindings.acceptor_address.value = acct_buf;
+
+ input_chan_bindings.application_data.value = emalloc(4);
+ * (unsigned short*)input_chan_bindings.application_data.value = local.sin_port;
+ * ((unsigned short *)input_chan_bindings.application_data.value + 1) = remote.sin_port;
+ input_chan_bindings.application_data.length = 4;
+
+ input_chan_bindings.application_data.length = 0;
+ input_chan_bindings.application_data.value = NULL;
+#endif
+
+ while(!context_established) {
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ cred,
+ &context_hdl,
+ server,
+ mech_oid,
+ GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
+ 0,
+ NULL,
+ input_token,
+ NULL,
+ output_token,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_init_sec_context");
+ if (output_token->length != 0)
+ write_token (sock, output_token);
+ if (GSS_ERROR(maj_stat)) {
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ }
+ if (maj_stat & GSS_S_CONTINUE_NEEDED) {
+ read_token (sock, input_token);
+ } else {
+ context_established = 1;
+ }
+
+ }
+ if (fork_flag) {
+ pid_t pid;
+ int pipefd[2];
+
+ if (pipe (pipefd) < 0)
+ err (1, "pipe");
+
+ pid = fork ();
+ if (pid < 0)
+ err (1, "fork");
+ if (pid != 0) {
+ gss_buffer_desc buf;
+
+ maj_stat = gss_export_sec_context (&min_stat,
+ &context_hdl,
+ &buf);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_export_sec_context");
+ write_token (pipefd[1], &buf);
+ exit (0);
+ } else {
+ gss_ctx_id_t context_hdl;
+ gss_buffer_desc buf;
+
+ close (pipefd[1]);
+ read_token (pipefd[0], &buf);
+ close (pipefd[0]);
+ maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_import_sec_context");
+ gss_release_buffer (&min_stat, &buf);
+ return do_trans (sock, context_hdl);
+ }
+ } else {
+ return do_trans (sock, context_hdl);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context context; /* XXX */
+ int port = client_setup(&context, &argc, argv);
+ return client_doit (argv[argc], port, service, proto);
+}
diff --git a/third_party/heimdal/appl/test/gssapi_server.c b/third_party/heimdal/appl/test/gssapi_server.c
new file mode 100644
index 0000000..baf13ec
--- /dev/null
+++ b/third_party/heimdal/appl/test/gssapi_server.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * A sample server that uses the GSSAPI.
+ */
+
+#include "test_locl.h"
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include "gss_common.h"
+
+static int
+process_it(int sock,
+ gss_ctx_id_t context_hdl,
+ gss_name_t client_name
+ )
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc real_input_token, real_output_token;
+ gss_buffer_t input_token = &real_input_token,
+ output_token = &real_output_token;
+ gss_name_t server_name;
+ int conf_flag;
+
+ print_gss_name("User is", client_name);
+
+ maj_stat = gss_inquire_context(&min_stat,
+ context_hdl,
+ NULL,
+ &server_name,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_inquire_context");
+
+ print_gss_name("Server is", server_name);
+
+ maj_stat = gss_release_name(&min_stat, &server_name);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_release_name");
+
+ /* gss_verify_mic */
+
+ read_token (sock, input_token);
+ read_token (sock, output_token);
+
+ maj_stat = gss_verify_mic (&min_stat,
+ context_hdl,
+ input_token,
+ output_token,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_verify_mic");
+
+ fprintf (stderr, "gss_verify_mic: %.*s\n", (int)input_token->length,
+ (char *)input_token->value);
+
+ gss_release_buffer (&min_stat, input_token);
+ gss_release_buffer (&min_stat, output_token);
+
+ /* create mic */
+
+ input_token->length = 6;
+ input_token->value = strdup("hejsan");
+
+ maj_stat = gss_get_mic(&min_stat,
+ context_hdl,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_get_mic");
+
+ write_token (sock, input_token);
+ write_token (sock, output_token);
+
+ gss_release_buffer (&min_stat, output_token);
+
+ /* gss_unwrap */
+
+ read_token (sock, input_token);
+
+ maj_stat = gss_unwrap (&min_stat,
+ context_hdl,
+ input_token,
+ output_token,
+ &conf_flag,
+ NULL);
+ if(GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_unwrap");
+
+ fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
+ (char *)output_token->value,
+ conf_flag ? "CONF" : "INT");
+
+ gss_release_buffer (&min_stat, input_token);
+ gss_release_buffer (&min_stat, output_token);
+
+ read_token (sock, input_token);
+
+ maj_stat = gss_unwrap (&min_stat,
+ context_hdl,
+ input_token,
+ output_token,
+ &conf_flag,
+ NULL);
+ if(GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_unwrap");
+
+ fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
+ (char *)output_token->value,
+ conf_flag ? "CONF" : "INT");
+
+ gss_release_buffer (&min_stat, input_token);
+ gss_release_buffer (&min_stat, output_token);
+
+ input_token->value = "hejhej";
+ input_token->length = 6;
+
+ maj_stat = gss_wrap (&min_stat,
+ context_hdl,
+ 1,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err(1, min_stat, "gss_wrap");
+
+ write_token (sock, output_token);
+ gss_release_buffer (&min_stat, output_token);
+
+ read_token (sock, input_token);
+
+ if (input_token->length != 6 && memcmp(input_token->value, "hejhej", 6) != 0)
+ errx(1, "invalid reply");
+
+ return 0;
+}
+
+static int
+proto (int sock, const char *service)
+{
+ struct sockaddr_in remote, local;
+ socklen_t addrlen;
+ gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ gss_buffer_desc real_input_token, real_output_token;
+ gss_buffer_t input_token = &real_input_token,
+ output_token = &real_output_token;
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t client_name;
+ struct gss_channel_bindings_struct input_chan_bindings;
+ gss_cred_id_t delegated_cred_handle = NULL;
+ krb5_ccache ccache = NULL;
+ u_char init_buf[4];
+ u_char acct_buf[4];
+ gss_OID mech_oid;
+ char *mech, *p;
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen != sizeof(local))
+ err (1, "getsockname)");
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen != sizeof(remote))
+ err (1, "getpeername");
+
+ input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
+ input_chan_bindings.initiator_address.length = 4;
+ init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
+ init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
+ init_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF;
+ init_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF;
+
+ input_chan_bindings.initiator_address.value = init_buf;
+ input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
+
+ input_chan_bindings.acceptor_address.length = 4;
+ acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
+ acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
+ acct_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF;
+ acct_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF;
+ input_chan_bindings.acceptor_address.value = acct_buf;
+ input_chan_bindings.application_data.value = emalloc(4);
+#if 0
+ * (unsigned short *)input_chan_bindings.application_data.value =
+ remote.sin_port;
+ * ((unsigned short *)input_chan_bindings.application_data.value + 1) =
+ local.sin_port;
+ input_chan_bindings.application_data.length = 4;
+#else
+ input_chan_bindings.application_data.length = 0;
+ input_chan_bindings.application_data.value = NULL;
+#endif
+
+ delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+ do {
+ read_token (sock, input_token);
+ maj_stat =
+ gss_accept_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_CREDENTIAL,
+ input_token,
+ &input_chan_bindings,
+ &client_name,
+ &mech_oid,
+ output_token,
+ NULL,
+ NULL,
+ &delegated_cred_handle);
+ if(GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_accept_sec_context");
+ if (output_token->length != 0)
+ write_token (sock, output_token);
+ if (GSS_ERROR(maj_stat)) {
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ }
+ } while(maj_stat & GSS_S_CONTINUE_NEEDED);
+
+ p = (char *)mech_oid->elements;
+ if (mech_oid->length == GSS_KRB5_MECHANISM->length
+ && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0)
+ mech = "Kerberos 5";
+ else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length
+ && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0)
+ mech = "SPNEGO"; /* XXX Silly, wont show up */
+ else
+ mech = "Unknown";
+
+ printf("Using mech: %s\n", mech);
+
+ if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+ krb5_context context = NULL;
+
+ printf("Delegated cred found\n");
+
+ min_stat = krb5_init_context(&context);
+ if (min_stat)
+ gss_err(1, min_stat, "krb5_init_context");
+ if (min_stat == 0)
+ min_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache);
+ if (min_stat == 0)
+ maj_stat = gss_krb5_copy_ccache(&min_stat,
+ delegated_cred_handle,
+ ccache);
+ else
+ maj_stat = GSS_S_FAILURE;
+ if (maj_stat == 0) {
+ krb5_principal p;
+ maj_stat = krb5_cc_get_principal(context, ccache, &p);
+ if (maj_stat == 0) {
+ char *name;
+ maj_stat = krb5_unparse_name(context, p, &name);
+ if (maj_stat == 0) {
+ printf("Delegated user is: `%s'\n", name);
+ free(name);
+ }
+ krb5_free_principal(context, p);
+ }
+ }
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ gss_release_cred(&min_stat, &delegated_cred_handle);
+ }
+
+ if (fork_flag) {
+ pid_t pid;
+ int pipefd[2];
+
+ if (pipe (pipefd) < 0)
+ err (1, "pipe");
+
+ pid = fork ();
+ if (pid < 0)
+ err (1, "fork");
+ if (pid != 0) {
+ gss_buffer_desc buf;
+
+ maj_stat = gss_export_sec_context (&min_stat,
+ &context_hdl,
+ &buf);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_export_sec_context");
+ write_token (pipefd[1], &buf);
+ exit (0);
+ } else {
+ gss_ctx_id_t context_hdl;
+ gss_buffer_desc buf;
+
+ close (pipefd[1]);
+ read_token (pipefd[0], &buf);
+ close (pipefd[0]);
+ maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_import_sec_context");
+ gss_release_buffer (&min_stat, &buf);
+ return process_it (sock, context_hdl, client_name);
+ }
+ } else {
+ return process_it (sock, context_hdl, client_name);
+ }
+}
+
+static void
+loop (int port, const char *service)
+{
+ int sock, sock2;
+ struct sockaddr_in my_addr;
+ int one = 1;
+
+ if (keytab_str)
+ gsskrb5_register_acceptor_identity(keytab_str);
+
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ err (1, "socket");
+
+ memset (&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = port;
+ my_addr.sin_addr.s_addr = INADDR_ANY;
+
+ if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&one, sizeof(one)) < 0)
+ warn ("setsockopt SO_REUSEADDR");
+
+ if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
+ err (1, "bind");
+
+ while (1) {
+ if (listen (sock, 1) < 0)
+ err (1, "listen");
+
+ sock2 = accept (sock, NULL, NULL);
+ if (sock2 < 0)
+ err (1, "accept");
+
+ proto (sock2, service);
+ }
+}
+
+/*
+ * Iterative server; process one connection at a time.
+ */
+int
+main(int argc, char **argv)
+{
+ krb5_context context = NULL; /* XXX */
+ krb5_error_code ret;
+ int port = server_setup(&context, argc, argv);
+
+ ret = krb5_kt_have_content(context, keytab);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_kt_have_content");
+
+ loop (port, service);
+ return 0;
+}
+
diff --git a/third_party/heimdal/appl/test/http_client.c b/third_party/heimdal/appl/test/http_client.c
new file mode 100644
index 0000000..24c4e6e
--- /dev/null
+++ b/third_party/heimdal/appl/test/http_client.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include "gss_common.h"
+#include <base64.h>
+
+RCSID("$Id$");
+
+/*
+ * A simplistic client implementing draft-brezak-spnego-http-04.txt
+ */
+
+static int
+do_connect (const char *hostname, const char *port)
+{
+ struct addrinfo *ai, *a;
+ struct addrinfo hints;
+ int error;
+ int s = -1;
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+
+ error = getaddrinfo (hostname, port, &hints, &ai);
+ if (error)
+ errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error));
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+ if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
+ warn ("connect(%s)", hostname);
+ close (s);
+ continue;
+ }
+ break;
+ }
+ freeaddrinfo (ai);
+ if (a == NULL)
+ errx (1, "failed to contact %s", hostname);
+
+ return s;
+}
+
+static void
+fdprintf(int s, const char *fmt, ...)
+{
+ size_t len;
+ ssize_t ret;
+ va_list ap;
+ char *str, *buf;
+
+ va_start(ap, fmt);
+ vasprintf(&str, fmt, ap);
+ va_end(ap);
+
+ if (str == NULL)
+ errx(1, "vasprintf");
+
+ buf = str;
+ len = strlen(buf);
+ while (len) {
+ ret = write(s, buf, len);
+ if (ret == 0)
+ err(1, "connection closed");
+ else if (ret < 0)
+ err(1, "error");
+ len -= ret;
+ buf += ret;
+ }
+ free(str);
+}
+
+static int help_flag;
+static int version_flag;
+static int verbose_flag;
+static int mutual_flag = 1;
+static int delegate_flag;
+static char *port_str = "http";
+static char *gss_service = "HTTP";
+
+static struct getargs http_args[] = {
+ { "verbose", 'v', arg_flag, &verbose_flag, "verbose logging", NULL },
+ { "port", 'p', arg_string, &port_str, "port to connect to", "port" },
+ { "delegate", 0, arg_flag, &delegate_flag, "gssapi delegate credential",
+ NULL },
+ { "gss-service", 's', arg_string, &gss_service, "gssapi service to use",
+ "service" },
+ { "mech", 'm', arg_string, &mech, "gssapi mech to use", "mech" },
+ { "mutual", 0, arg_negative_flag, &mutual_flag, "no gssapi mutual auth",
+ NULL },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_http_args = sizeof(http_args) / sizeof(http_args[0]);
+
+static void
+usage(int code)
+{
+ arg_printusage(http_args, num_http_args, NULL, "host [page]");
+ exit(code);
+}
+
+/*
+ *
+ */
+
+struct http_req {
+ char *response;
+ char **headers;
+ int num_headers;
+ void *body;
+ size_t body_size;
+};
+
+
+static void
+http_req_zero(struct http_req *req)
+{
+ req->response = NULL;
+ req->headers = NULL;
+ req->num_headers = 0;
+ req->body = NULL;
+ req->body_size = 0;
+}
+
+static void
+http_req_free(struct http_req *req)
+{
+ int i;
+
+ free(req->response);
+ for (i = 0; i < req->num_headers; i++)
+ free(req->headers[i]);
+ free(req->headers);
+ free(req->body);
+ http_req_zero(req);
+}
+
+static const char *
+http_find_header(struct http_req *req, const char *header)
+{
+ int i, len = strlen(header);
+
+ for (i = 0; i < req->num_headers; i++) {
+ if (strncasecmp(header, req->headers[i], len) == 0) {
+ return req->headers[i] + len + 1;
+ }
+ }
+ return NULL;
+}
+
+
+static int
+http_query(const char *host, const char *page,
+ char **headers, struct http_req *req)
+{
+ enum { RESPONSE, HEADER, BODY } state;
+ ssize_t ret;
+ char in_buf[1024], *in_ptr = in_buf;
+ size_t in_len = 0;
+ int s, i;
+
+ http_req_zero(req);
+
+ s = do_connect(host, port_str);
+ if (s < 0)
+ errx(1, "connection failed");
+
+ fdprintf(s, "GET %s HTTP/1.0\r\n", page);
+ for (i = 0; headers[i]; i++)
+ fdprintf(s, "%s\r\n", headers[i]);
+ fdprintf(s, "Host: %s\r\n\r\n", host);
+
+ state = RESPONSE;
+
+ while (1) {
+ ret = read (s, in_ptr, sizeof(in_buf) - in_len - 1);
+ if (ret == 0)
+ break;
+ else if (ret < 0)
+ err (1, "read: %lu", (unsigned long)ret);
+
+ in_buf[ret + in_len] = '\0';
+
+ if (state == HEADER || state == RESPONSE) {
+ char *p;
+
+ in_len += ret;
+ in_ptr += ret;
+
+ while (1) {
+ p = strstr(in_buf, "\r\n");
+
+ if (p == NULL) {
+ break;
+ } else if (p == in_buf) {
+ memmove(in_buf, in_buf + 2, sizeof(in_buf) - 2);
+ state = BODY;
+ in_len -= 2;
+ in_ptr -= 2;
+ break;
+ } else if (state == RESPONSE) {
+ req->response = emalloc(p - in_buf + 1);
+ memcpy(req->response, in_buf, p - in_buf);
+ req->response[p - in_buf] = '\0';
+ state = HEADER;
+ } else {
+ req->headers = realloc(req->headers,
+ (req->num_headers + 1) * sizeof(req->headers[0]));
+ req->headers[req->num_headers] = emalloc(p - in_buf + 1);
+ memcpy(req->headers[req->num_headers], in_buf, p - in_buf);
+ req->headers[req->num_headers][p - in_buf] = '\0';
+ if (req->headers[req->num_headers] == NULL)
+ errx(1, "strdup");
+ req->num_headers++;
+ }
+ memmove(in_buf, p + 2, sizeof(in_buf) - (p - in_buf) - 2);
+ in_len -= (p - in_buf) + 2;
+ in_ptr -= (p - in_buf) + 2;
+ }
+ }
+
+ if (state == BODY) {
+
+ req->body = erealloc(req->body, req->body_size + ret + 1);
+
+ memcpy((char *)req->body + req->body_size, in_buf, ret);
+ req->body_size += ret;
+ ((char *)req->body)[req->body_size] = '\0';
+
+ in_ptr = in_buf;
+ in_len = 0;
+ } else
+ abort();
+ }
+
+ if (verbose_flag) {
+ int i;
+ printf("response: %s\n", req->response);
+ for (i = 0; i < req->num_headers; i++)
+ printf("header[%d] %s\n", i, req->headers[i]);
+ printf("body: %.*s\n", (int)req->body_size, (char *)req->body);
+ }
+
+ close(s);
+ return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ struct http_req req;
+ const char *host, *page;
+ int i, done, print_body, gssapi_done, gssapi_started;
+ char *headers[10] = { 0 };
+ int num_headers = 0;
+ gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ gss_name_t server = GSS_C_NO_NAME;
+ int optind = 0;
+ gss_OID mech_oid;
+ OM_uint32 flags;
+
+ setprogname(argv[0]);
+
+ if(getarg(http_args, num_http_args, argc, argv, &optind))
+ usage(1);
+
+ if (help_flag)
+ usage (0);
+
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ mech_oid = select_mech(mech);
+
+ if (argc != 1 && argc != 2)
+ errx(1, "usage: %s host [page]", getprogname());
+ host = argv[0];
+ if (argc == 2)
+ page = argv[1];
+ else
+ page = "/";
+
+ flags = 0;
+ if (delegate_flag)
+ flags |= GSS_C_DELEG_FLAG;
+ if (mutual_flag)
+ flags |= GSS_C_MUTUAL_FLAG;
+
+ done = 0;
+ num_headers = 0;
+ gssapi_done = 1;
+ gssapi_started = 0;
+ do {
+ print_body = 0;
+
+ http_query(host, page, headers, &req);
+ for (i = 0 ; headers[i]; i++) {
+ free(headers[i]);
+ headers[i] = NULL;
+ }
+ num_headers = 0;
+
+ if (strstr(req.response, " 200 ") != NULL) {
+ print_body = 1;
+ done = 1;
+ } else if (strstr(req.response, " 401 ") != NULL) {
+ if (http_find_header(&req, "WWW-Authenticate:") == NULL)
+ errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
+ gssapi_done = 0;
+ }
+
+ if (!gssapi_done) {
+ const char *h = http_find_header(&req, "WWW-Authenticate:");
+ if (h == NULL)
+ errx(1, "Got %s but missed `WWW-Authenticate'", req.response);
+
+ if (strncasecmp(h, "Negotiate", 9) == 0) {
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc input_token, output_token;
+
+ if (verbose_flag)
+ printf("Negotiate found\n");
+
+ if (server == GSS_C_NO_NAME) {
+ char *name;
+ asprintf(&name, "%s@%s", gss_service, host);
+ input_token.length = strlen(name);
+ input_token.value = name;
+
+ maj_stat = gss_import_name(&min_stat,
+ &input_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &server);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_inport_name");
+ free(name);
+ input_token.length = 0;
+ input_token.value = NULL;
+ }
+
+ i = 9;
+ while(h[i] && isspace((unsigned char)h[i]))
+ i++;
+ if (h[i] != '\0') {
+ int len = strlen(&h[i]);
+ if (len == 0)
+ errx(1, "invalid Negotiate token");
+ input_token.value = emalloc(len);
+ len = rk_base64_decode(&h[i], input_token.value);
+ if (len < 0)
+ errx(1, "invalid base64 Negotiate token %s", &h[i]);
+ input_token.length = len;
+ } else {
+ if (gssapi_started)
+ errx(1, "Negotiate already started");
+ gssapi_started = 1;
+
+ input_token.length = 0;
+ input_token.value = NULL;
+ }
+
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &context_hdl,
+ server,
+ mech_oid,
+ flags,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ NULL,
+ &output_token,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_init_sec_context");
+ else if (maj_stat & GSS_S_CONTINUE_NEEDED)
+ gssapi_done = 0;
+ else {
+ gss_name_t targ_name, src_name;
+ gss_buffer_desc name_buffer;
+ gss_OID mech_type;
+
+ gssapi_done = 1;
+
+ printf("Negotiate done: %s\n", mech);
+
+ maj_stat = gss_inquire_context(&min_stat,
+ context_hdl,
+ &src_name,
+ &targ_name,
+ NULL,
+ &mech_type,
+ NULL,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_inquire_context");
+
+ maj_stat = gss_display_name(&min_stat,
+ src_name,
+ &name_buffer,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_display_name");
+
+ printf("Source: %.*s\n",
+ (int)name_buffer.length,
+ (char *)name_buffer.value);
+
+ gss_release_buffer(&min_stat, &name_buffer);
+
+ maj_stat = gss_display_name(&min_stat,
+ targ_name,
+ &name_buffer,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_display_name");
+
+ printf("Target: %.*s\n",
+ (int)name_buffer.length,
+ (char *)name_buffer.value);
+
+ gss_release_name(&min_stat, &targ_name);
+ gss_release_buffer(&min_stat, &name_buffer);
+ }
+
+ if (output_token.length) {
+ char *neg_token;
+
+ rk_base64_encode(output_token.value,
+ output_token.length,
+ &neg_token);
+
+ asprintf(&headers[num_headers++], "Authorization: Negotiate %s",
+ neg_token);
+
+ free(neg_token);
+ gss_release_buffer(&min_stat, &output_token);
+ }
+ if (input_token.length)
+ free(input_token.value);
+
+ } else
+ done = 1;
+ } else
+ done = 1;
+
+ if (verbose_flag) {
+ printf("%s\n\n", req.response);
+
+ for (i = 0; i < req.num_headers; i++)
+ printf("%s\n", req.headers[i]);
+ printf("\n");
+ }
+ if (print_body || verbose_flag)
+ printf("%.*s\n", (int)req.body_size, (char *)req.body);
+
+ http_req_free(&req);
+ } while (!done);
+
+ if (gssapi_done == 0)
+ errx(1, "gssapi not done but http dance done");
+
+ return 0;
+}
diff --git a/third_party/heimdal/appl/test/jgssapi_server.java b/third_party/heimdal/appl/test/jgssapi_server.java
new file mode 100644
index 0000000..6a9e75e
--- /dev/null
+++ b/third_party/heimdal/appl/test/jgssapi_server.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+import org.ietf.jgss.*;
+import java.io.*;
+import java.net.Socket;
+import java.net.ServerSocket;
+
+public class jgssapi_server {
+
+ static byte [] getMessage(DataInputStream inStream)
+ throws IOException
+ {
+ byte[] token;
+ token = new byte[inStream.readInt()];
+ inStream.readFully(token);
+ return token;
+ }
+
+ static void putMessage(DataOutputStream outStream, byte [] token)
+ throws IOException
+ {
+ outStream.writeInt(token.length);
+ outStream.write(token);
+ }
+
+
+ public static void main(String[] args)
+ throws IOException, GSSException {
+
+ GSSManager manager = GSSManager.getInstance();
+
+ GSSContext context = manager.createContext((GSSCredential)null);
+
+ byte[] token = null;
+
+ int port = 4717;
+
+ System.out.println("listen on port " + port);
+
+ Socket s = new ServerSocket(port).accept();
+
+ DataInputStream inStream = new DataInputStream(s.getInputStream());
+ DataOutputStream outStream = new DataOutputStream(s.getOutputStream());
+
+ System.out.println("negotiate context");
+ while (!context.isEstablished()) {
+ token = getMessage(inStream);
+
+ token = context.acceptSecContext(token, 0, token.length);
+ if (token != null)
+ putMessage(outStream, token);
+ }
+
+ System.out.println("done");
+
+ /*
+ * mic
+ */
+ System.out.println("mic test");
+
+ System.out.println(" verify mic");
+
+ byte[] intoken = getMessage(inStream);
+ byte[] outtoken = getMessage(inStream);
+ byte[] bytes = null;
+
+ context.verifyMIC(outtoken, 0, outtoken.length,
+ intoken, 0, intoken.length, new MessageProp(0, false));
+
+ System.out.println(" create mic");
+
+ bytes = new byte[] { 0x66, 0x6f, 0x6f };
+
+ outtoken = context.getMIC(bytes, 0, bytes.length, new MessageProp(0, false));
+ putMessage(outStream, bytes);
+ putMessage(outStream, outtoken);
+
+ /*
+ * wrap int
+ */
+ System.out.println("warp int");
+
+ outtoken = getMessage(inStream);
+
+ bytes = context.unwrap(outtoken, 0, outtoken.length, new MessageProp(0, false));
+
+ if (bytes == null)
+ System.err.println("wrap int failed");
+
+ /*
+ * wrap conf
+ */
+ System.out.println("warp conf");
+
+ outtoken = getMessage(inStream);
+
+ bytes = context.unwrap(outtoken, 0, outtoken.length, new MessageProp(0, true));
+
+ if (bytes == null)
+ System.err.println("wrap conf failed");
+
+
+ /*
+ * wrap conf
+ */
+ System.out.println("warp conf");
+ intoken = new byte[] { 0x66, 0x6f, 0x6f };
+ outtoken = context.wrap(intoken, 0, intoken.length, new MessageProp(0, true));
+ putMessage(outStream, outtoken);
+ outtoken = getMessage(inStream);
+
+ context.dispose();
+
+ System.exit(0);
+ }
+}
+
diff --git a/third_party/heimdal/appl/test/nt_gss_client.c b/third_party/heimdal/appl/test/nt_gss_client.c
new file mode 100644
index 0000000..fc9ff3c
--- /dev/null
+++ b/third_party/heimdal/appl/test/nt_gss_client.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi.h>
+#include "nt_gss_common.h"
+
+RCSID("$Id$");
+
+/*
+ * This program tries to act as a client for the sample in `Sample
+ * SSPI Code' in Windows 2000 RC1 SDK.
+ */
+
+static int
+proto (int sock, const char *hostname, const char *service)
+{
+ struct sockaddr_in remote, local;
+ socklen_t addrlen;
+
+ int context_established = 0;
+ gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t server;
+ gss_buffer_desc name_token;
+ char *str;
+
+ name_token.length = asprintf (&str,
+ "%s@%s", service, hostname);
+ if (str == NULL)
+ errx(1, "out of memory");
+ name_token.value = str;
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &server);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat,
+ "Error importing name `%s@%s':\n", service, hostname);
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen != sizeof(local))
+ err (1, "getsockname(%s)", hostname);
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen != sizeof(remote))
+ err (1, "getpeername(%s)", hostname);
+
+ input_token = &real_input_token;
+ output_token = &real_output_token;
+
+ input_token->length = 0;
+ output_token->length = 0;
+
+ while(!context_established) {
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &context_hdl,
+ server,
+ GSS_C_NO_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ input_token,
+ NULL,
+ output_token,
+ NULL,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_init_sec_context");
+ if (output_token->length != 0)
+ nt_write_token (sock, output_token);
+ if (GSS_ERROR(maj_stat)) {
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ }
+ if (maj_stat & GSS_S_CONTINUE_NEEDED) {
+ nt_read_token (sock, input_token);
+ } else {
+ context_established = 1;
+ }
+
+ }
+
+ /* get_mic */
+
+ input_token->length = 3;
+ input_token->value = strdup("hej");
+
+ maj_stat = gss_get_mic(&min_stat,
+ context_hdl,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_get_mic");
+
+ nt_write_token (sock, input_token);
+ nt_write_token (sock, output_token);
+
+ /* wrap */
+
+ input_token->length = 7;
+ input_token->value = "hemligt";
+
+
+ maj_stat = gss_wrap (&min_stat,
+ context_hdl,
+ 1,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_wrap");
+
+ nt_write_token (sock, output_token);
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context context; /* XXX */
+ int port = client_setup(&context, &argc, argv);
+ return client_doit (argv[argc], port, service, proto);
+}
diff --git a/third_party/heimdal/appl/test/nt_gss_common.c b/third_party/heimdal/appl/test/nt_gss_common.c
new file mode 100644
index 0000000..617c18a
--- /dev/null
+++ b/third_party/heimdal/appl/test/nt_gss_common.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi.h>
+#include "nt_gss_common.h"
+
+RCSID("$Id$");
+
+/*
+ * These are functions that are needed to interoperate with the
+ * `Sample SSPI Code' in Windows 2000 RC1 SDK.
+ */
+
+/*
+ * Write the `gss_buffer_t' in `buf' onto the fd `sock', but remember that
+ * the length is written in little-endian-order.
+ */
+
+void
+nt_write_token (int sock, gss_buffer_t buf)
+{
+ unsigned char net_len[4];
+ uint32_t len;
+ OM_uint32 min_stat;
+
+ len = buf->length;
+
+ net_len[0] = (len >> 0) & 0xFF;
+ net_len[1] = (len >> 8) & 0xFF;
+ net_len[2] = (len >> 16) & 0xFF;
+ net_len[3] = (len >> 24) & 0xFF;
+
+ if (write (sock, net_len, 4) != 4)
+ err (1, "write");
+ if (write (sock, buf->value, len) != len)
+ err (1, "write");
+
+ gss_release_buffer (&min_stat, buf);
+}
+
+/*
+ *
+ */
+
+void
+nt_read_token (int sock, gss_buffer_t buf)
+{
+ unsigned char net_len[4];
+ uint32_t len;
+
+ if (read(sock, net_len, 4) != 4)
+ err (1, "read");
+ len = (net_len[0] << 0)
+ | (net_len[1] << 8)
+ | (net_len[2] << 16)
+ | (net_len[3] << 24);
+
+ if (len > INT_MAX/16)
+ errx(1, "len too large");
+ buf->length = len;
+ buf->value = malloc(len);
+ if (read (sock, buf->value, len) != len)
+ err (1, "read");
+}
+
+void
+gss_print_errors (int min_stat)
+{
+ OM_uint32 new_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ OM_uint32 ret;
+
+ do {
+ ret = gss_display_status (&new_stat,
+ min_stat,
+ GSS_C_MECH_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf (stderr, "%.*s\n",
+ (int)status_string.length,
+ (char *)status_string.value);
+ gss_release_buffer (&new_stat, &status_string);
+ } while (!GSS_ERROR(ret) && msg_ctx != 0);
+}
+
+void
+gss_verr(int exitval, int status, const char *fmt, va_list ap)
+{
+ vwarnx (fmt, ap);
+ gss_print_errors (status);
+ exit (exitval);
+}
+
+void
+gss_err(int exitval, int status, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ gss_verr (exitval, status, fmt, args);
+ va_end(args);
+}
diff --git a/third_party/heimdal/appl/test/nt_gss_common.h b/third_party/heimdal/appl/test/nt_gss_common.h
new file mode 100644
index 0000000..134afe3
--- /dev/null
+++ b/third_party/heimdal/appl/test/nt_gss_common.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+void nt_write_token (int sock, gss_buffer_t buf);
+void nt_read_token (int sock, gss_buffer_t buf);
+
+void gss_print_errors (int min_stat);
+
+void gss_verr(int exitval, int status, const char *fmt, va_list ap)
+ __attribute__ ((format (printf, 3, 0)));
+
+void gss_err(int exitval, int status, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
diff --git a/third_party/heimdal/appl/test/nt_gss_server.c b/third_party/heimdal/appl/test/nt_gss_server.c
new file mode 100644
index 0000000..d6f7cc1
--- /dev/null
+++ b/third_party/heimdal/appl/test/nt_gss_server.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_spnego.h>
+#include <krb5.h>
+#include "nt_gss_common.h"
+
+RCSID("$Id$");
+
+/*
+ * This program tries to act as a server for the sample in `Sample
+ * SSPI Code' in Windows 2000 RC1 SDK.
+ *
+ * use --dump-auth to get a binary dump of the authorization data in the ticket
+ */
+
+static int help_flag;
+static int version_flag;
+static char *port_str;
+char *service = SERVICE;
+static char *auth_file;
+
+static struct getargs args[] = {
+ { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
+ { "service", 's', arg_string, &service, "service to use", "service" },
+ { "dump-auth", 0, arg_string, &auth_file, "dump authorization data",
+ "file" },
+ { "help", 'h', arg_flag, &help_flag, NULL, NULL },
+ { "version", 0, arg_flag, &version_flag, NULL, NULL }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static int
+proto (int sock, const char *service)
+{
+ struct sockaddr_in remote, local;
+ socklen_t addrlen;
+ gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t client_name;
+ gss_buffer_desc name_token;
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen != sizeof(local))
+ err (1, "getsockname)");
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen != sizeof(remote))
+ err (1, "getpeername");
+
+ input_token = &real_input_token;
+ output_token = &real_output_token;
+
+ do {
+ nt_read_token (sock, input_token);
+ maj_stat =
+ gss_accept_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_CREDENTIAL,
+ input_token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &client_name,
+ NULL,
+ output_token,
+ NULL,
+ NULL,
+ NULL);
+ if(GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_accept_sec_context");
+ if (output_token->length != 0)
+ nt_write_token (sock, output_token);
+ if (GSS_ERROR(maj_stat)) {
+ if (context_hdl != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context (&min_stat,
+ &context_hdl,
+ GSS_C_NO_BUFFER);
+ break;
+ }
+ } while(maj_stat & GSS_S_CONTINUE_NEEDED);
+
+ if (auth_file != NULL) {
+ gss_buffer_desc data;
+
+ maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
+ context_hdl,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &data);
+ if (maj_stat == GSS_S_COMPLETE) {
+ rk_dumpdata(auth_file, data.value, data.length);
+ gss_release_buffer(&min_stat, &data);
+ }
+ }
+
+ maj_stat = gss_display_name (&min_stat,
+ client_name,
+ &name_token,
+ NULL);
+ if (GSS_ERROR(maj_stat))
+ gss_err (1, min_stat, "gss_display_name");
+
+ fprintf (stderr, "User is `%.*s'\n", (int)name_token.length,
+ (char *)name_token.value);
+
+ /* write something back */
+
+ output_token->value = strdup ("hejsan");
+ output_token->length = strlen (output_token->value) + 1;
+ nt_write_token (sock, output_token);
+
+ output_token->value = strdup ("hoppsan");
+ output_token->length = strlen (output_token->value) + 1;
+ nt_write_token (sock, output_token);
+
+ return 0;
+}
+
+static int
+doit (int port, const char *service)
+{
+ int sock, sock2;
+ struct sockaddr_in my_addr;
+ int one = 1;
+
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ err (1, "socket");
+
+ memset (&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = port;
+ my_addr.sin_addr.s_addr = INADDR_ANY;
+
+ if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&one, sizeof(one)) < 0)
+ warn ("setsockopt SO_REUSEADDR");
+
+ if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
+ err (1, "bind");
+
+ if (listen (sock, 1) < 0)
+ err (1, "listen");
+
+ sock2 = accept (sock, NULL, NULL);
+ if (sock2 < 0)
+ err (1, "accept");
+
+ return proto (sock2, service);
+}
+
+static void
+usage(int code, struct getargs *args, int num_args)
+{
+ arg_printusage(args, num_args, NULL, "");
+ exit(code);
+}
+
+static int
+common_setup(krb5_context *context, int *argc, char **argv,
+ void (*usage)(int, struct getargs*, int))
+{
+ int port = 0;
+ *argc = krb5_program_setup(context, *argc, argv, args, num_args, usage);
+
+ if(help_flag)
+ (*usage)(0, args, num_args);
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(port_str){
+ struct servent *s = roken_getservbyname(port_str, "tcp");
+ if(s)
+ port = s->s_port;
+ else {
+ char *ptr;
+
+ port = strtol (port_str, &ptr, 10);
+ if (port == 0 && ptr == port_str)
+ errx (1, "Bad port `%s'", port_str);
+ port = htons(port);
+ }
+ }
+
+ if (port == 0)
+ port = krb5_getportbyname (*context, PORT, "tcp", 4711);
+
+ return port;
+}
+
+static int
+setup(krb5_context *context, int argc, char **argv)
+{
+ int port = common_setup(context, &argc, argv, usage);
+ if(argv[argc] != NULL)
+ usage(1, args, num_args);
+ return port;
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context context = NULL; /* XXX */
+ int port = setup(&context, argc, argv);
+ return doit (port, service);
+}
diff --git a/third_party/heimdal/appl/test/tcp_client.c b/third_party/heimdal/appl/test/tcp_client.c
new file mode 100644
index 0000000..2bbb068
--- /dev/null
+++ b/third_party/heimdal/appl/test/tcp_client.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+RCSID("$Id$");
+
+krb5_context context;
+
+static int
+proto (int sock, const char *hostname, const char *service)
+{
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_principal server;
+ krb5_data data;
+ krb5_data packet;
+ uint32_t len, net_len;
+
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status)
+ krb5_err (context, 1, status, "krb5_auth_con_init");
+
+ status = krb5_auth_con_setaddrs_from_fd (context,
+ auth_context,
+ &sock);
+ if (status)
+ krb5_err (context, 1, status, "krb5_auth_con_setaddrs_from_fd");
+
+ status = krb5_sname_to_principal (context,
+ hostname,
+ service,
+ KRB5_NT_SRV_HST,
+ &server);
+ if (status)
+ krb5_err (context, 1, status, "krb5_sname_to_principal");
+
+ status = krb5_sendauth (context,
+ &auth_context,
+ &sock,
+ VERSION,
+ NULL,
+ server,
+ AP_OPTS_MUTUAL_REQUIRED,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (status)
+ krb5_err (context, 1, status, "krb5_sendauth");
+
+ data.data = "hej";
+ data.length = 3;
+
+ krb5_data_zero (&packet);
+
+ status = krb5_mk_safe (context,
+ auth_context,
+ &data,
+ &packet,
+ NULL);
+ if (status)
+ krb5_err (context, 1, status, "krb5_mk_safe");
+
+ len = packet.length;
+ net_len = htonl(len);
+
+ if (krb5_net_write (context, &sock, &net_len, 4) != 4)
+ err (1, "krb5_net_write");
+ if (krb5_net_write (context, &sock, packet.data, len) != len)
+ err (1, "krb5_net_write");
+
+ data.data = "hemligt";
+ data.length = 7;
+
+ krb5_data_free (&packet);
+
+ status = krb5_mk_priv (context,
+ auth_context,
+ &data,
+ &packet,
+ NULL);
+ if (status)
+ krb5_err (context, 1, status, "krb5_mk_priv");
+
+ len = packet.length;
+ net_len = htonl(len);
+
+ if (krb5_net_write (context, &sock, &net_len, 4) != 4)
+ err (1, "krb5_net_write");
+ if (krb5_net_write (context, &sock, packet.data, len) != len)
+ err (1, "krb5_net_write");
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int port = client_setup(&context, &argc, argv);
+ return client_doit (argv[argc], port, service, proto);
+}
diff --git a/third_party/heimdal/appl/test/tcp_server.c b/third_party/heimdal/appl/test/tcp_server.c
new file mode 100644
index 0000000..50d1bf4
--- /dev/null
+++ b/third_party/heimdal/appl/test/tcp_server.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * A sample server that uses the Kerberos V5 API.
+ *
+ * See "Introduction to the Kerberos 5 API" in the Doxygen documentation
+ * for a walkthrough of this code.
+ */
+
+#include "test_locl.h"
+RCSID("$Id$");
+
+/* The API needs one Kerberos context per thread. */
+krb5_context context;
+
+static int
+proto (int sock, const char *service)
+{
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_principal server;
+ krb5_ticket *ticket;
+ char *name;
+ char hostname[MAXHOSTNAMELEN];
+ krb5_data packet;
+ krb5_data data;
+ uint32_t len, net_len;
+ ssize_t n;
+
+ /* Initialize the authentication context, to be used to authenticate the peer. */
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status)
+ krb5_err (context, 1, status, "krb5_auth_con_init");
+
+ /* Extract the local and remote address from the socket into auth_context. */
+ status = krb5_auth_con_setaddrs_from_fd (context,
+ auth_context,
+ &sock);
+ if (status)
+ krb5_err (context, 1, status, "krb5_auth_con_setaddrs_from_fd");
+
+ if (gethostname (hostname, sizeof(hostname)) < 0)
+ krb5_err (context, 1, errno, "gethostname");
+
+ /* Create principal "server" for "service" on "hostname" (this host). */
+ status = krb5_sname_to_principal (context,
+ hostname,
+ service,
+ KRB5_NT_SRV_HST,
+ &server);
+ if (status)
+ krb5_err (context, 1, status, "krb5_sname_to_principal");
+
+ /*
+ * Perform the server side of the sendauth protocol. On success, "ticket"
+ * contains the authenticated credentials of the client.
+ */
+ status = krb5_recvauth (context,
+ &auth_context,
+ &sock,
+ VERSION,
+ server,
+ 0, /* flags */
+ keytab,
+ &ticket);
+ if (status)
+ krb5_err (context, 1, status, "krb5_recvauth");
+
+ /* Extract the client name as a string. */
+ status = krb5_unparse_name (context,
+ ticket->client,
+ &name);
+ if (status)
+ krb5_err (context, 1, status, "krb5_unparse_name");
+
+ fprintf (stderr, "User is `%s'\n", name);
+ free (name);
+
+ krb5_data_zero (&data);
+ krb5_data_zero (&packet);
+
+ /*
+ * Read the payload (encoded as length, value).
+ */
+ n = krb5_net_read (context, &sock, &net_len, 4);
+ if (n == 0)
+ krb5_errx (context, 1, "EOF in krb5_net_read");
+ if (n < 0)
+ krb5_err (context, 1, errno, "krb5_net_read");
+
+ len = ntohl(net_len);
+
+ krb5_data_alloc (&packet, len);
+
+ n = krb5_net_read (context, &sock, packet.data, len);
+ if (n == 0)
+ krb5_errx (context, 1, "EOF in krb5_net_read");
+ if (n < 0)
+ krb5_err (context, 1, errno, "krb5_net_read");
+
+ /*
+ * Expect a KRB_SAFE message (authenticated, not encrypted)
+ */
+ status = krb5_rd_safe (context,
+ auth_context,
+ &packet,
+ &data,
+ NULL);
+ if (status)
+ krb5_err (context, 1, status, "krb5_rd_safe");
+
+ fprintf (stderr, "safe packet: %.*s\n", (int)data.length,
+ (char *)data.data);
+
+ /*
+ * Read the payload (encoded as length, value).
+ */
+ n = krb5_net_read (context, &sock, &net_len, 4);
+ if (n == 0)
+ krb5_errx (context, 1, "EOF in krb5_net_read");
+ if (n < 0)
+ krb5_err (context, 1, errno, "krb5_net_read");
+
+ len = ntohl(net_len);
+
+ krb5_data_alloc (&packet, len);
+
+ n = krb5_net_read (context, &sock, packet.data, len);
+ if (n == 0)
+ krb5_errx (context, 1, "EOF in krb5_net_read");
+ if (n < 0)
+ krb5_err (context, 1, errno, "krb5_net_read");
+
+ /*
+ * Expect a KRB_PRIV message (authenticated and encrypted)
+ */
+ status = krb5_rd_priv (context,
+ auth_context,
+ &packet,
+ &data,
+ NULL);
+ if (status)
+ krb5_err (context, 1, status, "krb5_rd_priv");
+
+ fprintf (stderr, "priv packet: %.*s\n", (int)data.length,
+ (char *)data.data);
+
+ return 0;
+}
+
+static int
+doit (int port, const char *service)
+{
+ /* Block waiting for a connection. */
+ mini_inetd (port, NULL);
+
+ return proto (STDIN_FILENO, service);
+}
+
+/*
+ * Process only one connection and then exit.
+ */
+int
+main(int argc, char **argv)
+{
+ int port = server_setup(&context, argc, argv);
+ krb5_error_code ret;
+
+ ret = krb5_kt_have_content(context, keytab);
+ if (ret)
+ krb5_err (context, 1, ret, "krb5_kt_have_content");
+
+ return doit (port, service);
+}
diff --git a/third_party/heimdal/appl/test/test_locl.h b/third_party/heimdal/appl/test/test_locl.h
new file mode 100644
index 0000000..dba2bba
--- /dev/null
+++ b/third_party/heimdal/appl/test/test_locl.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <errno.h>
+#include <roken.h>
+#include <getarg.h>
+#include <err.h>
+#include <krb5.h>
+
+#define SERVICE "test"
+
+#define PORT "test"
+
+extern char *service;
+extern char *mech;
+extern char *keytab_str;
+extern krb5_keytab keytab;
+extern int fork_flag;
+int server_setup(krb5_context*, int, char**);
+int client_setup(krb5_context*, int*, char**);
+int client_doit (const char *hostname, int port, const char *service,
+ int (*func)(int, const char *hostname, const char *service));
diff --git a/third_party/heimdal/appl/test/uu_client.c b/third_party/heimdal/appl/test/uu_client.c
new file mode 100644
index 0000000..15e7899
--- /dev/null
+++ b/third_party/heimdal/appl/test/uu_client.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+RCSID("$Id$");
+
+krb5_context context;
+
+static int
+proto (int sock, const char *hostname, const char *service)
+{
+ struct sockaddr_storage remote, local;
+ socklen_t addrlen;
+ krb5_address remote_addr, local_addr;
+ krb5_context context;
+ krb5_ccache ccache;
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_principal client;
+ krb5_data data;
+ krb5_data packet;
+ krb5_creds mcred, cred;
+ krb5_ticket *ticket;
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen > sizeof(local))
+ err (1, "getsockname(%s)", hostname);
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen > sizeof(remote))
+ err (1, "getpeername(%s)", hostname);
+
+ status = krb5_init_context(&context);
+ if (status)
+ errx(1, "krb5_init_context failed: %d", status);
+
+ status = krb5_cc_default (context, &ccache);
+ if (status)
+ krb5_err(context, 1, status, "krb5_cc_default");
+
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_init");
+
+ status = krb5_sockaddr2address (context, (struct sockaddr *)&local, &local_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_sockaddr2address(local)");
+ status = krb5_sockaddr2address (context, (struct sockaddr *)&remote, &remote_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_sockaddr2address(remote)");
+
+ status = krb5_auth_con_setaddrs (context,
+ auth_context,
+ &local_addr,
+ &remote_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_setaddr");
+
+ krb5_cc_clear_mcred(&mcred);
+
+ status = krb5_cc_get_principal(context, ccache, &client);
+ if(status)
+ krb5_err(context, 1, status, "krb5_cc_get_principal");
+ status = krb5_make_principal(context, &mcred.server,
+ krb5_principal_get_realm(context, client),
+ "krbtgt",
+ krb5_principal_get_realm(context, client),
+ NULL);
+ if(status)
+ krb5_err(context, 1, status, "krb5_make_principal");
+ mcred.client = client;
+
+ status = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
+ if(status)
+ krb5_err(context, 1, status, "krb5_cc_retrieve_cred");
+
+ {
+ char *client_name;
+ krb5_data data;
+ status = krb5_unparse_name(context, cred.client, &client_name);
+ if(status)
+ krb5_err(context, 1, status, "krb5_unparse_name");
+ data.data = client_name;
+ data.length = strlen(client_name) + 1;
+ status = krb5_write_message(context, &sock, &data);
+ if(status)
+ krb5_err(context, 1, status, "krb5_write_message");
+ free(client_name);
+ }
+
+ status = krb5_write_message(context, &sock, &cred.ticket);
+ if(status)
+ krb5_err(context, 1, status, "krb5_write_message");
+
+ status = krb5_auth_con_setuserkey(context, auth_context, &cred.session);
+ if(status)
+ krb5_err(context, 1, status, "krb5_auth_con_setuserkey");
+
+ status = krb5_recvauth(context, &auth_context, &sock,
+ VERSION, client, 0, NULL, &ticket);
+
+ if (status)
+ krb5_err(context, 1, status, "krb5_recvauth");
+
+ if (ticket->ticket.authorization_data) {
+ AuthorizationData *authz;
+ int i;
+
+ printf("Authorization data:\n");
+
+ authz = ticket->ticket.authorization_data;
+ for (i = 0; i < authz->len; i++) {
+ printf("\ttype %d, length %lu\n",
+ authz->val[i].ad_type,
+ (unsigned long)authz->val[i].ad_data.length);
+ }
+ }
+
+ data.data = "hej";
+ data.length = 3;
+
+ krb5_data_zero (&packet);
+
+ status = krb5_mk_safe (context,
+ auth_context,
+ &data,
+ &packet,
+ NULL);
+ if (status)
+ krb5_err(context, 1, status, "krb5_mk_safe");
+
+ status = krb5_write_message(context, &sock, &packet);
+ if(status)
+ krb5_err(context, 1, status, "krb5_write_message");
+
+ data.data = "hemligt";
+ data.length = 7;
+
+ krb5_data_free (&packet);
+
+ status = krb5_mk_priv (context,
+ auth_context,
+ &data,
+ &packet,
+ NULL);
+ if (status)
+ krb5_err(context, 1, status, "krb5_mk_priv");
+
+ status = krb5_write_message(context, &sock, &packet);
+ if(status)
+ krb5_err(context, 1, status, "krb5_write_message");
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int port = client_setup(&context, &argc, argv);
+ return client_doit (argv[argc], port, service, proto);
+}
diff --git a/third_party/heimdal/appl/test/uu_server.c b/third_party/heimdal/appl/test/uu_server.c
new file mode 100644
index 0000000..6e04699
--- /dev/null
+++ b/third_party/heimdal/appl/test/uu_server.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1997 - 2000, 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test_locl.h"
+RCSID("$Id$");
+
+krb5_context context;
+
+static int
+proto (int sock, const char *service)
+{
+ struct sockaddr_storage remote, local;
+ socklen_t addrlen;
+ krb5_address remote_addr, local_addr;
+ krb5_ccache ccache;
+ krb5_auth_context auth_context;
+ krb5_error_code status;
+ krb5_data packet;
+ krb5_data data;
+ krb5_data client_name;
+ krb5_creds in_creds, *out_creds;
+
+ addrlen = sizeof(local);
+ if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
+ || addrlen > sizeof(local))
+ err (1, "getsockname)");
+
+ addrlen = sizeof(remote);
+ if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
+ || addrlen > sizeof(remote))
+ err (1, "getpeername");
+
+ status = krb5_auth_con_init (context, &auth_context);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_init");
+
+ status = krb5_sockaddr2address (context, (struct sockaddr *)&local, &local_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_sockaddr2address(local)");
+ status = krb5_sockaddr2address (context, (struct sockaddr *)&remote, &remote_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_sockaddr2address(remote)");
+
+ status = krb5_auth_con_setaddrs (context,
+ auth_context,
+ &local_addr,
+ &remote_addr);
+ if (status)
+ krb5_err(context, 1, status, "krb5_auth_con_setaddr");
+
+ status = krb5_read_message(context, &sock, &client_name);
+ if(status)
+ krb5_err(context, 1, status, "krb5_read_message");
+
+ memset(&in_creds, 0, sizeof(in_creds));
+ status = krb5_cc_default(context, &ccache);
+ if(status)
+ krb5_err(context, 1, status, "krb5_cc_default");
+ status = krb5_cc_get_principal(context, ccache, &in_creds.client);
+ if(status)
+ krb5_err(context, 1, status, "krb5_cc_get_principal");
+
+ status = krb5_read_message(context, &sock, &in_creds.second_ticket);
+ if(status)
+ krb5_err(context, 1, status, "krb5_read_message");
+
+ status = krb5_parse_name(context, client_name.data, &in_creds.server);
+ if(status)
+ krb5_err(context, 1, status, "krb5_parse_name");
+
+ status = krb5_get_credentials(context, KRB5_GC_USER_USER, ccache,
+ &in_creds, &out_creds);
+ if(status)
+ krb5_err(context, 1, status, "krb5_get_credentials");
+ krb5_cc_close(context, ccache);
+ ccache = NULL;
+
+ status = krb5_cc_default(context, &ccache);
+ if(status)
+ krb5_err(context, 1, status, "krb5_cc_default");
+
+ status = krb5_sendauth(context,
+ &auth_context,
+ &sock,
+ VERSION,
+ in_creds.client,
+ in_creds.server,
+ AP_OPTS_USE_SESSION_KEY,
+ NULL,
+ out_creds,
+ ccache,
+ NULL,
+ NULL,
+ NULL);
+ krb5_cc_close(context, ccache);
+ ccache = NULL;
+
+ if (status)
+ krb5_err(context, 1, status, "krb5_sendauth");
+
+ {
+ char *str;
+ krb5_unparse_name(context, in_creds.server, &str);
+ printf ("User is `%s'\n", str);
+ free(str);
+ krb5_unparse_name(context, in_creds.client, &str);
+ printf ("Server is `%s'\n", str);
+ free(str);
+ }
+
+ krb5_free_principal(context, in_creds.client);
+ krb5_free_principal(context, in_creds.server);
+
+ krb5_data_zero (&data);
+ krb5_data_zero (&packet);
+
+ status = krb5_read_message(context, &sock, &packet);
+ if(status)
+ krb5_err(context, 1, status, "krb5_read_message");
+
+ status = krb5_rd_safe (context,
+ auth_context,
+ &packet,
+ &data,
+ NULL);
+ if (status)
+ krb5_err(context, 1, status, "krb5_rd_safe");
+
+ printf ("safe packet: %.*s\n", (int)data.length,
+ (char *)data.data);
+
+ status = krb5_read_message(context, &sock, &packet);
+ if(status)
+ krb5_err(context, 1, status, "krb5_read_message");
+
+ status = krb5_rd_priv (context,
+ auth_context,
+ &packet,
+ &data,
+ NULL);
+ if (status)
+ krb5_err(context, 1, status, "krb5_rd_priv");
+
+ printf ("priv packet: %.*s\n", (int)data.length,
+ (char *)data.data);
+
+ return 0;
+}
+
+static int
+doit (int port, const char *service)
+{
+ rk_socket_t sock;
+
+ mini_inetd(port, &sock);
+
+ return proto(sock, service);
+}
+
+int
+main(int argc, char **argv)
+{
+ int port = server_setup(&context, argc, argv);
+ return doit (port, service);
+}