From: Theodore Tso Date: Wed, 15 Jun 1994 04:52:28 +0000 (+0000) Subject: As submitted from Openvision --- a sample GSSAPI client/server application! X-Git-Tag: krb5-1.0-beta4~60 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=22e28d95f57ad5a12d4aa13d4750d7f4ea18a00e;p=krb5.git As submitted from Openvision --- a sample GSSAPI client/server application! git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3794 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/appl/gss-sample/Imakefile b/src/appl/gss-sample/Imakefile new file mode 100644 index 000000000..ae71ec128 --- /dev/null +++ b/src/appl/gss-sample/Imakefile @@ -0,0 +1,39 @@ +# $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() diff --git a/src/appl/gss-sample/Makefile.in b/src/appl/gss-sample/Makefile.in new file mode 100644 index 000000000..732dc7c96 --- /dev/null +++ b/src/appl/gss-sample/Makefile.in @@ -0,0 +1,43 @@ +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) diff --git a/src/appl/gss-sample/README b/src/appl/gss-sample/README new file mode 100644 index 000000000..5afa0ed4a --- /dev/null +++ b/src/appl/gss-sample/README @@ -0,0 +1,83 @@ +# 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 (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$ diff --git a/src/appl/gss-sample/configure.in b/src/appl/gss-sample/configure.in new file mode 100644 index 000000000..959036a7d --- /dev/null +++ b/src/appl/gss-sample/configure.in @@ -0,0 +1,7 @@ +AC_INIT(klist.c) +AC_HAVE_LIBRARY(socket) +AC_HAVE_LIBRARY(nsl) +CONFIG_RULES +KRB_INCLUDE +ISODE_INCLUDE +AC_OUTPUT(Makefile,[EXTRA_RULES]) diff --git a/src/appl/gss-sample/gss-client.c b/src/appl/gss-sample/gss-client.c new file mode 100644 index 000000000..264f451cc --- /dev/null +++ b/src/appl/gss-sample/gss-client.c @@ -0,0 +1,313 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +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 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; +} diff --git a/src/appl/gss-sample/gss-misc.c b/src/appl/gss-sample/gss-misc.c new file mode 100644 index 000000000..24705ab87 --- /dev/null +++ b/src/appl/gss-sample/gss-misc.c @@ -0,0 +1,181 @@ +/* + * 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 +#include +#include + +#include +#include + +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 : " 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; + } +} diff --git a/src/appl/gss-sample/gss-server.c b/src/appl/gss-sample/gss-server.c new file mode 100644 index 000000000..523b2bd50 --- /dev/null +++ b/src/appl/gss-sample/gss-server.c @@ -0,0 +1,346 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +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; +} + + +