summaryrefslogtreecommitdiffstats
path: root/src/lib/rpc/unit-test
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/rpc/unit-test')
-rw-r--r--src/lib/rpc/unit-test/Makefile97
-rw-r--r--src/lib/rpc/unit-test/client.c320
-rw-r--r--src/lib/rpc/unit-test/rpc_test.x30
-rw-r--r--src/lib/rpc/unit-test/server.c306
-rw-r--r--src/lib/rpc/unit-test/testsuite/Makefile24
-rw-r--r--src/lib/rpc/unit-test/testsuite/config/unix.exp79
-rw-r--r--src/lib/rpc/unit-test/testsuite/helpers.exp128
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp21
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp95
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp27
-rw-r--r--src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh56
11 files changed, 1183 insertions, 0 deletions
diff --git a/src/lib/rpc/unit-test/Makefile b/src/lib/rpc/unit-test/Makefile
new file mode 100644
index 0000000000..31853cb354
--- /dev/null
+++ b/src/lib/rpc/unit-test/Makefile
@@ -0,0 +1,97 @@
+# Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+#
+# $Id$
+# $Source$
+#
+# $Log$
+# Revision 1.9 1996/07/22 20:41:38 marc
+# this commit includes all the changes on the OV_9510_INTEGRATION and
+# OV_MERGE branches. This includes, but is not limited to, the new openvision
+# admin system, and major changes to gssapi to add functionality, and bring
+# the implementation in line with rfc1964. before committing, the
+# code was built and tested for netbsd and solaris.
+#
+# Revision 1.8.4.1 1996/07/18 04:20:01 marc
+# merged in changes from OV_9510_BP to OV_9510_FINAL1
+#
+# Revision 1.8.2.1 1996/06/20 23:41:48 marc
+# File added to the repository on a branch
+#
+# Revision 1.8 1995/12/07 17:36:54 jik
+# Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+# some systems. See PR 3553.
+#
+# Revision 1.7 1995/10/02 08:02:49 jik
+# Delete rpc-tset_clnt.c, rpc-test_svc.c and rpc-test.h before creating
+# them, because rpcgen on some platforms won't output to a file that
+# already exists.
+#
+# Revision 1.6 1994/10/24 19:35:57 bjaspan
+# [secure-build/2649: cannot use -L when compiling]
+#
+# Sandbox:
+#
+# [secure-build/2649] don't use -L
+#
+# Revision 1.7 1994/10/11 20:06:14 bjaspan
+# [secure-build/2649] don't use -L
+#
+# Revision 1.6 1994/09/30 22:25:29 jik
+# Don't need to set MDFLAGS to -a anymore, because it's done
+# automatically by the rules now.
+#
+# Revision 1.5 1994/03/22 19:55:34 shanzer
+# change NETLIBS to NETLIB
+#
+# Revision 1.4 1994/03/18 17:47:00 shanzer
+# added NETLIBS and BSDLIB
+#
+# Revision 1.3 1993/12/13 02:00:39 bjaspan
+# recurse to testsuite subdir.
+#
+# Revision 1.2 1993/12/08 21:45:47 bjaspan
+# misc
+#
+# Revision 1.1 1993/11/03 23:53:58 bjaspan
+# Initial revision
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+SUBDIRS = testsuite
+
+expand SubdirTarget
+
+SRCS = client.c server.c
+
+CFLAGS := -I../.. -I. $(CFLAGS)
+
+#LIBS = ../librpclib.a $(LIBGSSAPI_TRUST) $(LIBDB) $(LIBCOM_ERR) $(LIBDYN)
+LIBS = ../librpclib.a $(LIBGSSAPI_KRB5) $(LIBDB) $(LIBKRB5) \
+ $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR) $(LIBDYN) $(BSDLIB) $(NETLIB)
+DEPS = ../librpclib.a rpc_test.h
+DEPENDS = rpc_test.h
+
+PROG = client
+SRCS = client.c
+OBJS = client.o rpc_test_clnt.o
+
+expand Program
+expand Depend
+
+PROG = server
+SRCS = server.c
+OBJS = server.o rpc_test_svc.o
+
+expand Program
+expand Depend
+
+rpc_test.h rpc_test_clnt.c rpc_test_svc.c: rpc_test.x
+ -rm -f rpc_test_clnt.c rpc_test_svc.c rpc_test.h
+ rpcgen -l rpc_test.x -o rpc_test_clnt.c
+ rpcgen -m rpc_test.x -o rpc_test_svc.c
+ rpcgen -h rpc_test.x -o rpc_test.h
+
+clean::
+ rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c
new file mode 100644
index 0000000000..bcf2700e5e
--- /dev/null
+++ b/src/lib/rpc/unit-test/client.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.13 1996/07/22 20:41:40 marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches. This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964. before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.12.4.1 1996/07/18 04:20:03 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.12.2.1 1996/06/20 23:41:56 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.12 1996/05/12 06:58:10 marc
+ * type renamings for compatibility with beta6
+ *
+ * Revision 1.11 1996/02/12 15:58:42 grier
+ * [secure/3570]
+ * long conversion
+ *
+ * Revision 1.10 1995/12/07 17:37:03 jik
+ * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+ * some systems. See PR 3553.
+ *
+ * Revision 1.9 1994/09/21 18:38:56 bjaspan
+ * [secure-rpc/2536: unit test client.c: memory initialization and out-of-bounds reference bugs]
+ * [secure-releng/2537: audit secure-rpc/2536: minor memory problems in unit-test client]
+ *
+ * Sandbox:
+ *
+ * 1. Don't allow the count specifie on the command line to be bigger
+ * than the size of the buffer use for testing.
+ * 2. When initializing the buffer for the lengths test, initialize it to
+ * count bytes.
+ *
+ * Revision 1.9 1994/09/19 01:28:04 root
+ * 1. Don't allow the count specifie on the command line to be bigger
+ * than the size of the buffer use for testing.
+ * 2. When initializing the buffer for the lengths test, initialize it to
+ * count bytes.
+ *
+ * Revision 1.8 1994/04/06 22:13:01 jik
+ * Change -auth_once to -o, add -a, -m and -s arguments to set
+ * auth_debug_gssapi, svc_debug_gssapi and misc_debug_gssapi variables.
+ *
+ * Revision 1.7 1994/04/05 20:50:09 bjaspan
+ * fix typo that causes coredump when server blocks/fails
+ *
+ * Revision 1.6 1993/12/08 21:44:45 bjaspan
+ * test fix for secure-rpc/586, improve arg handlng
+ *
+ * Revision 1.5 1993/12/06 21:23:30 bjaspan
+ * accept count arg for RPC_TEST_LENGTHS
+ *
+ * Revision 1.4 1993/12/01 23:41:45 bjaspan
+ * don't free echo_resp if call fails
+ *
+ * Revision 1.3 1993/11/15 19:53:09 bjaspan
+ * test auto-syncrhonization
+ *
+ * Revision 1.2 1993/11/12 02:33:43 bjaspan
+ * use clnt_pcreateerror for auth failures
+ *
+ * Revision 1.1 1993/11/03 23:53:58 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <gssapi/gssapi.h>
+#include <rpc/rpc.h>
+#include <rpc/auth_gssapi.h>
+#include "rpc_test.h"
+
+#define BIG_BUF 4096
+/* copied from auth_gssapi.c for hackery */
+struct auth_gssapi_data {
+ bool_t established;
+ CLIENT *clnt;
+ gss_ctx_id_t context;
+ gss_buffer_desc client_handle;
+ OM_uint32 seq_num;
+ int def_cred;
+
+ /* pre-serialized ah_cred */
+ u_char cred_buf[MAX_AUTH_BYTES];
+ rpc_int32 cred_len;
+};
+#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
+
+extern int auth_debug_gssapi;
+char *whoami;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF];
+ CLIENT *clnt;
+ AUTH *tmp_auth;
+ struct rpc_err e;
+ int i, count, auth_once;
+ extern int optind;
+ extern char *optarg;
+ extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi;
+ int c;
+
+ whoami = argv[0];
+ count = 1026;
+ auth_once = 0;
+
+ while ((c = getopt(argc, argv, "a:m:os:")) != -1) {
+ switch (c) {
+ case 'a':
+ auth_debug_gssapi = atoi(optarg);
+ break;
+ case 'm':
+ misc_debug_gssapi = atoi(optarg);
+ break;
+ case 'o':
+ auth_once++;
+ break;
+ case 's':
+ svc_debug_gssapi = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ break;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ switch (argc) {
+ case 3:
+ count = atoi(argv[2]);
+ if (count > BIG_BUF) {
+ fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF);
+ usage();
+ }
+ case 2:
+ host = argv[0];
+ target = argv[1];
+ break;
+ default:
+ usage();
+ }
+
+ /* client handle to rstat */
+ clnt = clnt_create(host, RPC_TEST_PROG, RPC_TEST_VERS_1, "tcp");
+ if (clnt == NULL) {
+ clnt_pcreateerror(whoami);
+ exit(1);
+ }
+
+ clnt->cl_auth = auth_gssapi_create_default(clnt, target);
+ if (clnt->cl_auth == NULL) {
+ clnt_pcreateerror(whoami);
+ exit(2);
+ }
+
+ /*
+ * Call the echo service multiple times.
+ */
+ echo_arg = buf;
+ for (i = 0; i < 3; i++) {
+ sprintf(buf, "testing %d\n", i);
+
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL) {
+ fprintf(stderr, "RPC_TEST_ECHO call %d%s", i,
+ clnt_sperror(clnt, ""));
+ }
+ if (strncmp(*echo_resp, "Echo: ", 6) &&
+ strcmp(echo_arg, (*echo_resp) + 6) != 0)
+ fprintf(stderr, "RPC_TEST_ECHO call %d response wrong: "
+ "arg = %s, resp = %s\n", echo_arg, *echo_resp);
+ xdr_free(xdr_wrapstring, echo_resp);
+ }
+
+ /*
+ * Make a call with an invalid verifier and check for error;
+ * server should log error message. It is important to
+ *increment* seq_num here, since a decrement would be fixed (see
+ * below). Note that seq_num will be incremented (by
+ * authg_gssapi_refresh) twice, so we need to decrement by three
+ * to reset.
+ */
+ AUTH_PRIVATE(clnt->cl_auth)->seq_num++;
+
+ echo_arg = "testing with bad verf";
+
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL) {
+ CLNT_GETERR(clnt, &e);
+ if (e.re_status != RPC_AUTHERROR || e.re_why != AUTH_REJECTEDVERF)
+ clnt_perror(clnt, whoami);
+ } else {
+ fprintf(stderr, "bad seq didn't cause failure\n");
+ }
+
+ AUTH_PRIVATE(clnt->cl_auth)->seq_num -= 3;
+
+ /*
+ * Make sure we're resyncronized.
+ */
+ echo_arg = "testing for reset";
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL)
+ clnt_perror(clnt, "Sequence number improperly reset");
+
+ /*
+ * Now simulate a lost server response, and see if
+ * auth_gssapi_refresh recovers.
+ */
+ AUTH_PRIVATE(clnt->cl_auth)->seq_num--;
+ echo_arg = "forcing auto-resynchronization";
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL)
+ clnt_perror(clnt, "Auto-resynchronization failed");
+
+ /*
+ * Now make sure auto-resyncrhonization actually worked
+ */
+ echo_arg = "testing for resynchronization";
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL)
+ clnt_perror(clnt, "Auto-resynchronization did not work");
+
+ /*
+ * Test fix for secure-rpc/586, part 1: btree keys must be
+ * unique. Create another context from the same credentials; it
+ * should have the same expiration time and will cause the server
+ * to abort if the clients are not differentiated.
+ *
+ * Test fix for secure-rpc/586, part 2: btree keys cannot be
+ * mutated in place. To test this: a second client, *with a
+ * later expiration time*, must be run. The second client should
+ * destroy itself *after* the first one; if the key-mutating bug
+ * is not fixed, the second client_data will be in the btree
+ * before the first, but its key will be larger; thus, when the
+ * first client calls AUTH_DESTROY, the server won't find it in
+ * the btree and call abort.
+ *
+ * For unknown reasons, running just a second client didn't
+ * tickle the bug; the btree code seemed to guess which node to
+ * look at first. Running a total of three clients does ticket
+ * the bug. Thus, the full test sequence looks like this:
+ *
+ * kinit -l 20m user && client server test@ddn 200
+ * sleep 1
+ * kini -l 30m user && client server test@ddn 300
+ * sleep 1
+ * kinit -l 40m user && client server test@ddn 400
+ */
+ if (! auth_once) {
+ tmp_auth = clnt->cl_auth;
+ clnt->cl_auth = auth_gssapi_create_default(clnt, target);
+ if (clnt->cl_auth == NULL) {
+ clnt_pcreateerror(whoami);
+ exit(2);
+ }
+ AUTH_DESTROY(clnt->cl_auth);
+ clnt->cl_auth = tmp_auth;
+ }
+
+ /*
+ * Try RPC calls with argument/result lengths [0, 1025]. Do
+ * this last, since it takes a while..
+ */
+ echo_arg = buf;
+ memset(buf, 0, count);
+ for (i = 0; i < count; i++) {
+ echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+ if (echo_resp == NULL) {
+ fprintf(stderr, "RPC_TEST_LENGTHS call %d%s", i,
+ clnt_sperror(clnt, ""));
+ break;
+ } else {
+ if (strncmp(*echo_resp, "Echo: ", 6) &&
+ strcmp(echo_arg, (*echo_resp) + 6) != 0)
+ fprintf(stderr,
+ "RPC_TEST_LENGTHS call %d response wrong\n");
+ xdr_free(xdr_wrapstring, echo_resp);
+ }
+
+ /* cycle from 1 to 255 */
+ buf[i] = (i % 255) + 1;
+
+ if (i % 100 == 0) {
+ fputc('.', stdout);
+ fflush(stdout);
+ }
+ }
+ fputc('\n', stdout);
+
+ AUTH_DESTROY(clnt->cl_auth);
+ CLNT_DESTROY(clnt);
+ exit(0);
+}
+
+usage()
+{
+ fprintf(stderr, "usage: %s [-a] [-s num] [-m num] host service [count]\n",
+ whoami);
+ exit(1);
+}
diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/unit-test/rpc_test.x
new file mode 100644
index 0000000000..e9ae27c979
--- /dev/null
+++ b/src/lib/rpc/unit-test/rpc_test.x
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.2 1996/07/22 20:41:42 marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches. This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964. before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.1.4.1 1996/07/18 04:20:04 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+# Revision 1.1.2.1 1996/06/20 23:42:06 marc
+# File added to the repository on a branch
+#
+# Revision 1.1 1993/11/03 23:53:58 bjaspan
+# Initial revision
+#
+ */
+
+program RPC_TEST_PROG {
+ version RPC_TEST_VERS_1 {
+ string RPC_TEST_ECHO(string) = 1;
+ } = 1;
+} = 1000001;
diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c
new file mode 100644
index 0000000000..d98b2df0ba
--- /dev/null
+++ b/src/lib/rpc/unit-test/server.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ *
+ * $Log$
+ * Revision 1.15 1996/07/22 20:41:44 marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches. This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964. before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.14.4.1 1996/07/18 04:20:06 marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.14.2.1 1996/06/20 23:42:16 marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.14 1996/05/12 06:59:06 marc
+ * change SERVICE_NAME to "host" instead of "server"
+ *
+ * remove KRB5KTNAME support, since the library supports it internally now.
+ *
+ * Revision 1.13 1995/12/07 17:36:58 jik
+ * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on
+ * some systems. See PR 3553.
+ *
+ * Revision 1.12 1995/11/07 23:20:44 grier
+ * Add stdlib.h
+ * Add string.h
+ *
+ * Revision 1.11 1995/03/24 19:55:28 jik
+ * Cast a const gss_OID to (gss_OID) to prevent a compiler warning.
+ *
+ * Revision 1.10 1995/02/22 15:54:17 jik
+ * I was a moron in revision 1.8. This is the server function, not the
+ * client function, so it gets a struct svc_req *, not a CLIENT *.
+ *
+ * Revision 1.9 1995/02/22 15:21:51 jik
+ * Linux's rpcgen names the server function differently from the client
+ * function ("_svc" is appended to the end of it).
+ *
+ * Revision 1.8 1995/02/22 14:35:05 jik
+ * RPC server functions have CLIENT * passed into them, so I added it as
+ * an argument to rpc_test_echo_1.
+ *
+ * Revision 1.7 1994/09/21 18:35:57 bjaspan
+ * [gssapi/438: gss_nt_service_name should default to local host]
+ * [secure-releng/2513: audit gssapi/438: gss_nt_service_name should default to local host]
+ *
+ * Sandbox:
+ *
+ * Don't need to get local host name and put it in the service name,
+ * since the gssapi library does that now. See PR 438.
+ *
+ * Revision 1.8 1994/09/01 17:21:59 jik
+ * Don't need to get local host name and put it in the service name,
+ * since the gssapi library does that now. See PR 438.
+ *
+ * Revision 1.7 1994/04/08 17:22:11 bjaspan
+ * add KRB5KTNAME hack so unit tests continue to work
+ *
+ * Revision 1.6 1994/04/05 20:50:26 bjaspan
+ * print "running" when ready to tests can proceed
+ *
+ * Revision 1.5 1994/04/05 19:49:54 jik
+ * Use host name instead of localhost.
+ *
+ * Revision 1.4 1994/03/08 00:14:58 shanzer
+ * changed call to inet_ntoa
+ *
+ * Revision 1.3 1993/12/13 01:37:54 bjaspan
+ * update for new test system
+ * ,.
+ *
+ * Revision 1.2 1993/12/08 21:45:16 bjaspan
+ * display badauth errors, improve arg handling
+ *
+ * Revision 1.1 1993/11/03 23:53:58 bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <arpa/inet.h> /* inet_ntoa */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <rpc/auth_gssapi.h>
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include "rpc_test.h"
+
+#ifdef linux
+/*
+ For some reason, Linux's rpcgen names the server function
+ differently from the client function. I suppose this is useful if
+ you want to include them both in the same library or something, but
+ not useful at all if you want to link the client code directly to
+ the server code for testing, instead of going through the RPC layer.
+ */
+#define rpc_test_echo_1 rpc_test_echo_1_svc
+#endif
+
+extern void rpc_test_prog_1();
+
+extern int svc_debug_gssapi, misc_debug_gssapi;
+
+void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
+ struct sockaddr_in *addr, void *data);
+void log_badauth_display_status(OM_uint32 major, OM_uint32 minor);
+void log_badauth_display_status_1(OM_uint32 code, int type, int rec);
+static void rpc_test_badverf(gss_name_t client, gss_name_t server,
+ struct svc_req *rqst, struct rpc_msg *msg,
+ caddr_t data);
+
+#ifndef SERVICE_NAME
+#define SERVICE_NAME "host"
+#endif
+
+main(int argc, char **argv)
+{
+ auth_gssapi_name names[2];
+ register SVCXPRT *transp;
+
+ names[0].name = SERVICE_NAME;
+ names[0].type = (gss_OID) gss_nt_service_name;
+ names[1].name = 0;
+ names[1].type = 0;
+
+ switch (argc) {
+ case 3:
+ misc_debug_gssapi = atoi(argv[2]);
+ case 2:
+ svc_debug_gssapi = atoi(argv[1]);
+ case 1:
+ break;
+ default:
+ fprintf(stderr, "Usage: server [svc-debug] [misc-debug]\n");
+ exit(1);
+ }
+
+ (void) pmap_unset(RPC_TEST_PROG, RPC_TEST_VERS_1);
+
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (transp == NULL) {
+ fprintf(stderr, "cannot create tcp service.");
+ exit(1);
+ }
+ if (!svc_register(transp, RPC_TEST_PROG, RPC_TEST_VERS_1,
+ rpc_test_prog_1, IPPROTO_TCP)) {
+ fprintf(stderr,
+ "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, tcp).");
+ exit(1);
+ }
+
+ if (_svcauth_gssapi_set_names(names, 0) == FALSE) {
+ fprintf(stderr, "unable to set gssapi names\n");
+ exit(1);
+ }
+
+ _svcauth_gssapi_set_log_badauth_func(rpc_test_badauth, NULL);
+ _svcauth_gssapi_set_log_badverf_func(rpc_test_badverf, NULL);
+
+ printf("running\n");
+
+ svc_run();
+ fprintf(stderr, "svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
+
+char **rpc_test_echo_1(char **arg, struct svc_req *h)
+{
+ static char *res = NULL;
+
+ if (res)
+ free(res);
+ res = (char *) malloc(strlen(*arg) + strlen("Echo: ") + 1);
+ sprintf(res, "Echo: %s", *arg);
+ return &res;
+}
+
+static void rpc_test_badverf(gss_name_t client, gss_name_t server,
+ struct svc_req *rqst, struct rpc_msg *msg,
+ caddr_t data)
+{
+ OM_uint32 minor_stat;
+ gss_OID type;
+ gss_buffer_desc client_name, server_name;
+
+ (void) gss_display_name(&minor_stat, client, &client_name, &type);
+ (void) gss_display_name(&minor_stat, server, &server_name, &type);
+
+ printf("rpc_test server: bad verifier from %s at %s:%d for %s\n",
+ client_name.value,
+ inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr),
+ ntohs(rqst->rq_xprt->xp_raddr.sin_port),
+ server_name.value);
+
+ (void) gss_release_buffer(&minor_stat, &client_name);
+ (void) gss_release_buffer(&minor_stat, &server_name);
+}
+
+/*
+ * Function: log_badauth
+ *
+ * Purpose: Callback from GSS-API Sun RPC for authentication
+ * failures/errors.
+ *
+ * Arguments:
+ * major (r) GSS-API major status
+ * minor (r) GSS-API minor status
+ * addr (r) originating address
+ * data (r) arbitrary data (NULL), not used
+ *
+ * Effects:
+ *
+ * Logs the GSS-API error to stdout.
+ */
+void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
+ struct sockaddr_in *addr, void *data)
+{
+ char *a;
+
+ /* Authentication attempt failed: <IP address>, <GSS-API error */
+ /* strings> */
+
+ a = inet_ntoa(addr->sin_addr);
+
+ printf("rpc_test server: Authentication attempt failed: %s", a);
+ log_badauth_display_status(major, minor);
+ printf("\n");
+}
+
+void log_badauth_display_status(OM_uint32 major, OM_uint32 minor)
+{
+ log_badauth_display_status_1(major, GSS_C_GSS_CODE, 0);
+ log_badauth_display_status_1(minor, GSS_C_MECH_CODE, 0);
+}
+
+void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
+{
+ OM_uint32 gssstat, minor_stat;
+ gss_buffer_desc msg;
+ int msg_ctx;
+
+ msg_ctx = 0;
+ while (1) {
+ gssstat = gss_display_status(&minor_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ if (gssstat != GSS_S_COMPLETE) {
+ if (!rec) {
+ log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1);
+ log_badauth_display_status_1(minor_stat,
+ GSS_C_MECH_CODE, 1);
+ } else
+ printf("GSS-API authentication error %s: "
+ "recursive failure!\n", msg);
+ return;
+ }
+
+ printf(", %s", (char *)msg.value);
+ (void) gss_release_buffer(&minor_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
+
+
+#if 0
+
+/* this hack is no longer necessary, since the library supports it
+ internally */
+
+/* This is a hack to change the default keytab name */
+
+#include <krb5/krb5.h>
+extern char *krb5_defkeyname;
+
+krb5_error_code
+krb5_kt_default_name(char *name, int namesize)
+{
+ char *ktname;
+
+ if ((ktname = getenv("KRB5KTNAME")) == NULL)
+ ktname = krb5_defkeyname;
+
+ if (namesize < strlen(ktname)+1)
+ return(KRB5_CONFIG_NOTENUFSPACE);
+
+ strcpy(name, ktname);
+
+ return(0);
+}
+
+#endif
diff --git a/src/lib/rpc/unit-test/testsuite/Makefile b/src/lib/rpc/unit-test/testsuite/Makefile
new file mode 100644
index 0000000000..8a2cccdc2d
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/Makefile
@@ -0,0 +1,24 @@
+#
+# $Id$
+#
+
+TOP = ../../..
+include $(TOP)/config.mk/template
+
+export RPC_TEST_SRVTAB := /tmp/rpc_test_v5srvtab
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(START_SERVERS)
+ ./rpc_test_setup.sh
+
+unit-test-body::
+ $(RUNTEST) SERVER=../server CLIENT=../client --tool rpc_test
+
+unit-test-cleanup::
+ $(STOP_SERVERS)
+ -rm -f /tmp/rpc_test_v5srvtab /tmp/krb5cc_rpc_test_fullrun
+
+clean::
+ $(CLEAN) rpc_test.log rpc_test.plog rpc_test.sum rpc_test.psum
diff --git a/src/lib/rpc/unit-test/testsuite/config/unix.exp b/src/lib/rpc/unit-test/testsuite/config/unix.exp
new file mode 100644
index 0000000000..030837d49a
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/config/unix.exp
@@ -0,0 +1,79 @@
+#
+# $Id$
+#
+
+set kill /bin/kill
+set sleep /bin/sleep
+set kinit $env(TOP)/install/bin/kinit
+set kdestroy $env(TOP)/install/bin/kdestroy
+
+set hostname [exec hostname]
+
+proc rpc_test_version {} {
+ global CLIENT
+ global SERVER
+
+ clone_output "$CLIENT version <unknown>"
+ clone_output "$SERVER version <unknown>"
+}
+
+proc rpc_test_load {} {
+ #
+}
+
+# rpc_test_exit -- clean up and exit
+proc rpc_test_exit {} {
+ global server_id
+ global server_pid
+ global server_started
+ global kill
+
+ if {[catch {
+ expect {
+ -i $server_id
+ eof {
+ fail "server exited!"
+ verbose $expect_out(buffer) 1
+ }
+ timeout { pass "server survived" }
+ }
+ } tmp]} {
+ fail "server exited! (expect failed)"
+ }
+}
+
+#
+# rpc_test_start -- start the rpc_test server running
+#
+proc rpc_test_start { } {
+ global SERVER
+ global server_id
+ global server_pid
+ global server_started
+ global env
+
+ set env(KRB5KTNAME) FILE:$env(RPC_TEST_SRVTAB)
+
+ verbose "% $SERVER" 1
+ set server_pid [spawn $SERVER]
+ set server_id $spawn_id
+
+ unset env(KRB5KTNAME)
+
+ set timeout 30
+
+ expect {
+ "running" { }
+ eof {
+ fail "server exited!"
+ verbose $expect_out(buffer) 1
+ }
+ timeout {
+ fail "server didn't start in $timeout seconds"
+ verbose $expect_out(buffer) 1
+ }
+ }
+
+}
+
+rpc_test_start
diff --git a/src/lib/rpc/unit-test/testsuite/helpers.exp b/src/lib/rpc/unit-test/testsuite/helpers.exp
new file mode 100644
index 0000000000..1a37ad512a
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/helpers.exp
@@ -0,0 +1,128 @@
+if {[info commands exp_version] != {}} {
+ set exp_version_4 [regexp {^4} [exp_version]]
+} else {
+ set exp_version_4 [regexp {^4} [expect_version]]
+}
+
+# Backward compatibility until we're using expect 5 everywhere
+if {$exp_version_4} {
+ global wait_error_index wait_errno_index wait_status_index
+ set wait_error_index 0
+ set wait_errno_index 1
+ set wait_status_index 1
+} else {
+ set wait_error_index 2
+ set wait_errno_index 3
+ set wait_status_index 3
+}
+
+
+proc kinit {princ pass lifetime} {
+ global kinit
+ global wait_error_index wait_errno_index wait_status_index
+
+ spawn -noecho $kinit -l $lifetime $princ
+ expect {
+ -re "Password for $princ.*: " { send "$pass\n" }
+ timeout { error "Timeout waiting for kinit"; close }
+ }
+ expect { eof {} }
+
+ set ret [wait]
+ if {[lindex $ret $wait_error_index] == -1} {
+ error \
+ "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]"
+ } else {
+ if {[lindex $ret $wait_status_index] != 0} {
+ error \
+ "kinit $princ failed with [lindex $ret $wait_status_index]"
+ }
+ }
+}
+
+proc flush_server {} {
+ global server_id
+ global expect_out
+
+ verbose "flushing server output" 1
+
+ while {1} {
+ set timeout 5
+
+ expect {
+ -i $server_id
+ -re "^.+$" {
+ verbose "server output: $expect_out(buffer)"
+ }
+ timeout { break }
+ }
+ }
+}
+
+proc start_client {testname ccname user password lifetime count
+ {target ""}} {
+ global env
+ global CLIENT
+ global hostname
+ global spawn_id
+ global verbose
+
+ if {$target == ""} {
+ set target "server@$hostname"
+ }
+
+ set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname
+ kinit $user $password $lifetime
+
+ if {$verbose > 0} {
+ spawn $CLIENT -a 1 -s 1 -m 1 $hostname $target $count
+ } else {
+ spawn $CLIENT $hostname $target $count
+ }
+
+ verbose "$testname: client $ccname started"
+
+ unset env(KRB5CCNAME)
+}
+
+proc eof_client {testname ccname id status} {
+ verbose "$testname: eof'ing for client $ccname" 1
+
+ expect {
+ -i $id
+ eof { verbose $expect_out(buffer) 1 }
+ timeout {
+ fail "$testname: timeout waiting for client $ccname to exit"
+ }
+ }
+ wait_client $testname $ccname $id $status
+}
+
+
+proc wait_client {testname ccname id status} {
+ global env
+ global kill
+ global kdestroy
+ global wait_error_index wait_errno_index wait_status_index
+
+ verbose "$testname: waiting for client $ccname" 1
+
+ set ret [wait -i $id]
+ if {[lindex $ret $wait_error_index] == -1} {
+ fail \
+ "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]"
+ } else {
+ if {[lindex $ret $wait_status_index] == $status} {
+ pass "$testname: client $ccname"
+ } else {
+ fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status."
+ }
+ }
+
+ set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname
+ if {[catch "exec $kdestroy"] != 0} {
+ error "$testname: cannot destroy client $ccname ccache"
+ }
+
+ unset env(KRB5CCNAME)
+}
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp
new file mode 100644
index 0000000000..d80bae6dae
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp
@@ -0,0 +1,21 @@
+set timeout 40
+
+load_lib "helpers.exp"
+
+global spawn_id
+
+start_client expire 1 testuser notathena 20m 100
+set client1_id $spawn_id
+flush_server
+
+start_client expire 2 testuser notathena 40m 300
+set client2_id $spawn_id
+flush_server
+
+start_client expire 3 testuser notathena 60m 500
+set client3_id $spawn_id
+flush_server
+
+eof_client expire 1 $client1_id 0
+eof_client expire 2 $client2_id 0
+eof_client expire 3 $client3_id 0
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp
new file mode 100644
index 0000000000..6e8acf80e8
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp
@@ -0,0 +1,95 @@
+set timeout 120
+
+load_lib "helpers.exp"
+
+global spawn_id
+global server_id
+
+# Start the client and do a full run
+start_client "full run" fullrun testuser notathena 8 1026
+set client_id $spawn_id
+
+#
+# test: did we get 11 dots?
+#
+verbose "Starting RPC echo test. This will take about 50 seconds.\n"
+
+set ver_line "rpc_test server: bad verifier\[^\r\n\]*\n"
+
+set dots 0
+set server_lines 0
+while {1} {
+ set oldtimeout $timeout
+ set timeout 5
+ while {1} {
+ expect {
+ -i $server_id
+ -re $ver_line {
+ verbose "Got line from server."
+ incr server_lines
+ }
+ default {
+ break
+ }
+ }
+ }
+ set timeout $oldtimeout
+ expect {
+ -i $client_id
+ . {
+ incr dots
+ verbose "$expect_out(buffer)" 1
+ if ($dots==11) { break }
+ }
+ eof {
+ #
+ # test: was the exit status right?
+ #
+ wait_client "full run" fullrun $client_id 0
+ break
+ }
+
+ timeout {
+ verbose "Timeout waiting for dot\n" 1
+ fail "full run: timeout waiting for dot"
+ break
+ }
+
+ }
+}
+if {$dots==11} {
+ pass "fullrun: echo test"
+} else {
+ fail "fullrun: echo test: expected 11 dots, got $dots"
+}
+
+#
+# test: server logged four bad verifiers?
+#
+verbose "full run: checking server output"
+
+# Small timeout, since the server should have already printed everything
+set timeout 5
+
+while {$server_lines < 4} {
+ expect {
+ -i $server_id
+ -re $ver_line {
+ incr server_lines
+ }
+ -re ".+\r\n" {
+ verbose "Unexpected server output: $expect_out(buffer)"
+ }
+ default {
+ break
+ }
+ }
+}
+
+if {$server_lines == 4} {
+ pass "fullrun: bad verifiers"
+} else {
+ fail "fullrun: expected four bad verifiers, got $server_lines"
+}
+
+flush_server
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp
new file mode 100644
index 0000000000..f9d53052de
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp
@@ -0,0 +1,27 @@
+set timeout 30
+
+load_lib "helpers.exp"
+
+global spawn_id
+global server_id
+global hostname
+
+start_client "gss err" gsserr testuser notathena 8 1026 notserver@$hostname
+
+eof_client "gss err" gsserr $spawn_id 2
+
+#
+# test: server logged an authentication attempted failed?
+#
+verbose "gss err: checking server output"
+
+expect {
+ -i $server_id
+ -re "rpc_test server: Authent.*failed: .* Wrong princ" {
+ pass "gss err: server logged auth error"
+ }
+ eof { fail "gss err: server exited" }
+ timeout { fail "gss err: timeout waiting for server output" }
+}
+
+flush_server
diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh
new file mode 100644
index 0000000000..2a97af4d3c
--- /dev/null
+++ b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# This script performs additional setup for the RPC unit test. It
+# assumes that gmake has put TOP and RPC_TEST_SRVTAB into the
+# environment.
+#
+# $Id$
+# $Source$
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${CLNTTCL=$TESTDIR/util/ovsec_kadm_clnt_tcl}
+DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL
+DUMMY=${MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+if $VERBOSE; then
+ REDIRECT=
+else
+ REDIRECT='>/dev/null'
+fi
+
+PATH=$TOP/install/admin:$PATH; export PATH
+
+CANON_HOST=`perl -e 'chop($_=\`hostname\`);($n,$a,$t,$l,@a)=gethostbyname($_);($_)=gethostbyaddr($a[0],$t); print;'`
+export CANON_HOST
+
+eval $CLNTTCL <<'EOF' $REDIRECT
+source $env(TCLUTIL)
+set h $env(CANON_HOST)
+puts stdout [ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle]
+puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal server/$h] {OVSEC_KADM_PRINCIPAL} admin]
+puts stdout [ovsec_kadm_randkey_principal $server_handle server/$h key]
+puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal notserver/$h] {OVSEC_KADM_PRINCIPAL} admin]
+puts stdout [ovsec_kadm_randkey_principal $server_handle notserver/$h key]
+puts stdout [ovsec_kadm_destroy $server_handle]
+EOF
+
+rm -f $RPC_TEST_SRVTAB
+
+eval $MAKE_KEYTAB -princ server/$CANON_HOST $RPC_TEST_SRVTAB $REDIRECT
+
+grep -s "$CANON_HOST SECURE-TEST.OV.COM" /etc/krb.realms
+if [ $? != 0 ]; then
+ eval echo \"Adding \$CANON_HOST SECURE-TEST.OV.COM to /etc/krb.realms\" $REDIRECT
+ ed /etc/krb.realms <<EOF >/dev/null
+1i
+$CANON_HOST SECURE-TEST.OV.COM
+.
+w
+q
+EOF
+fi