diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /third_party/heimdal/appl | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/appl')
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,®pag_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); +} |