[3151] in Kerberos-V5-bugs

home help back first fref pref prev next nref lref last post

krb5-appl/788: New and improved samples GSSAPI client and server

daemon@ATHENA.MIT.EDU (Jonathan Kamens)
Tue Nov 23 16:56:16 1999

Resent-From: gnats@rt-11.MIT.EDU (GNATS Management)
Resent-To: krb5-unassigned@RT-11.MIT.EDU
Resent-Reply-To: krb5-bugs@MIT.EDU, jik@kamens.brookline.ma.us
Message-Id: <199911232154.QAA21101@jik2.kamens.brookline.ma.us>
Date: Tue, 23 Nov 1999 16:54:28 -0500
From: Jonathan Kamens <jik@kamens.brookline.ma.us>
Reply-To: jik@kamens.brookline.ma.us
To: krb5-bugs@MIT.EDU
Cc: jik@kamens.brookline.ma.us


>Number:         788
>Category:       krb5-appl
>Synopsis:       New and improved samples GSSAPI client and server
>Confidential:   yes
>Severity:       non-critical
>Priority:       low
>Responsible:    krb5-unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   unknown
>Arrival-Date:   Tue Nov 23 16:56:00 EST 1999
>Last-Modified:
>Originator:     Jonathan Kamens
>Organization:
	
>Release:        krb5-1.1
>Environment:
	
System: Linux jik2 2.2.12-20 #14 Thu Nov 18 20:57:02 EST 1999 i686 unknown
Architecture: i686

>Description:
	I previously submitted these changes against krb5 1.0.  Here
	they are again, merged into krb5 1.1.  I realize that these
	changes make the GSS sample application more complex, but they
	also make it much more functional and much more useful for
	testing GSS-API functionality.  I'd really like to see these
	changes folded into the tree.
>How-To-Repeat:
	
>Fix:
Index: ./src/appl/gss-sample/gss-client.c
--- gss-client.c	1999/11/23 19:33:58	1.1.1.1
+++ gss-client.c	1999/11/23 19:48:28	1.3
@@ -21,7 +21,7 @@
  */
 
 #if !defined(lint) && !defined(__CODECENTER__)
-static char *rcsid = "$Header: /b/src/krb5/krb5-1.1/src/appl/gss-sample/RCS/gss-client.c,v 1.1.1.1 1999/11/23 19:33:58 jik Exp $";
+static char *rcsid = "$Header: /b/src/krb5/krb5-1.1/src/appl/gss-sample/RCS/gss-client.c,v 1.3 1999/11/23 19:48:28 jik Exp $";
 #endif
 
 #include <stdio.h>
@@ -40,10 +40,13 @@
 #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);
 }
 
@@ -104,6 +107,9 @@
  *
  * 	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
  *
@@ -121,104 +127,121 @@
  * 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;
+       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;
-	  }
+       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);
+	 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;
+     }
 
-     (void) gss_release_name(&min_stat, &target_name);
      return 0;
 }
 
@@ -273,8 +296,15 @@
  *
  * 	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
  *
@@ -282,18 +312,22 @@
  * 
  * 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;
@@ -311,103 +345,108 @@
      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);
+     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;
+	 }
 
-     /* 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;
+	 }
+	 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_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_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);
 
-     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);
+	 /* 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 {
@@ -416,58 +455,83 @@
 	 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);
+       free(in_buf.value);
 
-     printf("Signature verified.\n");
+     /* Send NOOP */
+     (void) send_token(s, TOKEN_NOOP, empty_token);
 
-     /* 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;
+     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;
+       }
+
+       (void) gss_release_buffer(&min_stat, &out_buf);
      }
 
-     (void) gss_release_buffer(&min_stat, &out_buf);
      (void) close(s);
      return 0;
 }
@@ -481,7 +545,7 @@
     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);
@@ -511,8 +575,12 @@
      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++;
@@ -529,6 +597,26 @@
 	       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++;
@@ -543,13 +631,15 @@
      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;
 }
-
Index: ./src/appl/gss-sample/gss-misc.c
--- gss-misc.c	1997/02/12 02:15:53	1.1
+++ gss-misc.c	1997/02/12 16:58:45	1.2
@@ -20,10 +20,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#if !defined(lint) && !defined(__CODECENTER__)
-static char *rcsid = "$Header: /b/src/krb5/krb5-1.1/src/appl/gss-sample/RCS/gss-misc.c,v 1.1 1997/02/12 02:15:53 jik Exp $";
-#endif
-
 #include <stdio.h>
 #include <sys/types.h>
 #include <netinet/in.h>
@@ -44,6 +40,9 @@
 
 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) );
 
@@ -93,21 +92,32 @@
  * 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);
 
@@ -146,24 +156,40 @@
  * 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) {
@@ -179,7 +205,7 @@
 	  
      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");
Index: ./src/appl/gss-sample/gss-misc.h
--- gss-misc.h	1997/02/12 02:13:38	1.1
+++ gss-misc.h	1997/02/12 16:58:52	1.2
@@ -20,10 +20,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * $Id: gss-misc.h,v 1.1 1997/02/12 02:13:38 jik Exp $
- */
-
 #ifndef _GSSMISC_H_
 #define _GSSMISC_H_
 
@@ -33,14 +29,28 @@
 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
 	PROTOTYPE( (OM_uint32 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
Index: ./src/appl/gss-sample/gss-server.c
--- gss-server.c	1999/11/23 19:33:58	1.1.1.1
+++ gss-server.c	1999/11/23 21:09:47	1.4
@@ -21,7 +21,7 @@
  */
 
 #if !defined(lint) && !defined(__CODECENTER__)
-static char *rcsid = "$Header: /b/src/krb5/krb5-1.1/src/appl/gss-sample/RCS/gss-server.c,v 1.1.1.1 1999/11/23 19:33:58 jik Exp $";
+static char *rcsid = "$Header: /b/src/krb5/krb5-1.1/src/appl/gss-sample/RCS/gss-server.c,v 1.4 1999/11/23 21:09:47 jik Exp $";
 #endif
 
 #include <stdio.h>
@@ -46,8 +46,8 @@
 
 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);
 }
 
@@ -139,89 +139,111 @@
      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);
+     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);
+       /* display the flags */
+       display_ctx_flags(*ret_flags);
 
-     if (verbose && log) {
+       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;
 }
 
@@ -306,8 +328,9 @@
 	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);
@@ -335,6 +358,7 @@
  *			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
  *
@@ -349,83 +373,128 @@
  *
  * 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");
+     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, &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);
-     }
+     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");
+	 }
 
-     (void) gss_release_buffer(&min_stat, &msg_buf);
+	 (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);
+	 }
+       }
 
-     /* Send the signature block to the client */
-     if (send_token(s, &xmit_buf) < 0)
-	return(-1);
+       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);
+	 }
 
-     (void) gss_release_buffer(&min_stat, &xmit_buf);
+	 (void) gss_release_buffer(&min_stat, &msg_buf);
 
-     /* 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);
+	 /* 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);
 }
@@ -442,6 +511,7 @@
      int s;
      int once = 0;
      int do_inetd = 0;
+     int export = 0;
 
      log = stdout;
      display_file = stdout;
@@ -457,14 +527,25 @@
 	      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 diable 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;
@@ -485,31 +566,29 @@
 	 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;
 }
Index: ./src/appl/gss-sample/README
--- README	1997/02/12 01:53:24	1.1
+++ README	1997/02/12 16:58:20	1.2
@@ -19,76 +19,130 @@
 # 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:
+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.
 
-	1.  The client and server establish a GSS-API context.  The
-	server prints the identity of the client.
+	7. The client sends an empty block to the server to tell it
+	   that the exchange is finished.
 
-	2.  The client sends a sealed (encrypted) message to the
-	server.
+	8. The client and server close the TCP/IP connection and
+	   destroy the GSS-API context.
 
-	3.  The server decrypts the message and prints it.
+The server's command line usage is
 
-	4.  The server produces a signature block for the message and
-	sends it to the client.
+	gss-server [-port port] [-verbose] [-once] [-inetd] [-export]
+		[-logfile file] service_name
 
-	5.  The client verifies the signature block.
+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 command-line options have the following meanings:
 
-Obviously, this exchange does not perform a tremendously valuable
-function; however, it demostrates the use of primary GSS-API
-interfaces.
+-port	The TCP port on which to accept connections.  Default is 4444.
 
-The server's command line usage is
+-once	Tells the server to exit after a single exchange, rather than
+	persisting.
 
-	gss-server [-port port] [-k keytab] service_name
+-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".
 
-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.
+-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).
-
-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 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".
+gss-client!) and msg is the message.  The command-line options have
+the following meanings:
+
+-port	The TCP port to which to connect.  Default is 4444.
+
+-mech	The OID of the GSS-API mechanism to use.
+
+-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).
+
+-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".
+
+-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:
 
-	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
+	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
 
-Barry Jaspan, bjaspan@security.ov.com
+This application was originally written by Barry Jaspan of OpenVision
+Technologies, Inc.  It was updated significantly by Jonathan Kamens of
 OpenVision Technologies, Inc.
-
-$Id: README,v 1.1 1997/02/12 01:53:24 jik Exp $
>Audit-Trail:
>Unformatted:

home help back first fref pref prev next nref lref last post