--- /dev/null
+# $Source$
+# $Author$
+# $Id$
+#
+# Copyright 1990,1991 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+# require a specific license from the United States Government.
+# It is the responsibility of any person or organization contemplating
+# export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission. M.I.T. makes no representations about the suitability of
+# this software for any purpose. It is provided "as is" without express
+# or implied warranty.
+#
+#
+
+SRCS= gss-client.c gss-misc.c gss-server.c
+
+DEPLIBS= $(TOP)/lib/gssapi/libgssapi_krb5.a $(DEPKLIB)
+LIBS= $(TOP)/lib/gssapi/libgssapi_krb5.a $(KLIB)
+
+all:: gss-client gss-server
+
+NormalProgramTarget(gss-client,gss-client.o gss-misc.o,$(DEPLIBS),$(LIBS),)
+Krb5InstallClientProgram(gss-client)
+
+NormalProgramTarget(gss-server,gss-server.o gss-misc.o,$(DEPLIBS),$(LIBS),)
+Krb5InstallServerProgram(gss-server)
+
+DependTarget()
--- /dev/null
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+DEFS = @DEFS@
+LIBS = @LIBS@
+
+CFLAGS = -g $(DEFS) $(LOCALINCLUDE)
+LDFLAGS = -g
+
+BUILDTOP=../..
+SRCTOP = $(srcdir)/$(BUILDTOP)
+TOPLIBD = $(BUILDTOP)/lib
+ISODELIB=$(TOPLIBD)/libisode.a
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+DBMLIB=
+
+all::
+
+KLIB = $(TOPLIBD)/gssapi/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a \
+ $(TOPLIBD)/libcrypto.a $(ISODELIB) $(COMERRLIB) $(DBMLIB)
+
+gss-server: gss-server.o gss-misc.o
+ $(CC) $(CFLAGS) -o gss-server gss-server.o gss-misc.o $(KLIB) $(LIBS)
+
+gss-client: gss-client.o gss-misc.o
+ $(CC) $(CFLAGS) -o gss-client gss-client.o gss-misc.o $(KLIB) $(LIBS)
+
+gss-client.o: $(srcdir)/gss-client.o
+
+gss-misc.o: $(srcdir)/gss-misc.o
+
+gss-server.o: $(srcdir)/gss-server.o
+
+
+all:: gss-server gss-client
+
+
+clean::
+ $(RM) kinit.o kinit
+
+install::
+ $(INSTALLPROG) kinit ${DESTDIR}$(CLIENT_BINDIR)/kinit
+ $(INSTALLPROG) kinit.M ${DESTDIR}$(CLIENT_MANDIR)/kinit.$(CLIENT_MANSUFFIX)
--- /dev/null
+# Copyright 1993 by OpenVision Technologies, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose. It is provided "as is" without express or implied warranty.
+#
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+This directory contains a sample GSS-API client and server
+application. Each invocation of the client performs the following
+exchange with the server:
+
+ 1. The client and server establish a GSS-API context. The
+ server prints the identity of the client.
+
+ 2. The client sends a sealed (encrypted) message to the
+ server.
+
+ 3. The server decrypts the message and prints it.
+
+ 4. The server produces a signature block for the message and
+ sends it to the client.
+
+ 5. The client verifies the signature block.
+
+Obviously, this exchange does not perform a tremendously valuable
+function; however, it demostrates the use of primary GSS-API
+interfaces.
+
+The server's command line usage is
+
+ gss-server [-port port] service_name
+
+where service_name is a GSS-API service name of the form
+"service@host". The server will accept TCP connections on port
+(default 4444) and establish contexts as service_name.
+
+The client's command line usage is
+
+ gss-client [-port port] host service_name msg
+
+where host is the host running the server, service_name is the service
+name that the server will establish connections as, and msg is the
+message. The client connects to the TCP on <host:port> (default 4444)
+and performs the exchange.
+
+If you are using this sample application with OpenVision's Kerberos 5
+GSS-API mechanism:
+
+1. Link the client and server with -lgssapi_krb5 -lkrb5 -lcrypto
+-lisode -lcom_err.
+
+2. Make sure that the principal corresponding to service_name is in
+the default keytab on the server host, and that the gss-server process
+can read the keytab. For example, the service name "host@server"
+corresponds to the Kerberos principal "host/server.domain.com@REALM".
+
+This sample application uses the following GSS-API functions:
+
+ gss_accept_sec_context gss_release_buffer
+ gss_acquire_cred gss_release_cred
+ gss_delete_sec_context gss_release_name
+ gss_display_name gss_seal
+ gss_display_status gss_sign
+ gss_import_name gss_unseal
+ gss_init_sec_context gss_verify
+
+Barry Jaspan, bjaspan@security.ov.com
+OpenVision Technologies, Inc.
+
+$Id$
--- /dev/null
+AC_INIT(klist.c)
+AC_HAVE_LIBRARY(socket)
+AC_HAVE_LIBRARY(nsl)
+CONFIG_RULES
+KRB_INCLUDE
+ISODE_INCLUDE
+AC_OUTPUT(Makefile,[EXTRA_RULES])
--- /dev/null
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+int establish_context(int s, char *service_name, gss_ctx_id_t *gss_context);
+int connect_to_server(char *host, u_short port);
+int call_server(char *host, u_short port, char *service_name, char *msg);
+
+int send_token(int s, gss_buffer_t tok);
+int recv_token(int s, gss_buffer_t tok);
+void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+
+usage()
+{
+ fprintf(stderr, "Usage: gss-client [-port port] host service msg\n");
+ exit(1);
+}
+
+main(int argc, char **argv)
+{
+ char *service_name, *server_host, *msg;
+ u_short port = 4444;
+
+ /* Parse arguments. */
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "-port") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ port = atoi(*argv);
+ } else
+ break;
+ argc--; argv++;
+ }
+ if (argc != 3)
+ usage();
+
+ server_host = *argv++;
+ service_name = *argv++;
+ msg = *argv++;
+
+ if (call_server(server_host, port, service_name, msg) < 0)
+ exit(1);
+
+ return 0;
+}
+
+/*
+ * Function: call_server
+ *
+ * Purpose: Call the "sign" service.
+ *
+ * Arguments:
+ *
+ * host (r) the host providing the service
+ * port (r) the port to connect to on host
+ * service_name (r) the GSS-API service name to authenticate to
+ * msg (r) the message to have "signed"
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * call_server opens a TCP connection to <host:port> and establishes a
+ * GSS-API context with service_name over the connection. It then
+ * seals msg in a GSS-API token with gss_seal, sends it to the server,
+ * reads back a GSS-API signature block for msg from the server, and
+ * verifies it with gss_verify. -1 is returned if any step fails,
+ * otherwise 0 is returned.
+ */
+int call_server(char *host, u_short port, char *service_name, char *msg)
+{
+ gss_ctx_id_t context;
+ gss_buffer_desc in_buf, out_buf;
+ int s, state;
+ OM_uint32 maj_stat, min_stat;
+
+ /* Open connection */
+ if ((s = connect_to_server(host, port)) < 0)
+ return -1;
+
+ /* Establish context */
+ if (client_establish_context(s, service_name, &context) < 0)
+ return -1;
+
+ /* Seal the message */
+ in_buf.value = msg;
+ in_buf.length = strlen(msg) + 1;
+ maj_stat = gss_seal(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
+ &in_buf, &state, &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("sealing message", maj_stat, min_stat);
+ return -1;
+ } else if (! state) {
+ fprintf(stderr, "Warning! Message not encrypted.\n");
+ }
+
+ /* Send to server */
+ if (send_token(s, &out_buf) < 0)
+ return -1;
+ (void) gss_release_buffer(&min_stat, &out_buf);
+
+ /* Read signature block into out_buf */
+ if (recv_token(s, &out_buf) < 0)
+ return -1;
+
+ /* Verify signature block */
+ maj_stat = gss_verify(&min_stat, context, &in_buf, &out_buf, &state);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("verifying signature", maj_stat, min_stat);
+ return -1;
+ }
+ (void) gss_release_buffer(&min_stat, &out_buf);
+
+ printf("Signature verified.\n");
+
+ /* Delete context */
+ maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("deleting context", maj_stat, min_stat);
+ return -1;
+ }
+ (void) gss_release_buffer(&min_stat, &out_buf);
+
+ return 0;
+}
+
+/*
+ * Function: connect_to_server
+ *
+ * Purpose: Opens a TCP connection to the name host and port.
+ *
+ * Arguments:
+ *
+ * host (r) the target host name
+ * port (r) the target port, in host byte order
+ *
+ * Returns: the established socket file desciptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * The host name is resolved with gethostbyname(), and the socket is
+ * opened and connected. If an error occurs, an error message is
+ * displayed and -1 is returned.
+ */
+int connect_to_server(char *host, u_short port)
+{
+ struct sockaddr_in saddr;
+ struct hostent *hp;
+ int s;
+
+ if ((hp = gethostbyname(host)) == NULL) {
+ fprintf(stderr, "Unknown host: %s\n", host);
+ return -1;
+ }
+
+ saddr.sin_family = hp->h_addrtype;
+ memcpy((char *)&saddr.sin_addr, hp->h_addr, hp->h_length);
+ saddr.sin_port = htons(port);
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("creating socket");
+ return -1;
+ }
+ if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ perror("connecting to server");
+ return -1;
+ }
+ return s;
+}
+
+/*
+ * Function: client_establish_context
+ *
+ * Purpose: establishes a GSS-API context with a specified service and
+ * returns the context handle
+ *
+ * Arguments:
+ *
+ * s (r) an established TCP connection to the service
+ * service_name (r) the ASCII service name of the service
+ * context (w) the established GSS-API context
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * service_name is imported as a GSS-API name and a GSS-API context is
+ * established with the corresponding service; the service should be
+ * listening on the TCP connection s. The default GSS-API mechanism
+ * is used, and mutual authentication and replay detection are
+ * requested.
+ *
+ * If successful, the context handle is returned in context. If
+ * unsuccessful, the GSS-API error messages are displayed on stderr
+ * and -1 is returned.
+ */
+int client_establish_context(int s, char *service_name,
+ gss_ctx_id_t *gss_context)
+{
+ gss_buffer_desc send_tok, recv_tok, *token_ptr;
+ gss_name_t target_name;
+ OM_uint32 maj_stat, min_stat;
+
+ /*
+ * Import the name into target_name. Use send_tok to save
+ * local variable space.
+ */
+ send_tok.value = service_name;
+ send_tok.length = strlen(service_name) + 1;
+ maj_stat = gss_import_name(&min_stat, &send_tok,
+ gss_nt_service_name, &target_name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("parsing name", maj_stat, min_stat);
+ return -1;
+ }
+
+ /*
+ * Perform the context-establishement loop.
+ *
+ * On each pass through the loop, token_ptr points to the token
+ * to send to the server (or GSS_C_NO_BUFFER on the first pass).
+ * Every generated token is stored in send_tok which is then
+ * transmitted to the server; every received token is stored in
+ * recv_tok, which token_ptr is then set to, to be processed by
+ * the next call to gss_init_sec_context.
+ *
+ * GSS-API guarantees that send_tok's length will be non-zero
+ * if and only if the server is expecting another token from us,
+ * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
+ * and only if the server has another token to send us.
+ */
+
+ token_ptr = GSS_C_NO_BUFFER;
+ *gss_context = GSS_C_NO_CONTEXT;
+
+ do {
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ gss_context,
+ target_name,
+ GSS_C_NULL_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ NULL, /* no channel bindings */
+ token_ptr,
+ NULL, /* ignore mech type */
+ &send_tok,
+ NULL, /* ignore ret_flags */
+ NULL); /* ignore time_rec */
+
+ if (token_ptr != GSS_C_NO_BUFFER)
+ (void) gss_release_buffer(&min_stat, &recv_tok);
+
+ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+ display_status("initializing context", maj_stat, min_stat);
+ (void) gss_release_name(&min_stat, &target_name);
+ return -1;
+ }
+
+ if (send_tok.length != 0) {
+ if (send_token(s, &send_tok) < 0) {
+ (void) gss_release_buffer(&min_stat, &send_tok);
+ (void) gss_release_name(&min_stat, &target_name);
+ return -1;
+ }
+ }
+ (void) gss_release_buffer(&min_stat, &send_tok);
+
+ if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+ if (recv_token(s, &recv_tok) < 0) {
+ (void) gss_release_name(&min_stat, &target_name);
+ return -1;
+ }
+ token_ptr = &recv_tok;
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ (void) gss_release_name(&min_stat, &target_name);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+static void display_status_1(char *m, OM_uint32 code, int type);
+
+/*
+ * Function: send_token
+ *
+ * Purpose: Writes a token to a file descriptor.
+ *
+ * Arguments:
+ *
+ * s (r) an open file descriptor
+ * tok (r) the token to write
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * send_token writes the token length (as a network long) and then the
+ * token data to the file descriptor s. It returns 0 on success, and
+ * -1 if an error occurs or if it could not write all the data.
+ */
+int send_token(int s, gss_buffer_t tok)
+{
+ int len, ret;
+
+ len = htonl(tok->length);
+
+ ret = write(s, (char *) &len, 4);
+ if (ret < 0) {
+ perror("sending token length");
+ return -1;
+ } else if (ret != 4) {
+ fprintf(stderr, "sending token length: %d of %d bytes written\n",
+ ret, 4);
+ return -1;
+ }
+
+ ret = write(s, tok->value, tok->length);
+ if (ret < 0) {
+ perror("sending token data");
+ return -1;
+ } else if (ret != tok->length) {
+ fprintf(stderr, "sending token data: %d of %d bytes written\n",
+ ret, tok->length);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: recv_token
+ *
+ * Purpose: Reads a token from a file descriptor.
+ *
+ * Arguments:
+ *
+ * s (r) an open file descriptor
+ * tok (w) the read token
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * recv_token reads the token length (as a network long), allocates
+ * memory to hold the data, and then reads the token data from the
+ * file descriptor s. It blocks to read the length and data, if
+ * necessary. On a successful return, the token should be freed with
+ * gss_release_buffer. It returns 0 on success, and -1 if an error
+ * occurs or if it could not read all the data.
+ */
+int recv_token(int s, gss_buffer_t tok)
+{
+ int ret;
+
+ ret = read(s, (char *) &tok->length, 4);
+ if (ret < 0) {
+ perror("reading token length");
+ return -1;
+ } else if (ret != 4) {
+ fprintf(stderr, "reading token length: %d of %d bytes read\n",
+ ret, 4);
+ return -1;
+ }
+
+ tok->length = ntohl(tok->length);
+ tok->value = (char *) malloc(tok->length);
+ if (tok->value == NULL) {
+ fprintf(stderr, "Out of memory allocating token data\n");
+ return -1;
+ }
+
+ ret = read(s, (char *) tok->value, tok->length);
+ if (ret < 0) {
+ perror("reading token data");
+ free(tok->value);
+ return -1;
+ } else if (ret != tok->length) {
+ fprintf(stderr, "sending token data: %d of %d bytes written\n",
+ ret, tok->length);
+ free(tok->value);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: display_status
+ *
+ * Purpose: displays GSS-API messages
+ *
+ * Arguments:
+ *
+ * msg a string to be displayed with the message
+ * maj_stat the GSS-API major status code
+ * min_stat the GSS-API minor status code
+ *
+ * Effects:
+ *
+ * The GSS-API messages associated with maj_stat and min_stat are
+ * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
+ * followed by a newline.
+ */
+void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+ display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+ display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static void display_status_1(char *m, OM_uint32 code, int type)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc msg;
+ int msg_ctx;
+
+ msg_ctx = 0;
+ while (1) {
+ maj_stat = gss_display_status(&min_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ fprintf(stderr, "GSS-API error %s: %s\n", m,
+ (char *)msg.value);
+ (void) gss_release_buffer(&min_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+}
--- /dev/null
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+int create_socket(u_short port);
+
+int send_token(int s, gss_buffer_t tok);
+int recv_token(int s, gss_buffer_t tok);
+void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+
+usage()
+{
+ fprintf(stderr, "Usage: gss-server [-port port] service_name\n");
+ exit(1);
+}
+
+main(int argc, char **argv)
+{
+ struct sockaddr_in saddr;
+ char *service_name;
+ u_short port = 4444;
+ int s;
+
+ argc--; argv++;
+ while (argc) {
+ if (strcmp(*argv, "-port") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ port = atoi(*argv);
+ } else
+ break;
+ argc--; argv++;
+ }
+ if (argc != 1)
+ usage();
+
+ service_name = *argv;
+
+ if ((s = create_socket(port)) < 0)
+ exit(1);
+
+ if (sign_server(s, service_name) < 0)
+ exit(1);
+
+ /*NOTREACHED*/
+ return 0;
+}
+
+/*
+ * Function: create_socket
+ *
+ * Purpose: Opens a listening TCP socket.
+ *
+ * Arguments:
+ *
+ * port (r) the port number on which to listen
+ *
+ * Returns: the listening socket file descriptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * A listening socket on the specified port and created and returned.
+ * On error, an error message is displayed and -1 is returned.
+ */
+int create_socket(u_short port)
+{
+ struct sockaddr_in saddr;
+ int s;
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+ saddr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("creating socket");
+ return -1;
+ }
+ if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+ perror("binding socket");
+ return -1;
+ }
+ if (listen(s, 5) < 0) {
+ perror("listening on socket");
+ return -1;
+ }
+ return s;
+}
+
+/*
+ * Function: sign_server
+ *
+ * Purpose: Performs the "sign" service.
+ *
+ * Arguments:
+ *
+ * s (r) a TCP socket on which to listen for connections
+ * service_name (r) the ASCII name of the GSS-API service to
+ * establish a context as
+ *
+ * Returns: -1 on error
+ *
+ * Effects:
+ *
+ * sign_server acquires GSS-API credentials for service_name and then
+ * loops forever accepting TCP connections on s, establishing a
+ * context, and performing a single sign request.
+ *
+ * A sign request is a single GSS-API sealed token. The token is
+ * unsealed and a signature block, produced with gss_sign, is returned
+ * to the sender. The context is the destroyed and the connection
+ * closed.
+ *
+ * If any error occurs, -1 is returned.
+ */
+int sign_server(int s, char *service_name)
+{
+ gss_cred_id_t server_creds;
+ gss_buffer_desc client_name, xmit_buf, msg_buf;
+ gss_ctx_id_t context;
+ OM_uint32 maj_stat, min_stat;
+ int s2;
+
+ if (server_acquire_creds(service_name, &server_creds) < 0)
+ return -1;
+
+ while (1) {
+ /* Accept a TCP connection */
+ if ((s2 = accept(s, NULL, 0)) < 0) {
+ perror("accepting connection");
+ exit(1);
+ }
+
+ /* Establish a context with the client */
+ if (server_establish_context(s2, server_creds, &context,
+ &client_name) < 0)
+ break;
+
+ printf("Accepted connection: \"%s\"\n", client_name.value);
+ (void) gss_release_buffer(&min_stat, &client_name);
+
+ /* Receive the sealed message token */
+ if (recv_token(s2, &xmit_buf) < 0)
+ break;
+
+ /* Unseal the message token */
+ maj_stat = gss_unseal(&min_stat, context, &xmit_buf,
+ &msg_buf, NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("unsealing message", maj_stat, min_stat);
+ break;
+ }
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+
+ printf("Received message: \"%s\"\n", msg_buf.value);
+
+ /* Produce a signature block for the message */
+ maj_stat = gss_sign(&min_stat, context, GSS_C_QOP_DEFAULT,
+ &msg_buf, &xmit_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("signing message", maj_stat, min_stat);
+ break;
+ }
+
+ (void) gss_release_buffer(&min_stat, &msg_buf);
+
+ /* Send the signature block to the client */
+ if (send_token(s2, &xmit_buf) < 0)
+ break;
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+
+ /* Delete context */
+ maj_stat = gss_delete_sec_context(&min_stat, &context, &xmit_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("deleting context", maj_stat, min_stat);
+ break;
+ }
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+
+ /* Close TCP connection */
+ close(s2);
+ }
+
+ /*NOTREACHED*/
+ (void) gss_release_cred(&min_stat, &server_creds);
+ return -1;
+}
+
+/*
+ * Function: server_acquire_creds
+ *
+ * Purpose: imports a service name and acquires credentials for it
+ *
+ * Arguments:
+ *
+ * service_name (r) the ASCII service name
+ * server_creds (w) the GSS-API service credentials
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * The service name is imported with gss_import_name, and service
+ * credentials are acquired with gss_acquire_cred. If either opertion
+ * fails, an error message is displayed and -1 is returned; otherwise,
+ * 0 is returned.
+ */
+int server_acquire_creds(char *service_name, gss_cred_id_t *server_creds)
+{
+ gss_buffer_desc name_buf;
+ gss_name_t server_name;
+ OM_uint32 maj_stat, min_stat;
+
+ name_buf.value = service_name;
+ name_buf.length = strlen(name_buf.value) + 1;
+ maj_stat = gss_import_name(&min_stat, &name_buf, gss_nt_service_name,
+ &server_name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("importing name", maj_stat, min_stat);
+ return -1;
+ }
+
+ maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
+ GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+ server_creds, NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("acquiring credentials", maj_stat, min_stat);
+ return -1;
+ }
+
+ (void) gss_release_name(&min_stat, &server_name);
+
+ return 0;
+}
+
+/*
+ * Function: server_establish_context
+ *
+ * Purpose: establishses a GSS-API context as a specified service with
+ * an incoming client, and returns the context handle and associated
+ * client name
+ *
+ * Arguments:
+ *
+ * s (r) an established TCP connection to the client
+ * service_creds (r) server credentials, from gss_acquire_cred
+ * context (w) the established GSS-API context
+ * client_name (w) the client's ASCII name
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * Any valid client request is accepted. If a context is established,
+ * its handle is returned in context and the client name is returned
+ * in client_name and 0 is returned. If unsuccessful, an error
+ * message is displayed and -1 is returned.
+ */
+int server_establish_context(int s, gss_cred_id_t server_creds,
+ gss_ctx_id_t *context, gss_buffer_t
+ client_name)
+{
+ gss_buffer_desc send_tok, recv_tok;
+ gss_name_t client;
+ gss_OID doid;
+ OM_uint32 maj_stat, min_stat, ret_flags;
+
+ *context = GSS_C_NO_CONTEXT;
+
+ do {
+ if (recv_token(s, &recv_tok) < 0)
+ return -1;
+
+ maj_stat =
+ gss_accept_sec_context(&min_stat,
+ context,
+ server_creds,
+ &recv_tok,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &client,
+ &doid,
+ &send_tok,
+ &ret_flags,
+ NULL, /* ignore time_rec */
+ NULL); /* ignore del_cred_handle */
+
+ (void) gss_release_buffer(&min_stat, &recv_tok);
+
+ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+ display_status("accepting context", maj_stat, min_stat);
+ return -1;
+ }
+
+ if (send_tok.length != 0) {
+ if (send_token(s, &send_tok) < 0) {
+ fprintf(stderr, "failure sending token\n");
+ return -1;
+ }
+
+ (void) gss_release_buffer(&min_stat, &send_tok);
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ maj_stat = gss_display_name(&min_stat, client, client_name, &doid);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("displaying name", maj_stat, min_stat);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+