aboutsummaryrefslogtreecommitdiff
path: root/src/appl
diff options
context:
space:
mode:
authorTom Yu <tlyu@mit.edu>2000-02-11 23:06:47 +0000
committerTom Yu <tlyu@mit.edu>2000-02-11 23:06:47 +0000
commitb5c2b8fa138efadfa52d64be2d16be063cf6c268 (patch)
tree765dc01426edbc9b81ad6dfec0ead62d0d0e766a /src/appl
parenta39cd8baa12d266bf97e35078be96cb623e3fd1b (diff)
downloadkrb5-b5c2b8fa138efadfa52d64be2d16be063cf6c268.zip
krb5-b5c2b8fa138efadfa52d64be2d16be063cf6c268.tar.gz
krb5-b5c2b8fa138efadfa52d64be2d16be063cf6c268.tar.bz2
* README, gss-client.c, gss-misc.c, gss-misc.h, gss-server.c:
Patches from jik to make gss-sample more versatile. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12039 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/appl')
-rw-r--r--src/appl/gss-sample/ChangeLog5
-rw-r--r--src/appl/gss-sample/README162
-rw-r--r--src/appl/gss-sample/gss-client.c526
-rw-r--r--src/appl/gss-sample/gss-misc.c54
-rw-r--r--src/appl/gss-sample/gss-misc.h18
-rw-r--r--src/appl/gss-sample/gss-server.c383
6 files changed, 711 insertions, 437 deletions
diff --git a/src/appl/gss-sample/ChangeLog b/src/appl/gss-sample/ChangeLog
index fb37b22..004bff5 100644
--- a/src/appl/gss-sample/ChangeLog
+++ b/src/appl/gss-sample/ChangeLog
@@ -1,3 +1,8 @@
+2000-02-11 Tom Yu <tlyu@mit.edu>
+
+ * README, gss-client.c, gss-misc.c, gss-misc.h, gss-server.c:
+ Patches from jik to make gss-sample more versatile.
+
2000-01-31 Danilo Almeida <dalmeida@mit.edu>
* gss-client.c, gss-server.c, gss-misc.c: Include Windows headers
diff --git a/src/appl/gss-sample/README b/src/appl/gss-sample/README
index 52b1b21..ac90086 100644
--- a/src/appl/gss-sample/README
+++ b/src/appl/gss-sample/README
@@ -19,76 +19,132 @@
# 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.
-
+application. In addition to serving as an example of GSS-API
+programming, this application is also intended to be a tool for
+testing the performance of GSS-API implementations.
+
+Each time the client is invoked, it performs one or more exchanges
+with the server. Each exchange with the server consists primarily of
+the following steps:
+
+ 1. A TCP/IP connection is established.
+
+ 2. (optional, on by default) The client and server establish a
+ GSS-API context, and the server prints the identify of the
+ client.
+
+ / 3. The client sends a message to the server. The message may
+ / be plaintext, cryptographically "signed" but not encrypted,
+ | or encrypted (default).
+ |
+0 or | 4. The server decrypts the message (if necessary), verifies
+more | its signature (if there is one) and prints it.
+times|
+ | 5. The server sends either a signature block (the default) or an
+ | empty token back to the client to acknowledge the message.
+ \
+ \ 6. If the server sent a signature block, the client verifies
+ it and prints a message indicating that it was verified.
+
+ 7. The client sends an empty block to the server to tell it
+ that the exchange is finished.
+
+ 8. The client and server close the TCP/IP connection and
+ destroy the GSS-API context.
+
The server's command line usage is
-
- gss-server [-port port] [-k keytab] service_name
-
+
+ gss-server [-port port] [-verbose] [-once] [-inetd] [-export]
+ [-logfile file] service_name
+
where service_name is a GSS-API service name of the form
"service@host" (or just "service", in which case the local host name
-is used). The server will accept TCP connections on port (default
-4444) and establish contexts as service_name. If you compile with
-GSS_KRB5 defined and link against the MIT Kerberos libraries, the -k
-option specifies a keytab to use instead of the default one.
-
+is used). The command-line options have the following meanings:
+
+-port The TCP port on which to accept connections. Default is 4444.
+
+-once Tells the server to exit after a single exchange, rather than
+ persisting.
+
+-inetd Tells the server that it is running out of inetd, so it should
+ interact with the client on stdin rather than binding to a
+ network port. Implies "-once".
+
+-export Tells the server to test the gss_export_sec_context function
+ after establishing a context with a client.
+
+-logfile
+ The file to which the server should append its output, rather
+ than sending it to stdout.
+
The client's command line usage is
- gss-client [-port port] [-d] host service_name msg
+ gss-client [-port port] [-mech mechanism] [-d] [-f] [-q]
+ [-ccount count] [-mcount count] [-na] [-nw] [-nx] [-nm]
+ 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 (if you don't
specify the host name in the service name when running gss-server, and
it's running on a different machine from gss-client, make sure to
specify the server's host name in the service name you specify to
-gss-client!) and msg is the message. The client connects to the TCP
-on <host:port> (default 4444) and performs a context
-establishment. The "-d" option specifies delegation - a forwardable
-TGT will be sent to the server, which will put it in its credential
-cache (you must kinit -f for this to work). The -v2 option means that
-the GSSAPI v2 calls should be used (and tested).
+gss-client!) and msg is the message. The command-line options have
+the following meanings:
-If you are using this sample application with OpenVision's Kerberos 5
-GSS-API mechanism:
+-port The TCP port to which to connect. Default is 4444.
-1. Link the client and server with -lgssapi_krb5 -lkrb5 -lcrypto
--lisode -lcom_err.
+-mech The OID of the GSS-API mechanism to use.
-2. Make sure that the principal corresponding to service_name is in
-the default or specified 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".
+-d Tells the client to delegate credentials to the server. For
+ the Kerberos GSS-API mechanism, this means that a forwardable
+ TGT will be sent to the server, which will put it in its
+ credential cache (you must have acquired your tickets with
+ "kinit -f" for this to work).
-This sample application uses the following GSS-API functions:
+-f Tells the client that the "msg" argument is actually the name
+ of a file whose contents should be used as the message.
+
+-q Tells the client to be quiet, i.e., to only print error
+ messages.
+
+-ccount Specifies how many sessions the client should initiate with
+ the server (the "connection count").
+
+-mcount Specifies how many times the message should be sent to the
+ server in each session (the "message count").
+
+-na Tells the client not to do any authentication with the
+ server. Implies "-nw", "-nx" and "-nm".
- 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
+-nw Tells the client not to "wrap" messages. Implies "-nx".
+
+-nx Tells the client not to encrypt messages.
+
+-nm Tells the client not to ask the server to send back a
+ cryptographic checksum ("MIC").
+
+To run the server on a host, you need to 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:
-Barry Jaspan, bjaspan@security.ov.com
+ gss_accept_sec_context gss_inquire_names_for_mech
+ gss_acquire_cred gss_oid_to_str
+ gss_delete_sec_context gss_release_buffer
+ gss_display_name gss_release_cred
+ gss_display_status gss_release_name
+ gss_export_sec_context gss_release_oid
+ gss_get_mic gss_release_oid_set
+ gss_import_name gss_str_to_oid
+ gss_import_sec_context gss_unwrap
+ gss_init_sec_context gss_verify_mic
+ gss_inquire_context gss_wrap
+
+This application was originally written by Barry Jaspan of OpenVision
+Technologies, Inc. It was updated significantly by Jonathan Kamens of
OpenVision Technologies, Inc.
$Id$
diff --git a/src/appl/gss-sample/gss-client.c b/src/appl/gss-sample/gss-client.c
index 5e4ed60..7ad407a 100644
--- a/src/appl/gss-sample/gss-client.c
+++ b/src/appl/gss-sample/gss-client.c
@@ -45,10 +45,13 @@ static char *rcsid = "$Header$";
#include <gssapi/gssapi_generic.h>
#include "gss-misc.h"
+static int verbose = 1;
+
void usage()
{
- fprintf(stderr, "Usage: gss-client [-port port] [-d] host service \
-msg\n");
+ fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
+ fprintf(stderr, " [-f] [-q] [-ccount count] [-mcount count]\n");
+ fprintf(stderr, " [-na] [-nw] [-nx] [-nm] host service msg\n");
exit(1);
}
@@ -109,6 +112,9 @@ int connect_to_server(host, port)
*
* s (r) an established TCP connection to the service
* service_name (r) the ASCII service name of the service
+ * deleg_flag (r) GSS-API delegation flag (if any)
+ * auth_flag (r) whether to actually do authentication
+ * oid (r) OID of the mechanism to use
* context (w) the established GSS-API context
* ret_flags (w) the returned flags from init_sec_context
*
@@ -126,104 +132,121 @@ int connect_to_server(host, port)
* unsuccessful, the GSS-API error messages are displayed on stderr
* and -1 is returned.
*/
-int client_establish_context(s, service_name, deleg_flag, oid,
+int client_establish_context(s, service_name, deleg_flag, auth_flag, oid,
gss_context, ret_flags)
int s;
char *service_name;
gss_OID oid;
OM_uint32 deleg_flag;
+ int auth_flag;
gss_ctx_id_t *gss_context;
OM_uint32 *ret_flags;
{
- gss_buffer_desc send_tok, recv_tok, *token_ptr;
- gss_name_t target_name;
- OM_uint32 maj_stat, min_stat, init_sec_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_OID) gss_nt_service_name, &target_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("parsing name", maj_stat, min_stat);
- return -1;
- }
+ if (auth_flag) {
+ gss_buffer_desc send_tok, recv_tok, *token_ptr;
+ gss_name_t target_name;
+ OM_uint32 maj_stat, min_stat, init_sec_min_stat;
+ int token_flags;
+
+ /*
+ * 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_OID) 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.
- */
+ if (send_token(s, TOKEN_NOOP|TOKEN_CONTEXT_NEXT, empty_token) < 0) {
+ (void) gss_release_name(&min_stat, &target_name);
+ 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(&init_sec_min_stat,
- GSS_C_NO_CREDENTIAL,
- gss_context,
- target_name,
- oid,
- GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
- deleg_flag,
- 0,
- NULL, /* no channel bindings */
- token_ptr,
- NULL, /* ignore mech type */
- &send_tok,
- ret_flags,
- NULL); /* ignore time_rec */
-
- if (token_ptr != GSS_C_NO_BUFFER)
- (void) gss_release_buffer(&min_stat, &recv_tok);
-
- if (send_tok.length != 0) {
- printf("Sending init_sec_context token (size=%d)...",
- send_tok.length);
- 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_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
- display_status("initializing context", maj_stat,
- init_sec_min_stat);
- (void) gss_release_name(&min_stat, &target_name);
- if (*gss_context == GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&min_stat, gss_context,
- GSS_C_NO_BUFFER);
- return -1;
- }
+ token_ptr = GSS_C_NO_BUFFER;
+ *gss_context = GSS_C_NO_CONTEXT;
+
+ do {
+ maj_stat =
+ gss_init_sec_context(&init_sec_min_stat,
+ GSS_C_NO_CREDENTIAL,
+ gss_context,
+ target_name,
+ oid,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+ deleg_flag,
+ 0,
+ NULL, /* no channel bindings */
+ token_ptr,
+ NULL, /* ignore mech type */
+ &send_tok,
+ ret_flags,
+ NULL); /* ignore time_rec */
+
+ if (token_ptr != GSS_C_NO_BUFFER)
+ (void) gss_release_buffer(&min_stat, &recv_tok);
+
+ if (send_tok.length != 0) {
+ if (verbose)
+ printf("Sending init_sec_context token (size=%d)...",
+ send_tok.length);
+ if (send_token(s, TOKEN_CONTEXT, &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_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+ display_status("initializing context", maj_stat,
+ init_sec_min_stat);
+ (void) gss_release_name(&min_stat, &target_name);
+ if (*gss_context == GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat, gss_context,
+ GSS_C_NO_BUFFER);
+ return -1;
+ }
- if (maj_stat == GSS_S_CONTINUE_NEEDED) {
- printf("continue needed...");
- if (recv_token(s, &recv_tok) < 0) {
- (void) gss_release_name(&min_stat, &target_name);
- return -1;
- }
- token_ptr = &recv_tok;
- }
- printf("\n");
- } while (maj_stat == GSS_S_CONTINUE_NEEDED);
-
- (void) gss_release_name(&min_stat, &target_name);
+ if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+ if (verbose)
+ printf("continue needed...");
+ if (recv_token(s, &token_flags, &recv_tok) < 0) {
+ (void) gss_release_name(&min_stat, &target_name);
+ return -1;
+ }
+ token_ptr = &recv_tok;
+ }
+ if (verbose)
+ printf("\n");
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ (void) gss_release_name(&min_stat, &target_name);
+ }
+ else {
+ if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -278,8 +301,15 @@ void read_file(file_name, in_buf)
*
* 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
+ * service_name (r) the GSS-API service name to authenticate to
+ * deleg_flag (r) GSS-API delegation flag (if any)
+ * auth_flag (r) whether to do authentication
+ * wrap_flag (r) whether to do message wrapping at all
+ * encrypt_flag (r) whether to do encryption while wrapping
+ * mic_flag (r) whether to request a MIC from the server
* msg (r) the message to have "signed"
+ * use_file (r) whether to treat msg as an input file name
+ * mcount (r) the number of times to send the message
*
* Returns: 0 on success, -1 on failure
*
@@ -287,18 +317,22 @@ void read_file(file_name, in_buf)
*
* 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,
+ * seals msg in a GSS-API token with gss_wrap, 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(host, port, oid, service_name, deleg_flag, msg, use_file)
+int call_server(host, port, oid, service_name, deleg_flag, auth_flag,
+ wrap_flag, encrypt_flag, mic_flag, msg, use_file,
+ mcount)
char *host;
u_short port;
gss_OID oid;
char *service_name;
OM_uint32 deleg_flag;
+ int auth_flag, wrap_flag, encrypt_flag, mic_flag;
char *msg;
int use_file;
+ int mcount;
{
gss_ctx_id_t context;
gss_buffer_desc in_buf, out_buf;
@@ -316,103 +350,108 @@ int call_server(host, port, oid, service_name, deleg_flag, msg, use_file)
gss_OID_set mech_names;
gss_buffer_desc oid_name;
size_t i;
+ int token_flags;
/* Open connection */
if ((s = connect_to_server(host, port)) < 0)
return -1;
/* Establish context */
- if (client_establish_context(s, service_name, deleg_flag, oid, &context,
- &ret_flags) < 0) {
+ if (client_establish_context(s, service_name, deleg_flag, auth_flag,
+ oid, &context, &ret_flags) < 0) {
(void) close(s);
return -1;
}
- /* display the flags */
- display_ctx_flags(ret_flags);
-
- /* Get context information */
- maj_stat = gss_inquire_context(&min_stat, context,
- &src_name, &targ_name, &lifetime,
- &mechanism, &context_flags,
- &is_local,
- &is_open);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("inquiring context", maj_stat, min_stat);
- return -1;
- }
+ if (auth_flag) {
+ if (verbose) {
+ /* display the flags */
+ display_ctx_flags(ret_flags);
+
+ /* Get context information */
+ maj_stat = gss_inquire_context(&min_stat, context,
+ &src_name, &targ_name, &lifetime,
+ &mechanism, &context_flags,
+ &is_local,
+ &is_open);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("inquiring context", maj_stat, min_stat);
+ return -1;
+ }
- maj_stat = gss_display_name(&min_stat, src_name, &sname,
- &name_type);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("displaying source name", maj_stat, min_stat);
- return -1;
- }
- maj_stat = gss_display_name(&min_stat, targ_name, &tname,
- (gss_OID *) NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("displaying target name", maj_stat, min_stat);
- return -1;
- }
- fprintf(stderr, "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
- (int) sname.length, (char *) sname.value,
- (int) tname.length, (char *) tname.value, lifetime,
- context_flags,
- (is_local) ? "locally initiated" : "remotely initiated",
- (is_open) ? "open" : "closed");
-
- (void) gss_release_name(&min_stat, &src_name);
- (void) gss_release_name(&min_stat, &targ_name);
- (void) gss_release_buffer(&min_stat, &sname);
- (void) gss_release_buffer(&min_stat, &tname);
-
- maj_stat = gss_oid_to_str(&min_stat,
- name_type,
- &oid_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
- }
- fprintf(stderr, "Name type of source name is %.*s.\n",
- (int) oid_name.length, (char *) oid_name.value);
- (void) gss_release_buffer(&min_stat, &oid_name);
-
- /* Now get the names supported by the mechanism */
- maj_stat = gss_inquire_names_for_mech(&min_stat,
- mechanism,
- &mech_names);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("inquiring mech names", maj_stat, min_stat);
- return -1;
- }
+ maj_stat = gss_display_name(&min_stat, src_name, &sname,
+ &name_type);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("displaying source name", maj_stat, min_stat);
+ return -1;
+ }
+ maj_stat = gss_display_name(&min_stat, targ_name, &tname,
+ (gss_OID *) NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("displaying target name", maj_stat, min_stat);
+ return -1;
+ }
+ printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
+ (int) sname.length, (char *) sname.value,
+ (int) tname.length, (char *) tname.value, lifetime,
+ context_flags,
+ (is_local) ? "locally initiated" : "remotely initiated",
+ (is_open) ? "open" : "closed");
+
+ (void) gss_release_name(&min_stat, &src_name);
+ (void) gss_release_name(&min_stat, &targ_name);
+ (void) gss_release_buffer(&min_stat, &sname);
+ (void) gss_release_buffer(&min_stat, &tname);
- maj_stat = gss_oid_to_str(&min_stat,
- mechanism,
- &oid_name);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
- }
- fprintf(stderr, "Mechanism %.*s supports %d names\n",
- (int) oid_name.length, (char *) oid_name.value,
- mech_names->count);
- (void) gss_release_buffer(&min_stat, &oid_name);
+ maj_stat = gss_oid_to_str(&min_stat,
+ name_type,
+ &oid_name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("converting oid->string", maj_stat, min_stat);
+ return -1;
+ }
+ printf("Name type of source name is %.*s.\n",
+ (int) oid_name.length, (char *) oid_name.value);
+ (void) gss_release_buffer(&min_stat, &oid_name);
+
+ /* Now get the names supported by the mechanism */
+ maj_stat = gss_inquire_names_for_mech(&min_stat,
+ mechanism,
+ &mech_names);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("inquiring mech names", maj_stat, min_stat);
+ return -1;
+ }
- for (i=0; i<mech_names->count; i++) {
maj_stat = gss_oid_to_str(&min_stat,
- &mech_names->elements[i],
+ mechanism,
&oid_name);
if (maj_stat != GSS_S_COMPLETE) {
+ display_status("converting oid->string", maj_stat, min_stat);
+ return -1;
+ }
+ printf("Mechanism %.*s supports %d names\n",
+ (int) oid_name.length, (char *) oid_name.value,
+ mech_names->count);
+ (void) gss_release_buffer(&min_stat, &oid_name);
+
+ for (i=0; i<mech_names->count; i++) {
+ maj_stat = gss_oid_to_str(&min_stat,
+ &mech_names->elements[i],
+ &oid_name);
+ if (maj_stat != GSS_S_COMPLETE) {
display_status("converting oid->string", maj_stat, min_stat);
return -1;
- }
- fprintf(stderr, " %d: %.*s\n", i,
- (int) oid_name.length, (char *) oid_name.value);
+ }
+ printf(" %d: %.*s\n", i,
+ (int) oid_name.length, (char *) oid_name.value);
- (void) gss_release_buffer(&min_stat, &oid_name);
+ (void) gss_release_buffer(&min_stat, &oid_name);
+ }
+ (void) gss_release_oid_set(&min_stat, &mech_names);
+ }
}
- (void) gss_release_oid_set(&min_stat, &mech_names);
-
+
if (use_file) {
read_file(msg, &in_buf);
} else {
@@ -421,58 +460,83 @@ int call_server(host, port, oid, service_name, deleg_flag, msg, use_file)
in_buf.length = strlen(msg);
}
- maj_stat = gss_wrap(&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);
- (void) close(s);
- (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- } else if (! state) {
- fprintf(stderr, "Warning! Message not encrypted.\n");
- }
+ for (i = 0; i < mcount; i++) {
+ if (wrap_flag) {
+ maj_stat = gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT,
+ &in_buf, &state, &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("wrapping message", maj_stat, min_stat);
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ } else if (encrypt_flag && ! state) {
+ fprintf(stderr, "Warning! Message not encrypted.\n");
+ }
+ }
+ else {
+ out_buf = in_buf;
+ }
+
+ /* Send to server */
+ if (send_token(s, (TOKEN_DATA |
+ (wrap_flag ? TOKEN_WRAPPED : 0) |
+ (encrypt_flag ? TOKEN_ENCRYPTED : 0) |
+ (mic_flag ? TOKEN_SEND_MIC : 0)), &out_buf) < 0) {
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ }
+ if (out_buf.value != in_buf.value)
+ (void) gss_release_buffer(&min_stat, &out_buf);
+
+ /* Read signature block into out_buf */
+ if (recv_token(s, &token_flags, &out_buf) < 0) {
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ }
- /* Send to server */
- if (send_token(s, &out_buf) < 0) {
- (void) close(s);
- (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- }
- (void) gss_release_buffer(&min_stat, &out_buf);
+ if (mic_flag) {
+ /* Verify signature block */
+ maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
+ &out_buf, &qop_state);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("verifying signature", maj_stat, min_stat);
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ }
- /* Read signature block into out_buf */
- if (recv_token(s, &out_buf) < 0) {
- (void) close(s);
- (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
- }
+ if (verbose)
+ printf("Signature verified.\n");
+ }
+ else {
+ if (verbose)
+ printf("Response received.\n");
+ }
- /* Verify signature block */
- maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
- &out_buf, &qop_state);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("verifying signature", maj_stat, min_stat);
- (void) close(s);
- (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
+ (void) gss_release_buffer(&min_stat, &out_buf);
}
- (void) gss_release_buffer(&min_stat, &out_buf);
if (use_file)
- free(in_buf.value);
-
- printf("Signature verified.\n");
+ free(in_buf.value);
+
+ /* Send NOOP */
+ (void) send_token(s, TOKEN_NOOP, empty_token);
+
+ if (auth_flag) {
+ /* 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);
+ (void) close(s);
+ (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+ return -1;
+ }
- /* 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);
- (void) close(s);
- (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
- return -1;
+ (void) gss_release_buffer(&min_stat, &out_buf);
}
- (void) gss_release_buffer(&min_stat, &out_buf);
(void) close(s);
return 0;
}
@@ -486,7 +550,7 @@ static void parse_oid(char *mechanism, gss_OID *oid)
if (isdigit(mechanism[0])) {
mechstr = malloc(strlen(mechanism)+5);
if (!mechstr) {
- printf("Couldn't allocate mechanism scratch!\n");
+ fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
return;
}
sprintf(mechstr, "{ %s }", mechanism);
@@ -516,8 +580,12 @@ int main(argc, argv)
int use_file = 0;
OM_uint32 deleg_flag = 0, min_stat;
gss_OID oid = GSS_C_NULL_OID;
-
+ int mcount = 1, ccount = 1;
+ int i;
+ int auth_flag, wrap_flag, encrypt_flag, mic_flag;
+
display_file = stdout;
+ auth_flag = wrap_flag = encrypt_flag = mic_flag = 1;
/* Parse arguments. */
argc--; argv++;
@@ -534,6 +602,26 @@ int main(argc, argv)
deleg_flag = GSS_C_DELEG_FLAG;
} else if (strcmp(*argv, "-f") == 0) {
use_file = 1;
+ } else if (strcmp(*argv, "-q") == 0) {
+ verbose = 0;
+ } else if (strcmp(*argv, "-ccount") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ ccount = atoi(*argv);
+ if (ccount <= 0) usage();
+ } else if (strcmp(*argv, "-mcount") == 0) {
+ argc--; argv++;
+ if (!argc) usage();
+ mcount = atoi(*argv);
+ if (mcount < 0) usage();
+ } else if (strcmp(*argv, "-na") == 0) {
+ auth_flag = wrap_flag = encrypt_flag = mic_flag = 0;
+ } else if (strcmp(*argv, "-nw") == 0) {
+ wrap_flag = 0;
+ } else if (strcmp(*argv, "-nx") == 0) {
+ encrypt_flag = 0;
+ } else if (strcmp(*argv, "-nm") == 0) {
+ mic_flag = 0;
} else
break;
argc--; argv++;
@@ -548,13 +636,15 @@ int main(argc, argv)
if (mechanism)
parse_oid(mechanism, &oid);
- if (call_server(server_host, port, oid, service_name,
- deleg_flag, msg, use_file) < 0)
- exit(1);
+ for (i = 0; i < ccount; i++) {
+ if (call_server(server_host, port, oid, service_name,
+ deleg_flag, auth_flag, wrap_flag, encrypt_flag, mic_flag,
+ msg, use_file, mcount) < 0)
+ exit(1);
+ }
if (oid != GSS_C_NULL_OID)
(void) gss_release_oid(&min_stat, &oid);
return 0;
}
-
diff --git a/src/appl/gss-sample/gss-misc.c b/src/appl/gss-sample/gss-misc.c
index fedd376..d2b6cab 100644
--- a/src/appl/gss-sample/gss-misc.c
+++ b/src/appl/gss-sample/gss-misc.c
@@ -49,6 +49,9 @@ extern char *malloc();
FILE *display_file;
+gss_buffer_desc empty_token_buf = { 0, (void *) "" };
+gss_buffer_t empty_token = &empty_token_buf;
+
static void display_status_1
PROTOTYPE( (char *m, OM_uint32 code, int type) );
@@ -98,21 +101,32 @@ static int read_all(int fildes, char *buf, unsigned int nbyte)
* Arguments:
*
* s (r) an open file descriptor
+ * flags (r) the flags to write
* 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.
+ * send_token writes the token flags (a single byte, even though
+ * they're passed in in an integer), then 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(s, tok)
+int send_token(s, flags, tok)
int s;
+ int flags;
gss_buffer_t tok;
{
int len, ret;
+ unsigned char char_flags = (unsigned char) flags;
+
+ ret = write_all(s, (char *)&char_flags, 1);
+ if (ret != 1) {
+ perror("sending token flags");
+ return -1;
+ }
len = htonl(tok->length);
@@ -151,24 +165,40 @@ int send_token(s, tok)
* Arguments:
*
* s (r) an open file descriptor
+ * flags (w) the read flags
* 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.
+ * recv_token reads the token flags (a single byte, even though
+ * they're stored into an integer, then 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(s, tok)
+int recv_token(s, flags, tok)
int s;
+ int *flags;
gss_buffer_t tok;
{
int ret;
+ unsigned char char_flags;
+
+ ret = read_all(s, (char *) &char_flags, 1);
+ if (ret < 0) {
+ perror("reading token flags");
+ return -1;
+ } else if (! ret) {
+ if (display_file)
+ fputs("reading token flags: 0 bytes read\n", display_file);
+ return -1;
+ } else {
+ *flags = (int) char_flags;
+ }
ret = read_all(s, (char *) &tok->length, 4);
if (ret < 0) {
@@ -184,7 +214,7 @@ int recv_token(s, tok)
tok->length = ntohl(tok->length);
tok->value = (char *) malloc(tok->length);
- if (tok->value == NULL) {
+ if (tok->length && tok->value == NULL) {
if (display_file)
fprintf(display_file,
"Out of memory allocating token data\n");
diff --git a/src/appl/gss-sample/gss-misc.h b/src/appl/gss-sample/gss-misc.h
index bfdcad2..82c55bd 100644
--- a/src/appl/gss-sample/gss-misc.h
+++ b/src/appl/gss-sample/gss-misc.h
@@ -33,9 +33,9 @@
extern FILE *display_file;
int send_token
- PROTOTYPE( (int s, gss_buffer_t tok) );
+ PROTOTYPE( (int s, int flags, gss_buffer_t tok) );
int recv_token
- PROTOTYPE( (int s, gss_buffer_t tok) );
+ PROTOTYPE( (int s, int *flags, gss_buffer_t tok) );
void display_status
PROTOTYPE( (char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) );
void display_ctx_flags
@@ -43,4 +43,18 @@ void display_ctx_flags
void print_token
PROTOTYPE( (gss_buffer_t tok) );
+/* Token types */
+#define TOKEN_NOOP (1<<0)
+#define TOKEN_CONTEXT (1<<1)
+#define TOKEN_DATA (1<<2)
+#define TOKEN_MIC (1<<3)
+
+/* Token flags */
+#define TOKEN_CONTEXT_NEXT (1<<4)
+#define TOKEN_WRAPPED (1<<5)
+#define TOKEN_ENCRYPTED (1<<6)
+#define TOKEN_SEND_MIC (1<<7)
+
+extern gss_buffer_t empty_token;
+
#endif
diff --git a/src/appl/gss-sample/gss-server.c b/src/appl/gss-sample/gss-server.c
index 6a163db..8d2ca27 100644
--- a/src/appl/gss-sample/gss-server.c
+++ b/src/appl/gss-sample/gss-server.c
@@ -51,8 +51,8 @@ static char *rcsid = "$Header$";
void usage()
{
- fprintf(stderr, "Usage: gss-server [-port port] [-verbose]\n");
- fprintf(stderr, " [-inetd] [-logfile file] service_name\n");
+ fprintf(stderr, "Usage: gss-server [-port port] [-verbose] [-once]\n");
+ fprintf(stderr, " [-inetd] [-export] [-logfile file] [service_name]\n");
exit(1);
}
@@ -144,89 +144,111 @@ int server_establish_context(s, server_creds, context, client_name, ret_flags)
gss_OID doid;
OM_uint32 maj_stat, min_stat, acc_sec_min_stat;
gss_buffer_desc oid_name;
+ int token_flags;
+
+ if (recv_token(s, &token_flags, &recv_tok) < 0)
+ return -1;
+
+ (void) gss_release_buffer(&min_stat, &recv_tok);
+ if (! (token_flags & TOKEN_NOOP)) {
+ if (log)
+ fprintf(log, "Expected NOOP token, got %d token instead\n",
+ token_flags);
+ return -1;
+ }
*context = GSS_C_NO_CONTEXT;
-
- do {
- if (recv_token(s, &recv_tok) < 0)
- return -1;
-
- if (verbose && log) {
- fprintf(log, "Received token (size=%d): \n", recv_tok.length);
- print_token(&recv_tok);
- }
-
- maj_stat =
- gss_accept_sec_context(&acc_sec_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 (send_tok.length != 0) {
- if (verbose && log) {
- fprintf(log,
- "Sending accept_sec_context token (size=%d):\n",
- send_tok.length);
- print_token(&send_tok);
- }
- if (send_token(s, &send_tok) < 0) {
- fprintf(log, "failure sending token\n");
- return -1;
- }
-
- (void) gss_release_buffer(&min_stat, &send_tok);
- }
- if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
- display_status("accepting context", maj_stat,
- acc_sec_min_stat);
- if (*context == GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&min_stat, context,
- GSS_C_NO_BUFFER);
- return -1;
- }
-
- if (verbose && log) {
- if (maj_stat == GSS_S_CONTINUE_NEEDED)
- fprintf(log, "continue needed...\n");
- else
- fprintf(log, "\n");
- fflush(log);
- }
- } while (maj_stat == GSS_S_CONTINUE_NEEDED);
-
- /* display the flags */
- display_ctx_flags(*ret_flags);
-
- if (verbose && log) {
+
+ if (token_flags & TOKEN_CONTEXT_NEXT) {
+ do {
+ if (recv_token(s, &token_flags, &recv_tok) < 0)
+ return -1;
+
+ if (verbose && log) {
+ fprintf(log, "Received token (size=%d): \n", recv_tok.length);
+ print_token(&recv_tok);
+ }
+
+ maj_stat =
+ gss_accept_sec_context(&acc_sec_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 (send_tok.length != 0) {
+ if (verbose && log) {
+ fprintf(log,
+ "Sending accept_sec_context token (size=%d):\n",
+ send_tok.length);
+ print_token(&send_tok);
+ }
+ if (send_token(s, TOKEN_CONTEXT, &send_tok) < 0) {
+ if (log)
+ fprintf(log, "failure sending token\n");
+ return -1;
+ }
+
+ (void) gss_release_buffer(&min_stat, &send_tok);
+ }
+ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+ display_status("accepting context", maj_stat,
+ acc_sec_min_stat);
+ if (*context == GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat, context,
+ GSS_C_NO_BUFFER);
+ return -1;
+ }
+
+ if (verbose && log) {
+ if (maj_stat == GSS_S_CONTINUE_NEEDED)
+ fprintf(log, "continue needed...\n");
+ else
+ fprintf(log, "\n");
+ fflush(log);
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+ /* display the flags */
+ display_ctx_flags(*ret_flags);
+
+ if (verbose && log) {
maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);
if (maj_stat != GSS_S_COMPLETE) {
- display_status("converting oid->string", maj_stat, min_stat);
- return -1;
+ display_status("converting oid->string", maj_stat, min_stat);
+ return -1;
}
fprintf(log, "Accepted connection using mechanism OID %.*s.\n",
(int) oid_name.length, (char *) oid_name.value);
(void) gss_release_buffer(&min_stat, &oid_name);
- }
+ }
- 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;
+ 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;
+ }
+ maj_stat = gss_release_name(&min_stat, &client);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("releasing name", maj_stat, min_stat);
+ return -1;
+ }
}
- maj_stat = gss_release_name(&min_stat, &client);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("releasing name", maj_stat, min_stat);
- return -1;
+ else {
+ client_name->length = *ret_flags = 0;
+
+ if (log)
+ fprintf(log, "Accepted unauthenticated connection.\n");
}
+
return 0;
}
@@ -311,8 +333,9 @@ int test_import_export_context(context)
copied_token.length = context_token.length;
copied_token.value = malloc(context_token.length);
if (copied_token.value == 0) {
+ if (log)
fprintf(log, "Couldn't allocate memory to copy context token.\n");
- return 1;
+ return 1;
}
memcpy(copied_token.value, context_token.value, copied_token.length);
maj_stat = gss_import_sec_context(&min_stat, &copied_token, context);
@@ -340,6 +363,7 @@ int test_import_export_context(context)
* accept()ed
* service_name (r) the ASCII name of the GSS-API service to
* establish a context as
+ * export (r) whether to test context exporting
*
* Returns: -1 on error
*
@@ -354,83 +378,128 @@ int test_import_export_context(context)
*
* If any error occurs, -1 is returned.
*/
-int sign_server(s, server_creds)
+int sign_server(s, server_creds, export)
int s;
gss_cred_id_t server_creds;
+ int export;
{
gss_buffer_desc client_name, xmit_buf, msg_buf;
gss_ctx_id_t context;
OM_uint32 maj_stat, min_stat;
int i, conf_state, ret_flags;
char *cp;
-
+ int token_flags;
+
/* Establish a context with the client */
if (server_establish_context(s, server_creds, &context,
&client_name, &ret_flags) < 0)
return(-1);
-
- printf("Accepted connection: \"%.*s\"\n",
- (int) client_name.length, (char *) client_name.value);
- (void) gss_release_buffer(&min_stat, &client_name);
- for (i=0; i < 3; i++)
- if (test_import_export_context(&context))
- return -1;
-
- /* Receive the sealed message token */
- if (recv_token(s, &xmit_buf) < 0)
- return(-1);
-
- if (verbose && log) {
- fprintf(log, "Sealed message token:\n");
- print_token(&xmit_buf);
+ if (context == GSS_C_NO_CONTEXT) {
+ printf("Accepted unauthenticated connection.\n");
}
-
- maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,
- &conf_state, (gss_qop_t *) NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("unsealing message", maj_stat, min_stat);
- return(-1);
- } else if (! conf_state) {
- fprintf(stderr, "Warning! Message not encrypted.\n");
- }
-
- (void) gss_release_buffer(&min_stat, &xmit_buf);
-
- fprintf(log, "Received message: ");
- cp = msg_buf.value;
- if ((isprint(cp[0]) || isspace(cp[0])) &&
- (isprint(cp[1]) || isspace(cp[1]))) {
- fprintf(log, "\"%.*s\"\n", msg_buf.length, msg_buf.value);
- } else {
- printf("\n");
- print_token(&msg_buf);
- }
-
- /* Produce a signature block for the message */
- maj_stat = gss_get_mic(&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);
- return(-1);
+ else {
+ printf("Accepted connection: \"%.*s\"\n",
+ (int) client_name.length, (char *) client_name.value);
+ (void) gss_release_buffer(&min_stat, &client_name);
+
+ if (export) {
+ for (i=0; i < 3; i++)
+ if (test_import_export_context(&context))
+ return -1;
+ }
}
- (void) gss_release_buffer(&min_stat, &msg_buf);
+ do {
+ /* Receive the message token */
+ if (recv_token(s, &token_flags, &xmit_buf) < 0)
+ return(-1);
+
+ if (token_flags & TOKEN_NOOP) {
+ if (log)
+ fprintf(log, "NOOP token\n");
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+ break;
+ }
+
+ if (verbose && log) {
+ fprintf(log, "Message token (flags=%d):\n", token_flags);
+ print_token(&xmit_buf);
+ }
+
+ if ((context == GSS_C_NO_CONTEXT) &&
+ (token_flags & (TOKEN_WRAPPED|TOKEN_ENCRYPTED|TOKEN_SEND_MIC))) {
+ if (log)
+ fprintf(log,
+ "Unauthenticated client requested authenticated services!\n");
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+ return(-1);
+ }
+
+ if (token_flags & TOKEN_WRAPPED) {
+ maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,
+ &conf_state, (gss_qop_t *) NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("unsealing message", maj_stat, min_stat);
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+ return(-1);
+ } else if (! conf_state && (token_flags & TOKEN_ENCRYPTED)) {
+ fprintf(stderr, "Warning! Message not encrypted.\n");
+ }
- /* Send the signature block to the client */
- if (send_token(s, &xmit_buf) < 0)
- return(-1);
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+ }
+ else {
+ msg_buf = xmit_buf;
+ }
+
+ if (log) {
+ fprintf(log, "Received message: ");
+ cp = msg_buf.value;
+ if ((isprint(cp[0]) || isspace(cp[0])) &&
+ (isprint(cp[1]) || isspace(cp[1]))) {
+ fprintf(log, "\"%.*s\"\n", msg_buf.length, msg_buf.value);
+ } else {
+ fprintf(log, "\n");
+ print_token(&msg_buf);
+ }
+ }
- (void) gss_release_buffer(&min_stat, &xmit_buf);
+ if (token_flags & TOKEN_SEND_MIC) {
+ /* Produce a signature block for the message */
+ maj_stat = gss_get_mic(&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);
+ return(-1);
+ }
- /* Delete context */
- maj_stat = gss_delete_sec_context(&min_stat, &context, NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- display_status("deleting context", maj_stat, min_stat);
- return(-1);
+ (void) gss_release_buffer(&min_stat, &msg_buf);
+
+ /* Send the signature block to the client */
+ if (send_token(s, TOKEN_MIC, &xmit_buf) < 0)
+ return(-1);
+
+ (void) gss_release_buffer(&min_stat, &xmit_buf);
+ }
+ else {
+ (void) gss_release_buffer(&min_stat, &msg_buf);
+ if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+ return(-1);
+ }
+ } while (1 /* loop will break if NOOP received */);
+
+ if (context != GSS_C_NO_CONTEXT) {
+ /* Delete context */
+ maj_stat = gss_delete_sec_context(&min_stat, &context, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ display_status("deleting context", maj_stat, min_stat);
+ return(-1);
+ }
}
- fflush(log);
+ if (log)
+ fflush(log);
return(0);
}
@@ -447,6 +516,7 @@ main(argc, argv)
int s;
int once = 0;
int do_inetd = 0;
+ int export = 0;
log = stdout;
display_file = stdout;
@@ -462,14 +532,25 @@ main(argc, argv)
once = 1;
} else if (strcmp(*argv, "-inetd") == 0) {
do_inetd = 1;
+ } else if (strcmp(*argv, "-export") == 0) {
+ export = 1;
} else if (strcmp(*argv, "-logfile") == 0) {
argc--; argv++;
if (!argc) usage();
- log = fopen(*argv, "a");
- display_file = log;
- if (!log) {
+ /* Gross hack, but it makes it unnecessary to add an
+ extra argument to disable logging, and makes the code
+ more efficient because it doesn't actually write data
+ to /dev/null. */
+ if (! strcmp(*argv, "/dev/null")) {
+ log = display_file = NULL;
+ }
+ else {
+ log = fopen(*argv, "a");
+ display_file = log;
+ if (!log) {
perror(*argv);
exit(1);
+ }
}
} else
break;
@@ -490,31 +571,29 @@ main(argc, argv)
close(1);
close(2);
- sign_server(0, server_creds);
+ sign_server(0, server_creds, export);
close(0);
} else {
int stmp;
- if ((stmp = create_socket(port)) >= 0) {
- do {
- /* Accept a TCP connection */
- if ((s = accept(stmp, NULL, 0)) < 0) {
- perror("accepting connection");
- continue;
- }
- /* this return value is not checked, because there's
- not really anything to do if it fails */
- sign_server(s, server_creds);
- close(s);
- } while (!once);
-
- close(stmp);
- }
+ if ((stmp = create_socket(port)) >= 0) {
+ do {
+ /* Accept a TCP connection */
+ if ((s = accept(stmp, NULL, 0)) < 0) {
+ perror("accepting connection");
+ continue;
+ }
+ /* this return value is not checked, because there's
+ not really anything to do if it fails */
+ sign_server(s, server_creds);
+ close(s);
+ } while (!once);
+
+ close(stmp);
+ }
}
(void) gss_release_cred(&min_stat, &server_creds);
- /*NOTREACHED*/
- (void) close(s);
return 0;
}