#include "mysccs.h"
SCCSID("@(#)gsstest.c   %E%   SAP   %I%")

static char * this_File GNU_UNUSED = __FILE__;

/************************************************************************/
/* $Id: //tools/src/freeware/gsstest/gsstest.c#7 $
 ************************************************************************
 *
 * Copyright (c) 1998-2000  SAP AG.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by SAP AG"
 *
 * 4. The name "SAP AG" must not be used to endorse or promote products
 *    derived from this software without prior written permission.
 *    For written permission, please contact www.press@sap.com
 *
 * 5. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by SAP AG"
 *
 * THIS SOFTWARE IS PROVIDED BY SAP AG ``AS IS'' AND ANY EXPRESSED
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. SAP AG SHALL BE LIABLE FOR ANY DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE ONLY IF CAUSED BY SAP AG'S
 * INTENT OR GROSS NEGLIGENCE. IN CASE SAP AG IS LIABLE UNDER THIS
 * AGREEMENT FOR DAMAGES CAUSED BY SAP AG'S GROSS NEGLIGENCE SAP AG
 * FURTHER SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT, AND SHALL NOT BE LIABLE IN EXCESS OF THE AMOUNT OF
 * DAMAGES TYPICALLY FORESEEABLE FOR SAP AG, WHICH SHALL IN NO EVENT
 * EXCEED US$ 500.000.- 
 *
 ************************************************************************/


#include "gsstest.h"
#include "non_ansi.h"
#include "locale.h"

char * gsstest_version = "Version 1.29   19-Jun-2008";
char * build_time      = __DATE__ " at " __TIME__ ;

char     bogus_ptr[16];

struct prog_options_s options = {
   /* -b 0/1  bogus_check	     = */		TRUE,
   /* -s 0/1  sap_constraints	     = */		FALSE,
   /* -m      try_msgprot_anyway     = */		FALSE,
   /* -x 0/1  cross_process_xfer     = */		TRUE,
   /* -f      force_xfer	     = */		FALSE,
   /* -c      child_process	     = */		FALSE,
   /* -z      zap trailing NULs on names */		FALSE,
   /* -e      test user and app errors = */             FALSE,
   /* -v      show error location info = */	        FALSE,
   /*         tee logfile to stdout  = */		FALSE,
   /* -E      try user errors        = */               TRUE,
   /* -v <n>  verbose_level	     = */		0,
   /* -t <n>  show_timing_data	     = */		0,
   /* -n <n>  num_parallel_contexts  = */		10,
   /* -w <n>  wrap_range_level       = */	        0,
   /*	      mech_to_use	     = */		0,
   /* -l lib  dll_name		     = */		NULL,  /* dynamic */
   /* -a name target/acceptor name   = */		NULL,  /* dynamic */
   /*	      initiator		     = */		NULL,  /* dynamic */
   /* -o/p    log filename           = */		NULL   /* dynamic */
};


FILE   * vfp   = NULL;    /* "verbose output" (global file pointer) */
FILE   * logfp = NULL;    /* "logfile output" (global file pointer) */

char   * prog_exe_name = PROG_EXE_NAME;
char   * logfile = NULL;

char   * parent_env  = "GSSTEST_CHILD=0";
char   * child_env   = "GSSTEST_CHILD=1";

char  ** prog_argv;
int      prog_argc;

size_t   testnum          = 0;
int      missing_msg_prot = 0;
int      ignore_name_for_statistics = FALSE;
int      testing_kerberos = FALSE;

int	 gui_only_flag = FALSE;

Ulong    timedelay;

DLL_GSSFP_T    GSSfps_ini;
DLL_GSSFP_T    GSSfps_acc;

char * nt_i_elements[64];
char * nt_a_elements[64];

gss_OID_desc nt_ini_oid[1] = { { 0, (void *) &(nt_i_elements[0]) } };
gss_OID_desc nt_acc_oid[1] = { { 0, (void *) &(nt_a_elements[0]) } };

gss_OID_desc pre_rfc1964_krb5_oid =  {  5, "\053\005\001\005\002"                     };
gss_OID_desc     rfc1964_krb5_oid =  {  9, "\052\206\110\206\367\022\001\002\002"     }; 

#if 0
gss_name_t     ini_name  = GSS_C_NO_NAME;
gss_name_t     acc_name  = GSS_C_NO_NAME;
gss_name_t     targ_name = GSS_C_NO_NAME;
#endif

struct sys_platform_s  platform_info;

char * snc_qop_values[] = {
   "(unknown)",
   "Authentication only",
   "Integrity Protection",
   "Privacy Protection"
};

/*
 * show_greetings()
 *
 *
 */
void
show_greetings( void )
{

   XVEB((V_SHOW,"\n"
	        "  **************************************************************************\n"
	        "  ***                                                                    ***\n"
		"  ***  \"gsstest\" -- GSS-API v2  Shared Library API Test Program          ***\n"
		"  ***                                                                    ***\n"
		"  ***  %-50.50s                ***\n"
		"  ***                                                                    ***\n",
		gsstest_version ));
   XVEB((V_SHOW,"  ***  This implementation is Copyright (c), 1998  SAP AG Walldorf       ***\n"
		"  ***                                                                    ***\n"
		"  **************************************************************************\n"
		"  ***      This tool may be freely used to test functionality and        ***\n" ));
   XVEB((V_SHOW,"  ***      robustness of GSS-API v2 mechanism implemenations             ***\n"
		/* "  *** See accompanying README.LIC for full licensing&usage terms   ***\n" */
		"  **************************************************************************\n" ));
   XVEB((V_SHOW,"  *** THIS SOFTWARE IS PROVIDED BY SAP AG ``AS IS'' AND ANY EXPRESSED    ***\n"
		"  *** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE          ***\n"
	        "  *** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ***\n"
	        "  *** PURPOSE ARE DISCLAIMED. SAP AG SHALL BE LIABLE FOR ANY DAMAGES     ***\n" ));
   XVEB((V_SHOW,"  *** ARISING OUT OF THE USE OF THIS SOFTWARE ONLY IF CAUSED BY SAP AG'S ***\n"
	        "  *** INTENT OR GROSS NEGLIGENCE. IN CASE SAP AG IS LIABLE UNDER THIS    ***\n"
		"  *** AGREEMENT FOR DAMAGES CAUSED BY SAP AG'S GROSS NEGLIGENCE SAP AG   ***\n"
	        "  *** FURTHER SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, ***\n" ));
   XVEB((V_SHOW,"  *** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,***\n"
	        "  *** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,    ***\n"
		"  *** OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY    ***\n"
	        "  *** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,        ***\n" ));
   XVEB((V_SHOW,"  *** OR TORT, AND SHALL NOT BE LIABLE IN EXCESS OF THE AMOUNT OF        ***\n"
	        "  *** DAMAGES TYPICALLY FORESEEABLE FOR SAP AG, WHICH SHALL IN NO EVENT  ***\n"
	        "  *** EXCEED US$ 500.000.-                                               ***\n" ));
   XVEB((V_SHOW,"  **************************************************************************\n"
		"\n" ));

   return;

} /* show_greetings() */




/*
 * usage()
 *
 *
 */
void
usage( void )
{
   show_timer_resolution();

   sys_greeting("  ", &platform_info);

   fprintf(vfp, "\n");

   fprintf(vfp, "\n"
	        "  gsstest  -l <lib> -a <target_name> [-d <level>] [-n <num>] [-w <level> [-v]\n"
		"          [-b 1/0] [-s 1/0] [-x 1/0] [-t <level>]    [-f] [-h] [-m] [-e] [-z]\n"
		"          [-o <logfile>] [-p <logfile>] [-l <2nd-lib>]\n"
		"\n"										   );
   fprintf(vfp, "  required arguments:\n"
	        "    -l <lib>            specifies the name of the shared library / DLL\n"
		"    -a <target_name>    specifies the identity of the target / acceptor\n"
		"\n"										   );
   fprintf(vfp, "  optional arguments:\n"
	        "    -d <level>   level of debug/trace output [0..4]               (default  0)\n"
		"    -n <num>     number of concurrent security contexts           (default 10)\n"
		"    -b 1/0       pass bogus or cleared handles into gssapi        (default  1)\n"
		"    -s 1/0       check/verify SAP-specific constraints            (default  0)\n" );
   fprintf(vfp, "    -w <level>   wrap ranges level (resolution of test [0..3])    (default  0)\n"
		"    -x 1/0       attempt cross-process security context transfers (default  1)\n"
		"    -o <logfile> transcript output into logfile and STDOUT\n"
		"    -p <logfile> transcript output into logfile only\n"
		"    -e           simulate/test user and application errors\n"			   );
   fprintf(vfp,	"    -E           DON'T try user error (typo in names, wrong names)\n"
   		"    -f           imply GSS_C_TRANS_FLAG, force security context transfers\n"
		"    -h           show this help\n"						   
	        "    -m           imply CONF and INTEG, force message protection\n"		   );
   fprintf(vfp,	"    -v           show location&line-numbers for ERROR messages\n"
   		"    -z           zap trailing NUL chars on names (dirty hack!)\n"
		"    -t <level>   print detailed timing statistics for gssapi calls (default  0)\n"
		"                   0=none, 1=parent, 2=child, 3=both\n" );
   fprintf(vfp,	"    -l <2nd-lib> specifies the name of a secondary shared library / DLL\n"
		"                   which will then be used for all acceptor side operations\n"
		"                   Use this for interop-testing of two libraries / DLLs\n"
		"\n" );

   return;

} /* usage() */



  
/*
 * clean_options()
 *
 *
 */
void
clean_options( void )
{
   CFREE( options.target     );
   CFREE( options.dll_name_1 );
   CFREE( options.dll_name_2 );
   CFREE( options.initiator  );
   CFREE( options.logfile    );

   if ( logfp!=NULL ) {
      fflush( logfp );
      fclose( logfp );
      logfp = NULL;
   }

   return;

} /* clean_options() */




/*
 * open_logfile()
 *
 */
FILE *
open_logfile( char  * log_filename, char * mode, int with_tee )
{
   FILE  * fp = NULL;

   if ( log_filename!=NULL ) {
      fp = fopen( log_filename, mode );
      if ( fp==NULL ) {
	 fprintf(vfp, "fopen(\"%s\",\"%s\" failed: %s\n",
		      log_filename, mode, strerror(errno) );
      } else {
	 if ( with_tee!=0 ) {
	    options.log_tee     = TRUE;
	    duplicate_to_stdout = TRUE;
	 }
      }
   }

   return(fp);

} /* open_logfile() */


/*
 * tail_logfile()
 *
 */
void
tail_logfile( FILE * logfp )
{
   if ( logfp!=NULL ) {
      fseek( logfp, 0, SEEK_END );
   }

   return;

} /* tail_logfile() */




/*
 * main()
 *
 *
 */
int
main( int argc, char **argv )
{
   int		    rc        = 0;
   DLL_GSSFP_T    * gssfp_ini = &GSSfps_ini;
   DLL_GSSFP_T    * gssfp_acc = &GSSfps_acc;
   int              opt;
   int		    intarg;
   int              level;
   int		    i;
   int		    result    = 0;

   DEBUG_BEGIN(main)

   DEBUG_EXEC( debug_init( FALSE, stderr, "STDERR"); )

   vfp = stderr;

   setlocale(LC_ALL, "C");

   prog_argv = argv;
   prog_argc = argc;

   putenv(parent_env);

   verbose_init( 0, stdout, "STDOUT", FALSE );

   init_timer();  /* THIS MUST BE EARLY ON!! */

   if (argc<2 && dll_dynamic_linking!=FALSE ) {
      show_greetings();
      usage();
      exit(0);
   }

   Xopterr = 0;
   while( (opt = Xgetopt( argc, argv, ":a:b:cd:eEfhl:mM:n:o:p:s:t:vw:x:z" ))>0 ) {
      switch( opt ) {
        case ':':
		  show_greetings();
		  fprintf(vfp, "Missing argument for option \"-%c\" -- aborting!\n", Xoptopt );
		  result = 1;
		  goto error;

        case '?':
	default:
		  show_greetings();
		  fprintf(vfp, "Unknown or Invalid option \"-%c\" -- aborting!\n", Xoptopt );
		  result = 1;
		  goto error;

	case 'a': options.target = Strmaxdup( Xoptarg, 256 );
	          break;

	case 'b': options.bogus_check = (atoi(Xoptarg)) ? 1 : 0;
		  break;

		  /* The command line option "-c" is reserved for starting */
		  /* our own child when transfering security context       */
		  /* accross process boundaries                            */
	case 'c': result = read_options_from_file( OPTIONS_FILE );
		  if ( result!=0 ) {
		     show_greetings();
		     XVEB((V_ERR, "Failed to read options from file \"%s\" -- aborting\n", OPTIONS_FILE ));
		     goto error;
		  }

		  putenv(child_env);
		  options.child_process       = TRUE;
		  options.cross_process_xfer  = (options.cross_process_xfer>0)
						 ? (options.cross_process_xfer - 1) : 0;
		  logfp = open_logfile( options.logfile, "a+", options.log_tee );
		  if ( logfp!=NULL ) {
		     verbose_init( options.verbose_level, logfp, options.logfile, FALSE );
		  } else {
		     set_verbose_level( options.verbose_level );
		  }
		  goto child_opts;


	case 'd': level = atoi(Xoptarg);
		  set_verbose_level(level);
		  options.verbose_level = verbose_level;
		  break;

        case 'e': options.test_errors = TRUE;
		  break;

	case 'E': options.try_user_errors = FALSE;
		  break;

	case 'f': options.force_xfer = TRUE;
		  break;

	case 'h': show_greetings();
		  usage();
		  result = 0;
		  goto error;

	case 'l': if ( options.dll_name_1==NULL ) {
		     options.dll_name_1 = Strmaxdup( Xoptarg, 1024 );
		  } else if ( options.dll_name_2==NULL ) {
		     options.dll_name_2 = Strmaxdup( Xoptarg, 1024 );
		  } else {
		     fprintf(vfp, "at most 2 libraries can be specified with option '-l'\n");
		     goto error;
		  }
		  break;

        case 'm': options.try_msgprot_anyway = TRUE;
		  break;

	case 'M': intarg = atoi(Xoptarg);
		  if ( intarg>=0 && intarg<=100 ) {
		      options.mech_to_use = intarg;
		  }
		  break;

	case 'n': intarg = atoi(Xoptarg);
		  if ( intarg>0 && intarg<20000 ) {
		     options.num_parallel_contexts = intarg;
		  }
		  break;

        case 'o':
	case 'p': logfile = Xoptarg;
		  (options.logfile) = Strmaxdup( logfile, 256 );
		  logfp = open_logfile( options.logfile, "w", (opt=='o') );
		  break;

        case 's': options.sap_constraints = (atoi(Xoptarg)) ? 1 : 0;
		  break;

	case 't': intarg =  (atoi(Xoptarg));
		  if ( intarg>=0 && intarg <=3
		       && (*Xoptarg=='0' || *Xoptarg=='1' || *Xoptarg=='2' || *Xoptarg=='3' ) ) {
		     options.show_timing_data = intarg;
		  } else {
		     show_greetings();
		     fprintf(vfp, "use numeric argument [0..3] for option '-t'\n");
		     goto error;
		  }
		  break;

        case 'v': show_error_location = options.error_location = TRUE;
		  break;

        case 'w': intarg = (atoi(Xoptarg));
		  if ( intarg>=0 && intarg<=3
		       && (*Xoptarg=='0' || *Xoptarg=='1' || *Xoptarg=='2' || *Xoptarg=='3' ) ) {
		     options.wrap_range_level = intarg;
		  } else {
		     show_greetings();
		     fprintf(vfp, "use numeric argument [0..3] for options '-w'\n");
		     goto error;
		  }
		  break;

	case 'x': options.cross_process_xfer =  (atoi(Xoptarg)) ? 1 : 0;
		  break;

	case 'z': options.zap_trailing_nuls = TRUE;
		  break;

      }
   }

   if ( Xoptind != argc ) {
      show_greetings();
      fprintf(vfp, "unexpected non-option argument%s encountered:\n", (Xoptind+1==argc) ? "" : "s" );
      if ( (argc - Xoptind)>0 ) {
	 for ( i = Xoptind ; i<argc ; i++ ) {
	    fprintf(vfp, "    argv[%u] = \"%.250s\"\n", (Uint) i, argv[i] );
	 }
      }
      fprintf(vfp, "\n");
      goto error;
   }

   if ( logfp!=NULL ) {
      /* switch to logfile -- if one was selected with '-o' command line argument */
      verbose_init( options.verbose_level, logfp, logfile, TRUE );
   }

   if ( options.zap_trailing_nuls!=FALSE
	||  options.cross_process_xfer==0
	||  options.try_msgprot_anyway!=0
	||  options.bogus_check==0
        ||  options.try_user_errors==0
	||  options.dll_name_2!=NULL ) {
      options.sap_constraints = FALSE;
   }

   show_greetings();

   if ( options.dll_name_1==NULL ) {
      options.dll_name_1 = Strmaxdup( "gssapi" SHLIB_EXTENSION, 1024 );
   }

   result = write_options_to_file( OPTIONS_FILE );
   if ( result!=0 )
      goto error;

child_opts:
   show_error_location = options.error_location;
   clear_timing_data( verbose_level, gssfp_ini, GSS_INVALID_CALL, GSS_INVALID_CALL );
   clear_timing_data( verbose_level, gssfp_acc, GSS_INVALID_CALL, GSS_INVALID_CALL );

   /* Use argv[0] as the program name for our child process */
   prog_exe_name = argv[0];

   if ( options.child_process==FALSE ) {

      options.show_timing_data &= 0x01; /* mask out child timing-stats bit */
      rc += parent_main( gssfp_ini, gssfp_acc );

      remove( OPTIONS_FILE );

   } else {

      options.show_timing_data &= 0x02; /* mask out parent timing-stats bit */
      rc += child_main( gssfp_ini, gssfp_acc );

   }

error:
   clean_options();

   return(result);

} /* main() */




/*
 * parent_load_dll()
 *
 *
 */
int
parent_load_dll( int p_verbose,  char *  p_dll_name,  char *p_postfix,  DLL_GSSFP_T   *  p_gssfp )
{
   int  rc;

   if ( p_verbose==0 ) {
      XVEB((V_SHOW, "Loading GSS-API %s%s \"%s\" ...\n", SHLIB_TERM, p_postfix, p_dll_name));
   }

   rc  = dll_load_gssapi( p_verbose, p_dll_name, p_gssfp );

   /* Abort here when the loading of the DLL failed */
   if ( rc!=0 ) {
      XVEB((V_SHOW, "Loading of %s terminated with error(s) -- aborting!\n", SHLIB_TERM));
      goto error;
   }

   if ( p_verbose==0 && p_gssfp->snc_adapter_flag!=FALSE ) {
      XVEB((V_SHOW, "      ... was loaded as an SAP SNC-Adapter.\n"));
   }

error:
   return(rc);

} /* parent_load_dll() */



/*
 * parent_main()
 *
 *
 */
int
parent_main( DLL_GSSFP_T  * p_gssfp_ini,  DLL_GSSFP_T  * p_gssfp_acc )
{
   int		    rci	      = 0;
   int		    rc        = 0;
   int		    bad_opt   = 0;
   char           * what;

   show_timer_resolution();

   sys_greeting("", &platform_info );

   /* XVEB((V_SHOW, "====================\n\n")); */
   XVEB((V_SHOW, "\n"));

   rc = parent_load_dll( verbose_level, options.dll_name_1, " #1", p_gssfp_ini );
   if ( rc!=0 )
      goto error;

   XVEB((V_SHOW, "\n"));

   /* retrieve the list of supported mechanisms from the gssapi library */
   rc += indicate_mechs( verbose_level, p_gssfp_ini, &(p_gssfp_ini->mech_set), NULL );
   print_timing_data( verbose_level, p_gssfp_ini, "Timing for initial GSS-API call",
			     GSS_INDICATE_MECHS, 0, TRUE );
   if ( p_gssfp_ini->mech_set!=GSS_C_NO_OID_SET ) {

      if ( verbose_level==0 ) 
	 print_oid_set( 1, "mech_list from gss_indicate_mechs() #1", p_gssfp_ini->mech_set);

      if ( options.sap_constraints!=FALSE
	   &&  (p_gssfp_ini->snc_adapter_flag)==FALSE ) {
	 int  index;

	 index = find_builtin_snc_adapter( p_gssfp_ini->mech_set );
	 if ( index>=0 ) {
	    if ( (p_gssfp_ini->mech_set->count)>1 ) {
	       XVEB((V_SHOW, "SNC will recognize this mechanism OID and force this selection ---\n"));
	    }
	    options.mech_to_use = index;
	    /* We need to sync this change of mechanism selection  */
	    /* to the options file so that the child process will  */
	    /* be able to pick the same mechanism from the library */
	    rc += write_options_to_file( OPTIONS_FILE );
	 }
      }

      if ( options.mech_to_use >= p_gssfp_ini->mech_set->count ) {
	 rc++;
	 XVEB((V_ERR, "Invalid mechanism selection (%u)\n", (Uint)options.mech_to_use));
	 goto error;
      }

      p_gssfp_ini->mech = &(p_gssfp_ini->mech_set->elements[options.mech_to_use]);
      XVEB((V_SHOW, "  Selecting mechanism (%u) from GSS %s #1:\n",
		       (Uint) options.mech_to_use, SHLIB_TERM));
      print_oid(3, NULL, p_gssfp_ini->mech);

   }

   if ( 0==compare_oid( p_gssfp_ini->mech, &pre_rfc1964_krb5_oid )
       || 0==compare_oid( p_gssfp_ini->mech, &rfc1964_krb5_oid ) ) {
       testing_kerberos = TRUE;
   } else {
       testing_kerberos = FALSE;
   }

   if ( options.dll_name_2 == NULL ) {

      p_gssfp_acc = p_gssfp_ini;

   } else {

      XVEB((V_SHOW, "\n====================\n\n"));

      rc = parent_load_dll( verbose_level, options.dll_name_2, " #2", p_gssfp_acc );
      if ( rc!=0 )
	 goto error;

      XVEB((V_SHOW, "\n"));

      rc += indicate_mechs( verbose_level, p_gssfp_acc, &(p_gssfp_acc->mech_set), NULL );
      print_timing_data( verbose_level, p_gssfp_acc, "Timing for initial GSS-API call",
			     GSS_INDICATE_MECHS, 0, TRUE );

      if ( p_gssfp_acc->mech_set!=GSS_C_NO_OID_SET ) {
	 int  index;

	 if ( verbose_level==0 )
	    print_oid_set( 1, "mech_list from gss_indicate_mechs() #2", p_gssfp_acc->mech_set);

	 /* Search for the selected mechanism OID in the mech_list of the */
	 /* second library                                                */
	 index = oid_in_oid_set( p_gssfp_acc->mech_set, p_gssfp_ini->mech );
	 if ( index<0 ) {
	    XVEB((V_ERR, "\nSelected Mechanism is NOT supported by 2nd GSS %s!\n", SHLIB_TERM));
	    rc++;
	    goto leave_early;
	 }

	 p_gssfp_acc->mech = &(p_gssfp_acc->mech_set->elements[index]);
	 XVEB((V_SHOW, "  Using corresponding mechanism (%u) from GSS %s #2:\n",
			  (Uint) index, SHLIB_TERM ));
	 print_oid(3, NULL, p_gssfp_acc->mech);
      }

   }

   XVEB((V_SHOW, "\n====================\n\n"));


   /* copy the target name and put trash behind it                 */
   /* a gssapi mechanism is supposed to look at the length field,  */
   /* GSS-API printable names do not need a trailing NUL character */
   if ( options.target!=NULL && *options.target!='\0' ) {
      VERBOSE_DUPMEM( options.target, strlen(options.target), (p_gssfp_ini->acceptor), (p_gssfp_ini->acceptor_len) );
      if ( p_gssfp_ini != p_gssfp_acc ) {
	 VERBOSE_DUPMEM( options.target, strlen(options.target), (p_gssfp_acc->acceptor), (p_gssfp_acc->acceptor_len) );
      }

   }


   if ( p_gssfp_ini->mech_set!=GSS_C_NO_OID_SET
        &&  p_gssfp_acc->mech_set!=GSS_C_NO_OID_SET ) {

      if ( p_gssfp_ini->gss_inquire_names_for_mech!=0 ) {
	 /* requesting list of supported nametypes for mechanism */
	 XVEB((V_SHOW, "Checking supported nametypes via gss_inquire_names_for_mech()\n"));
	 rc += inquire_names_for_mech( 1, p_gssfp_ini, &(p_gssfp_ini->nt_list), NULL );
	 if ( verbose_level<=1 ) {
	    rc += print_oid_set( 1, "name_types", (p_gssfp_ini->nt_list) );
	 }
	 rci = validate_oidset( p_gssfp_ini, OID_ANY, "gss_inquire_names_for_mech()",
				"nametype_list", p_gssfp_ini->nt_list );
	 rc += rci;
	 if (rci>0) {
	    release_oid_set( p_gssfp_ini, &(p_gssfp_ini->nt_list) );
	 }
	 XVEB((V_SHOW, "\n"));
      }

      rc += generic_tests( p_gssfp_ini );
      if ( p_gssfp_ini!=p_gssfp_acc ) {
	 rc += generic_tests ( p_gssfp_acc );
      }

      rc += cred_tests( p_gssfp_ini,  p_gssfp_acc );

      if ( p_gssfp_ini->initiator_len > 0) {

	 rc += name_tests( p_gssfp_ini );
	 if ( p_gssfp_ini!=p_gssfp_acc ) {
	    rc += name_tests( p_gssfp_acc );
	 }

	 rc += context_tests( p_gssfp_ini, p_gssfp_acc );

	 if ( p_gssfp_ini->context_counter > 0  &&  p_gssfp_acc->context_counter > 0 ) {
	    rc += msg_prot_tests( p_gssfp_ini, p_gssfp_acc );
	 }

      }

      if ( options.try_user_errors!=0 &&  p_gssfp_ini->context_counter >0 ) {
	 rc += error_tests( p_gssfp_ini, p_gssfp_acc );
      }

      XVEB((V_HIDE, "\n\n"));

   }

leave_early:
   /* release these two names so that the timing statistics include them */
   rc += release_name( p_gssfp_ini, &(p_gssfp_ini->acc_name) );
   rc += release_name( p_gssfp_ini, &(p_gssfp_ini->ini_name) );
   if ( p_gssfp_ini != p_gssfp_acc ) {
      rc += release_name( p_gssfp_acc, &(p_gssfp_acc->acc_name) );
      rc += release_name( p_gssfp_acc, &(p_gssfp_acc->ini_name) );
   }

   XVEB((V_SHOW, "====================\n\n"));
   
   if ( p_gssfp_ini->context_counter==0 || p_gssfp_acc->context_counter==0 ) {

      XVEB((V_SHOW, "  ABORTING TEST!\n\n"));
      XVEB((V_SHOW, "  Not even a single security context could be established.\n\n"));
      XVEB((V_SHOW, "  Accumulated RC value:  %d\n", rc ));
      XVEB((V_SHOW, "\n====================\n"));

   } else {

      XVEB((V_SHOW, "Finally ...\n----------\n"));

      sap_constraints_count = 0;

      print_gssapi_statistics( p_gssfp_ini, p_gssfp_acc, rc );

      XVEB((V_SHOW, "\n==================\n\n"));
      if ( rc==0 ) {
	 XVEB((V_SHOW, "Passing all API result tests.\n"));
      } else {
	 XVEB((V_SHOW, "FAILING some API result tests with accumulated RC value:  %d\n", rc ));
      }


      if ( options.sap_constraints!=FALSE ) {

	 /* Were we actually testing SAP constraints on the API ? */
	 if ( sap_constraints_count==0 ) {
	    XVEB((V_SHOW, "Passing all SAP constraints.\n"));
	 } else {
	    XVEB((V_SHOW, "FAILING %d SAP constraint%s!\n",
	               sap_constraints_count,
		       (sap_constraints_count==1) ? "" : "s" ));
	 }

	 XVEB((V_SHOW, "\n"));

	 if ( options.bogus_check==FALSE ) {
	    XVEB((V_SHOW, "OPTION '-b 0' was used.\n"));
	    bad_opt++;
	 }

	 if ( options.try_msgprot_anyway!=FALSE ) {
	    XVEB((V_SHOW, "OPTION '-m' was used.\n"));
	    bad_opt++;
	 }

	 if ( options.cross_process_xfer==FALSE ) {
	    XVEB((V_SHOW, "OPTION '-x 0' was used.\n"));
	    bad_opt++;
	 }

	 if ( options.zap_trailing_nuls!=FALSE ) {
	    XVEB((V_SHOW, "OPTION '-z' was used.\n"));
	    bad_opt++;
	 }

	 if ( bad_opt>0 ) {

	    XVEB((V_SHOW, "\n"));
	    XVEB((V_SHOW, "Several SAP-contraints were not checked because of these options!\n"));

	 } else {

	    if ( p_gssfp_ini->snc_builtin_flag!=FALSE ) {
	       what = "builtin";
	    } else if ( p_gssfp_ini->snc_adapter_flag!=FALSE ) {
	       what = "external";
	    } else {
	       what = NULL;
	    }

	    if ( sap_constraints_count!=0 || rc!=0 ) {

	       XVEB((V_SHOW, "!!! FAILED !!!   SAP GSS-API v2 Test\n"));

	    } else {

	       if ( compare_oid( p_gssfp_ini->mech, p_gssfp_ini->mech_set->elements)==0 ) {
		  if ( gui_only_flag!=FALSE ) {
		     XVEB((V_SHOW, "!!! Performance Constraint !!!\n"
				   "!!! Frontend use ONLY      !!!\n\n"));
		  }

		  if ( what==NULL ) {
		     XVEB((V_SHOW, "** No problems detected, BUT\n"));
		     XVEB((V_SHOW, "** this gssapi mechanism REQUIRES the use of an external SNC-Adapter\n"));
		  } else {
		     XVEB((V_SHOW, "--- Passed ---   SAP GSS-API v2 Test (%s SNC-Adapter)\n", what));
		  }

		  XVEB((V_SHOW, "\n"));

		  print_oid( 1, "Mechanism ", p_gssfp_ini->mech         );
		  print_oid( 1, "Nametype  ", p_gssfp_ini->can_nametype );

		  XVEB((V_SHOW, "\n"));
		  XVEB((V_SHOW, "  Max. data protection level =   %d (%s)\n",
				(int)p_gssfp_ini->snc_qop, snc_qop_values[p_gssfp_ini->snc_qop] ));

		  XVEB((V_SHOW, "\n"));
		  XVEB((V_SHOW, "  Hardware Platform          =   %s %s\n",
				platform_info.os_name, platform_info.os_release ));
		  XVEB((V_SHOW, "\n"));
		  XVEB((V_SHOW, "  Platform Description       =   %s\n",
				os_platform ));
		  XVEB((V_SHOW, "\n"));

	       }

	    }

	 }

      } /* options.sap_constraints!=FALSE */


      XVEB((V_SHOW, "\n==================\nDone.\n\n"));

   } /* (p_gssfp->context_counter > 0 */

   /* releasing list of supported nametypes (if we have one) */
   rc += release_oid_set( p_gssfp_ini, &(p_gssfp_ini->nt_list) );
   if ( p_gssfp_ini!=p_gssfp_acc ) {
      rc += release_oid_set( p_gssfp_acc, &(p_gssfp_acc->nt_list) );
   }

   if ( (p_gssfp_ini->gss_export_name)!=0 ) {

      /*  XVEB((V_HIDE, "GSS-API v2 mechanism:  releasing mech_set from gss_indicate_mechs().\n" )); */
      rc += release_oid_set( p_gssfp_ini, &(p_gssfp_ini->mech_set) );

   } else {

      /* XVEB((V_HIDE, "treating mech_set from gss_indicate_mechs() as readonly.\n" )); */
      p_gssfp_ini->mech_set = GSS_C_NO_OID_SET;
   }

   if ( p_gssfp_ini!=p_gssfp_acc ) {
      if ( (p_gssfp_acc->gss_export_name)!=0 ) {
	 rc += release_oid_set( p_gssfp_acc, &(p_gssfp_acc->mech_set) );
      } else {
	 p_gssfp_acc->mech_set = GSS_C_NO_OID_SET;
      }
   }

error:
   rc += dll_unload_gssapi( verbose_level, p_gssfp_ini );
   if ( p_gssfp_ini != p_gssfp_acc ) {
      rc += dll_unload_gssapi( verbose_level, p_gssfp_acc );
   }

   return(rc);

} /* parent_main() */




/*
 * child_main()
 *
 *
 */
int
child_main( DLL_GSSFP_T  * p_gssfp_ini,  DLL_GSSFP_T  * p_gssfp_acc )
{
   struct tmsg_job   *	joblist = NULL;
   struct ctx_desc   *  ini     = NULL;
   struct ctx_desc   *  acc     = NULL;
   char		     *  enter_msg;
   char		     *  leave_msg;
   int			success = FALSE;
   int			rci     = 0;
   int			rc2;
   int			rc      = 0;

   enter_msg = "  >->->->->->->->->->-> Greetings from Child Process >->->->->->->->->->->\n";
   leave_msg = "  <-<-<-<-<-<-<-<-<-<-< Terminating Child process  <-<-<-<-<-<-<-<-<-<-<-<\n\n";

   set_enter_leave_messages( enter_msg, leave_msg );
   XVEB((V_OK, verbose_level, "\n"));

   rc  = dll_load_gssapi( verbose_level-2, options.dll_name_1, p_gssfp_ini );
   if ( rc==0 ) {
      if ( options.dll_name_2!=NULL ) {
	 rc  = dll_load_gssapi( verbose_level-2, options.dll_name_2, p_gssfp_acc );
      } else {
	 p_gssfp_acc = p_gssfp_ini;
      }
   }

   /* Abort here when the loading of the DLL failed */
   if ( rc!=0 )
      goto error;

   p_gssfp_ini->rci = p_gssfp_acc->rci = 0;

   /* retrieve the list of supported mechanisms from the gssapi library */
   rc += indicate_mechs( verbose_level-1, p_gssfp_ini, &(p_gssfp_ini->mech_set), NULL );
   if ( p_gssfp_ini != p_gssfp_acc ) {
      rc += indicate_mechs( verbose_level-1, p_gssfp_acc, &(p_gssfp_acc->mech_set), NULL );
   }

   if ( p_gssfp_ini->mech_set!=GSS_C_NO_OID_SET ) {

      if ( options.mech_to_use >= p_gssfp_ini->mech_set->count ) {

	 rc++;
	 XVEB((V_ERR, "Invalid mechanism selection (%u)\n",
	              (Uint)options.mech_to_use));

      } else {

	 p_gssfp_ini->mech = &(p_gssfp_ini->mech_set->elements[options.mech_to_use]);

	 if ( p_gssfp_ini->gss_inquire_names_for_mech!=0 ) {
	    /* requesting list of supported nametypes for mechanism */
	    rc += inquire_names_for_mech( 0, p_gssfp_ini, &(p_gssfp_ini->nt_list), NULL );
	    rci = validate_oidset( p_gssfp_ini, OID_ANY, "gss_inquire_names_for_mech()",
				   "nametype_list", p_gssfp_ini->nt_list );
	    rc += rci;
	    if (rci>0) {
	       release_oid_set( p_gssfp_ini, &(p_gssfp_ini->nt_list) );
	    }
	 }

	 if ( p_gssfp_ini != p_gssfp_acc ) {
	     if ( p_gssfp_acc->mech_set!=GSS_C_NO_OID_SET ) {

		int  index;

		/* Search for the selected mechanism OID in the mech_list of the */
		/* second library                                                */
		index = oid_in_oid_set( p_gssfp_acc->mech_set, p_gssfp_ini->mech );
		if ( index<0 ) {
		    XVEB((V_ERR, "\nSelected Mechanism is NOT supported by 2nd GSS %s!\n", SHLIB_TERM));
		    rc++;
		} else {
		    p_gssfp_acc->mech = &(p_gssfp_acc->mech_set->elements[index]);
		}
	     }
	 }

	 if ( p_gssfp_ini->mech!=GSS_C_NO_OID && p_gssfp_acc->mech!=GSS_C_NO_OID ) {
	    /* DebugBreak(); */

	    rc += import_from_file( verbose_level, PARENT_CTX_FILE, TRUE, &joblist,
				    p_gssfp_ini, p_gssfp_acc, &ini, &acc, &rc2, &success );
	    if ( success!=FALSE ) {

	       if ( joblist!=NULL ) {

		  rc += test_message_exchange( verbose_level, "child-imported context",
					       options.show_timing_data, joblist,
					       &ini, &acc, NULL, NULL, &success );
	       }

	       remove( CHILD_CTX_FILE );
	       if ( ini==NULL || acc==NULL ) {
		  char   * which;

		  which = (ini==NULL) ? ((acc==NULL) ? "both contexts" : "initiator context") : "acceptor context";
		  XVEB((V_ERR, "Child process lost %s!\n", which));
	       } else {
		  rc += export_to_file( verbose_level, CHILD_CTX_FILE, NULL, rc,
				        &ini, &acc, &success );
	       }
	    }

	    if ( joblist!=NULL )     { free( joblist );  joblist = NULL; }

	    rc += release_ctx_desc( &ini );
	    rc += release_ctx_desc( &acc );
	 
	    /* releasing list of supported nametypes (if we have one) */
	    rc += release_oid_set( p_gssfp_ini, &(p_gssfp_ini->nt_list) );
	 }
      }

      XVEB((V_OK, verbose_level-1, "\n\n"));

      if ( (p_gssfp_ini->gss_export_name)!=0 ) {
	 rc += release_oid_set( p_gssfp_ini, &(p_gssfp_ini->mech_set) );
      } else {
	 p_gssfp_ini->mech_set = GSS_C_NO_OID_SET;
      }

      if ( p_gssfp_ini != p_gssfp_acc ) {
	 if ( (p_gssfp_acc->gss_export_name)!=0 ) {
	    rc += release_oid_set( p_gssfp_acc, &(p_gssfp_acc->mech_set) );
	 } else {
	    p_gssfp_acc->mech_set = GSS_C_NO_OID_SET;
	 }
      }

   }

   /* release these two names so that the timing statistics include them */
   rc += release_name( p_gssfp_ini, &(p_gssfp_ini->acc_name) );
   rc += release_name( p_gssfp_ini, &(p_gssfp_ini->ini_name) );
   if ( p_gssfp_ini != p_gssfp_acc ) {
      rc += release_name( p_gssfp_acc, &(p_gssfp_acc->acc_name) );
      rc += release_name( p_gssfp_acc, &(p_gssfp_acc->ini_name) );
   }

   print_timing_statistics(verbose_level, p_gssfp_ini);
   if ( p_gssfp_ini!=p_gssfp_acc ) {
      print_timing_statistics(verbose_level, p_gssfp_acc);
   }
 
error:
   rc += dll_unload_gssapi( verbose_level-2, p_gssfp_ini );
   if ( p_gssfp_ini!=p_gssfp_acc ) {
      rc += dll_unload_gssapi( verbose_level-2, p_gssfp_acc );
   }


   checkout_message(); /* XVEB((V_OK, verbose_level+1, leave_msg )); */
   
   return(rc);

} /* child_main() */



/*
 * set_static_nt_oid()
 *
 * Description:
 *   Create a static nametype OID for the printable canonical
 *   name.  When transfering a security context to a child process,
 *   the names are passed along as printable accomanied by a
 *   nametype oid for the canonical printable name ...
 *
 *   We only have two of them, one for each library / gssfp:
 *   initiator and acceptor.
 *
 */
int
set_static_nt_oid( DLL_GSSFP_T  * p_gssfp, gss_OID p_target_oid, gss_OID  p_oid )
{
   char        * this_Call = "set_static_nt_oid";

   if ( p_oid->length>=64 ) {
      XVEB((V_BUG, "%(): oid_length %lu exceeds static buffer!\n",
		   this_Call, (Ulong) p_oid->length ));
      return(1);

   } else if ( p_target_oid==nt_ini_oid ) {

      memcpy( nt_ini_oid->elements, p_oid->elements, p_oid->length );
      nt_ini_oid->length     = p_oid->length;
      p_gssfp->can_nametype  = nt_ini_oid;

   } else if ( p_target_oid==nt_acc_oid ) {

      memcpy( nt_acc_oid->elements, p_oid->elements, p_oid->length );
      nt_acc_oid->length     = p_oid->length;
      p_gssfp->can_nametype  = nt_acc_oid;

   } else {

      XVEB((V_BUG, "%s(): target_oid not recognized!\n", this_Call));
      return(1);

   }

   return(0);

} /* set_static_nt_oid() */

static char * empty_labels  [2] = {    "",    "" };
static char * visible_labels[2] = { "Ini", "Acc" }; 

/*
 * print_single_speed_line()
 *
 *
 */
static void
print_single_speed_line( char * p_call_name, struct xtime * p_xtime_ini, struct xtime * p_xtime_acc )
{
   struct xtime    * xt[3];
   char           ** label_base;
   float             min, max, avg;
   int               i;

   xt[0]      = p_xtime_ini;
   xt[1]      = NULL;
   label_base = empty_labels;
   xt[2]      = NULL;

   if ( p_xtime_ini!=p_xtime_acc ) {
      xt[1]      = p_xtime_acc;
      label_base = visible_labels;
   }

   for ( i=0 ; xt[i]!=NULL ; i++ ) {

      if ( xt[i]->count>0 ) {
	 min = xt[i]->min/(float)1000;
	 max = xt[i]->max/(float)1000;
	 avg = xt[i]->sum/(float)xt[i]->count/(float)1000;


	 XVEB((V_SHOW, "  %-15s %3.3s (%5lu calls) %5.1f  %6.1f  KByte/msec  min=%5.2f ms\n",
		       p_call_name, label_base[i], (Ulong) (xt[i]->count), avg, max, min ));

      } else {

	 XVEB((V_SHOW, "  %-15s %3.3s (0 calls)       no measured results\n", p_call_name, label_base[i] ));

      }

   }

   return;

} /* print_single_speed_line() */



/*
 * print_single_timing()
 *
 *
 */
static void
print_single_timing( char * p_call_name, struct xtime * p_xtime, int p_print_always )
{
   float    min, max, avg;

   if ( p_xtime->count>0 ) {
      min = p_xtime->min/(float)1000;
      max = p_xtime->max/(float)1000;
      avg = p_xtime->sum/(float)p_xtime->count/(float)1000;

      XVEB((V_SHOW, "  %-28s (%5lu calls)  %7.2f  %7.2f  %7.2f  ms\n",
		    p_call_name, (Ulong) (p_xtime->count), min, avg, max ));

   } else {

      if ( p_print_always!=FALSE ) {
	 XVEB((V_SHOW, "  %-28s (0 calls)       no measured results\n", p_call_name ));
      }

   }

   return;

} /* print_single_timing() */



char * no_measurements = "NO measurements available!";

/*
 * print_gssapi_statistics()
 *
 *
 */
void
print_gssapi_statistics( DLL_GSSFP_T  * p_gssfp_ini, DLL_GSSFP_T * p_gssfp_acc, int p_rc )
{
   struct xtime   ini_time;
   struct xtime   acc_time;
   char           tmpbuf[256];
   char         * msg;
   double         fract, ini_sum, acc_sum;
   Uint		  i;
   Uint		  nway = 1;
   char         * bits = "32";

   print_timing_statistics(verbose_level, p_gssfp_ini);
   if ( p_gssfp_ini!=p_gssfp_acc ) 
      print_timing_statistics(verbose_level, p_gssfp_acc);

   XVEB((V_SHOW, "\n\n"
	         "*********************************************************************\n"
		 "*                                                                   *\n" ));
   XVEB((V_SHOW, "*   GSStest Result Summary :                                        *\n"
                 "*                                                                   *\n"
	         "*********************************************************************\n"
		 "\n" ));

   if ( sizeof(int)==2 ) {
      bits = "16";
   } else if ( sizeof(void *)==4 ) {
      bits = "32";
   } else if ( sizeof(size_t)==8 ) {
      bits = "64";
   } else if ( sizeof(size_t)==16 ) {
      bits = "128";
   } else if ( sizeof(int)<4 ) {
      bits = "<32";
   } else if ( sizeof(size_t)>8 ) {
      bits = ">64";
   }
   XVEB((V_SHOW, "  GSSTEST Release   :  %s  (%s-bit)\n",
		 gsstest_version, bits   ));

   XVEB((V_SHOW, "         built on   :  %s\n\n", build_time        ));

   XVEB((V_SHOW, "  Command line:\n"));
   show_command_line( prog_argc, prog_argv );

   XVEB((V_SHOW, "\n" ));
   
   if ( p_gssfp_ini->snc_adapter_flag==FALSE ) {
      if ( p_gssfp_ini!=p_gssfp_acc ) {
	 XVEB((V_SHOW, "  GSS-API Library #1 (Initiator):  %s\n", p_gssfp_ini->dll_name ));
	 XVEB((V_SHOW, "  GSS-API Library #2 (Acceptor) :  %s\n", p_gssfp_acc->dll_name ));
      } else {
	 XVEB((V_SHOW, "  GSS-API Library   :  %s\n", p_gssfp_ini->dll_name ));
	 if ( options.sap_constraints!=FALSE ) {
	    verify_snc_builtin_info(p_gssfp_ini, "");
	    if ( p_gssfp_ini->snc_builtin_flag==FALSE ) {
	       XVEB((V_SHOW, "\nNOTICE: This GSS-API mechanism REQUIRES an external SNC-Adapter!\n"));
	    }
	 }
      }
   } else {
      if ( p_gssfp_ini != p_gssfp_acc ) {
	 XVEB((V_SHOW, "  SNC-Adapter #1 (Initiator) :  %s\n", p_gssfp_ini->dll_name ));
	 p_rc += print_sncadapter_info(p_gssfp_ini, "");
	 XVEB((V_SHOW, "  SNC-Adapter #2 (Acceptor)  :  %s\n", p_gssfp_acc->dll_name ));
	 p_rc += print_sncadapter_info(p_gssfp_acc, "");
      } else {
	 XVEB((V_SHOW, "  SNC-Adapter       :  %s\n", p_gssfp_ini->dll_name ));
	 p_rc += print_sncadapter_info(p_gssfp_ini, "");
      }
   }

   XVEB((V_SHOW, "\n" ));

   memset( &platform_info, 0, sizeof(platform_info) );
   sys_greeting("", &platform_info );

   XVEB((V_SEC, 1, "a"));
   if ( p_gssfp_ini->mech != GSS_C_NO_OID ) {
      print_oid( 1,        "Mechanism", p_gssfp_ini->mech );
      dump_oid_cstruct( 1, "         ", p_gssfp_ini->mech );
   } else {
      XVEB((V_SHOW, "  Huh? Mechanism OID not available!\n"));
   }

   XVEB((V_SEC, 1, "b"));
   if ( p_gssfp_ini->can_nametype!=GSS_C_NO_OID ) {
      print_oid( 1,        "Nametype ",  p_gssfp_ini->can_nametype );
      dump_oid_cstruct( 1, "         ",  p_gssfp_ini->can_nametype );
   } else {
      XVEB((V_SHOW, "  Huh? Nametype OID not available!\n"));
   }

   XVEB((V_SEC, 1, "c"));
   if ( p_gssfp_ini->initiator!=NULL ) {
      XVEB((V_SHOW, "  default    Initiator name: \"%.*s\"\n",
	   (int)(p_gssfp_ini->initiator_len), p_gssfp_ini->initiator   ));
   } else {
      XVEB((V_SHOW, "  default    Initiator name:  NOT AVAILABLE!\n"));
   }
   if ( p_gssfp_acc->acceptor!=NULL ) {
      XVEB((V_SHOW, "  given      Acceptor  name: \"%.*s\"\n",
	    (int)(p_gssfp_acc->acceptor_len),  p_gssfp_acc->acceptor    ));
   }
   if ( p_gssfp_acc->can_acc!=NULL ) {
      XVEB((V_SHOW, "  canonical  Acceptor  name: \"%.*s\"\n",
	    (int)(p_gssfp_acc->can_acc_len),   p_gssfp_acc->can_acc     ));
   }
   if ( p_gssfp_acc->def_acc!=NULL ) {
      XVEB((V_SHOW, "\n  (default)  Acceptor  name: \"%.*s\"\n",
	    (int)(p_gssfp_acc->def_acc_len),   p_gssfp_acc->def_acc     ));
   } else {
      XVEB((V_SHOW, "\n  (default)  Acceptor  name:  not available -- don't worry\n"));
   }

   /****************************************************/
   /* Statistics for Name-related gssapi calls         */
   /****************************************************/

   XVEB((V_SHOW, "\n----------\n"));
   XVEB((V_SEC, 2, "a"));

   if ( p_gssfp_ini->canonical_names_calls==FALSE ) {
      XVEB((V_SAP, "GSS-API v2 binary canonical names missing!\n"));
   }

   XVEB((V_SHOW, "Performance of names management calls             min      avg      max :\n"));
   if ( p_gssfp_ini == p_gssfp_acc ) {

      print_single_timing( "gss_import_name()",	      &(p_gssfp_ini->gtm[GSS_IMPORT_NAME]),	   TRUE );
      print_single_timing( "gss_display_name()",      &(p_gssfp_ini->gtm[GSS_DISPLAY_NAME]),	   TRUE );
      print_single_timing( "gss_export_name()",       &(p_gssfp_ini->gtm[GSS_EXPORT_NAME]),	   TRUE );
      print_single_timing( "gss_canonicalize_name()", &(p_gssfp_ini->gtm[GSS_CANONICALIZE_NAME]),  TRUE );
      print_single_timing( "gss_compare_name()",      &(p_gssfp_ini->gtm[GSS_COMPARE_NAME]),	   TRUE );
      print_single_timing( "gss_release_name()",      &(p_gssfp_ini->gtm[GSS_RELEASE_NAME]),	   TRUE );

   } else {

      print_single_timing( "gss_import_name()       Ini", &(p_gssfp_ini->gtm[GSS_IMPORT_NAME]),	   TRUE );
      print_single_timing( "gss_import_name()       Acc", &(p_gssfp_acc->gtm[GSS_IMPORT_NAME]),	   TRUE );
      print_single_timing( "gss_display_name()      Ini", &(p_gssfp_ini->gtm[GSS_DISPLAY_NAME]),   TRUE );
      print_single_timing( "gss_display_name()      Acc", &(p_gssfp_acc->gtm[GSS_DISPLAY_NAME]),   TRUE );
      print_single_timing( "gss_export_name()       Ini", &(p_gssfp_ini->gtm[GSS_EXPORT_NAME]),	   TRUE );
      print_single_timing( "gss_export_name()       Acc", &(p_gssfp_acc->gtm[GSS_EXPORT_NAME]),	   TRUE );
      print_single_timing( "gss_canonicalize_name() Ini", &(p_gssfp_ini->gtm[GSS_CANONICALIZE_NAME]),  TRUE );
      print_single_timing( "gss_canonicalize_name() Acc", &(p_gssfp_acc->gtm[GSS_CANONICALIZE_NAME]),  TRUE );
      print_single_timing( "gss_compare_name()      Ini", &(p_gssfp_ini->gtm[GSS_COMPARE_NAME]),   TRUE );
      print_single_timing( "gss_compare_name()      Acc", &(p_gssfp_acc->gtm[GSS_COMPARE_NAME]),   TRUE );
      print_single_timing( "gss_release_name()      Ini", &(p_gssfp_ini->gtm[GSS_RELEASE_NAME]),   TRUE );
      print_single_timing( "gss_release_name()      Acc", &(p_gssfp_acc->gtm[GSS_RELEASE_NAME]),   TRUE );
   }

   XVEB((V_SEC, 2, "b"));
   XVEB((V_SHOW, "Observed sizes of names:\n"));
   XVEB((V_SHOW, "  printable names                  [%3lu ..%3lu ]  bytes\n",
	    (Ulong)(p_gssfp_ini->prname_size_min), (Ulong)(p_gssfp_ini->prname_size_max) ));
   XVEB((V_SHOW, "  exported binary canonical names  [%3lu ..%3lu ]  bytes\n",
            (Ulong)(p_gssfp_ini->bcname_size_min), (Ulong)(p_gssfp_ini->bcname_size_max) ));

   XVEB((V_SHOW, "\n"));

   if ( (p_gssfp_ini->dspname_leading_wsp) > 0 ) {
      XVEB((V_SAP, "gss_display_name() returned %lu name(s) with leading whitespace!\n",
		   (Ulong)p_gssfp_ini->dspname_leading_wsp ));
   }
   if ( (p_gssfp_ini->dspname_trailing_wsp) > 0 ) {
      XVEB((V_SAP, "gss_display_name() returned %lu name(s) with trailing whitespace!\n",
		   (Ulong)p_gssfp_ini->dspname_trailing_wsp ));
   }
   if ( (p_gssfp_ini->dspname_linebreak) > 0 ) {
      XVEB((V_SAP, "gss_display_name() returned %lu name(s) containing line break(s)!\n",
		   (Ulong)p_gssfp_ini->dspname_linebreak ));
   }
   if ( (p_gssfp_ini->dspname_embedded_nul) > 0 ) {
      XVEB((V_SAP, "gss_display_name() returned %lu name(s) with embedded NUL characters!\n",
		   (Ulong)p_gssfp_ini->dspname_embedded_nul ));
   }
   if ( (p_gssfp_ini->dspname_trailing_nul) > 0 ) {
      XVEB((V_SAP, "gss_display_name() returned %lu name(s) with trailing NUL characters!\n",
		   (Ulong)p_gssfp_ini->dspname_trailing_nul ));
   }

   XVEB((V_SHOW, "Support of Hostbased Service Names:\n"));
   if ( (p_gssfp_ini->nt_list_has_hb_service)==FALSE ) {
      if ( (p_gssfp_ini->hb_service_looks_ok)==FALSE && (p_gssfp_ini->hb_service_alt_looks_ok)==FALSE ) {
	 XVEB((V_SHOW, "Mechanism apparently doesn't support Hostbased Service Names\n"));
      } else {
	 if ( (p_gssfp_ini->hb_service_looks_ok) ) {
	    XVEB((V_SHOW, "  Although mechanism doesn't return GSS_C_NT_HOSTBASED_SERVICE from\n"
			  "  gss_inquire_names_for_mech(), our sample hostbased service name is accepted.\n"));
	 } else if ( (p_gssfp_ini->hb_service_alt_looks_ok) || (p_gssfp_ini->nt_list_has_hb_service_alt) ) {
	    XVEB((V_SHOW, "  Mechanism recognizes GSS_C_NT_HOSTBASED_SERVICE_X but not GSS_C_HOSTBASED_SERVICE!\n"));
	 }
      }

   } else {

      if ( (p_gssfp_ini->hb_service_looks_ok) ) {
	 XVEB((V_SHOW, "  gss_inquire_names_for_mech() includes GSS_C_NT_HOSTBASED_SERVICE,\n"
		       "  and our sample hostbased service name is accepted.\n"));
      } else {
	 XVEB((V_SHOW, "  gss_inquire_names_for_mech() includes GSS_C_NT_HOSTBASED_SERVICE,\n"
		       "  but our sample hostbased service name is **rejected**.\n"));
      }

   }
   
   /****************************************************/
   /* Statistics for Credentials-related gssapi calls  */
   /****************************************************/

   XVEB((V_SHOW, "\n----------\n"));
   XVEB((V_SEC, 3, "a"));

   XVEB((V_SHOW, "Performance of credential management calls        min      avg      max :\n"));
   print_single_timing( "gss_acquire_cred() Ini", &(p_gssfp_ini->gtm[GSS_ACQUIRE_CRED_I]),   TRUE );
   print_single_timing( "gss_acquire_cred() Acc", &(p_gssfp_acc->gtm[GSS_ACQUIRE_CRED_A]),   TRUE );
   print_single_timing( "gss_inquire_cred() Ini", &(p_gssfp_ini->gtm[GSS_INQUIRE_CRED_I]),   TRUE );
   print_single_timing( "gss_inquire_cred() Acc", &(p_gssfp_acc->gtm[GSS_INQUIRE_CRED_A]),   TRUE );
   if ( p_gssfp_ini!=p_gssfp_acc ) {
      print_single_timing( "gss_release_cred() Ini", &(p_gssfp_ini->gtm[GSS_RELEASE_CRED]),  TRUE );
      print_single_timing( "gss_release_cred() Acc", &(p_gssfp_acc->gtm[GSS_RELEASE_CRED]),  TRUE );
   } else {
      print_single_timing( "gss_release_cred()",     &(p_gssfp_ini->gtm[GSS_RELEASE_CRED]),  TRUE );
   }

   XVEB((V_SEC, 3, "b"));
   XVEB((V_SHOW, "Observed Credentials lifetime(s):\n" ));

   if ( p_gssfp_ini->cred_lifetime_counter==0 ) {

      XVEB((V_SHOW, "  Credentials lifetime data not available! (Huh?)\n"));

   } else {

      if ( p_gssfp_ini->ctx_lifetime_inconsistent ) {

	 XVEB((V_SAP, "  Inconsistent credentials lifetime changes !\n"));

      } else {

	 print_lifetime( 1, "                                Elapsed real time ",
		         (OM_uint32)(p_gssfp_ini->ctx_lifetime_stat_end - p_gssfp_ini->ctx_lifetime_stat_begin) );

	 if ( (p_gssfp_ini->cred_lifetime_ini_final) == (p_gssfp_ini->cred_lifetime_ini_initial)
	      &&  (p_gssfp_ini->cred_lifetime_ini_growth)==0 ) {
	    /* initial and final cred lifetime are the same and no reverse aging was noticed */
	    print_lifetime( 1,    "  Initiator credentials lifetime constant at      ",
			          p_gssfp_ini->cred_lifetime_ini_final );
	 } else {

	    XVEB((V_SHOW, "\n"));

	    if ( (p_gssfp_ini->cred_lifetime_ini_growth) > 0 ) {
	       char ltime[128];

	       print_lifetime_only(ltime, (OM_uint32) p_gssfp_ini->cred_lifetime_ini_growth);
	       /* reverse aging was encountered on credential lifetime */
	       XVEB((V_SHOW, "  Reverse aging (- %s) encountered on initiator credentials!\n", ltime ));
	    } else {
	       print_lifetime( 1, "  Initiator credentials         lifetime decrease ",
			          (OM_uint32)(p_gssfp_ini->cred_lifetime_ini_initial - p_gssfp_ini->cred_lifetime_ini_final) );
	    }

	    print_lifetime( 1,	  "  Initiator credentials initial lifetime          ",
				  p_gssfp_ini->cred_lifetime_ini_initial);

	    print_lifetime( 1,    "  Initiator credentials final   lifetime          ",
			          p_gssfp_ini->cred_lifetime_ini_final );

	    XVEB((V_SHOW, "\n"));

	 }


	 if ( (p_gssfp_acc->cred_lifetime_acc_final) == (p_gssfp_acc->cred_lifetime_acc_initial)
	      &&  (p_gssfp_acc->cred_lifetime_acc_growth)==0 ) {

	    /* initial and final cred lifetime are the same and no reverse aging was noticed */
	    print_lifetime( 1,    "  Acceptor  credentials lifetime constant at      ",
			          p_gssfp_acc->cred_lifetime_acc_final );
	 } else {

	    if ( (p_gssfp_acc->cred_lifetime_acc_growth) > 0 ) {
	       char ltime[128];

	       print_lifetime_only(ltime, (OM_uint32) p_gssfp_acc->cred_lifetime_acc_growth);
	       /* reverse aging encountered on credential lifetime */
	       XVEB((V_SHOW, "  Reverse aging (- %s) encountered on acceptor  credentials!\n", ltime ));
	    } else {
	       print_lifetime( 1, "  Acceptor  credentials         lifetime decrease ",
			          (OM_uint32)(p_gssfp_acc->cred_lifetime_acc_initial - p_gssfp_acc->cred_lifetime_acc_final) );
	    }

	    print_lifetime( 1,    "  Acceptor  credentials initial lifetime          ",
			          p_gssfp_acc->cred_lifetime_acc_initial);

	    print_lifetime( 1,    "  Acceptor  credentials final   lifetime          ",
				  p_gssfp_acc->cred_lifetime_acc_final );

	 }

      }

   }


   /***************************************************************/
   /* Statistics for context-related and message protection calls */
   /***************************************************************/

   if ( p_gssfp_ini->context_counter==0 || p_gssfp_acc->context_counter==0 ) {
      
      XVEB((V_SHOW, "\n----------\nNo successful security context establishments -- test failure!\n"));
      
   } else {

      /**************************************************/
      /* Statistics for Security context establishment  */
      /**************************************************/

      XVEB((V_SHOW, "\n----------\nSecurity context establishment  (%lu contexts)\n",
		    (Ulong)p_gssfp_ini->context_counter ));

      XVEB((V_SHOW, "\n"));

      ini_time.count = acc_time.count = p_gssfp_ini->context_counter;

      for ( i=0 ; i<4 ; i++ ) {
	 if ( p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1 + i ].count == 0 ) {
	    nway =  2 * i - 1;
	    break;
	 }

	 if ( p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1 + i ].count == 0 ) {
	    nway =  2 * i;
	    break;
	 }
      }

      ini_time.min = p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1].min
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT2].min
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT3].min
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT4].min;
      acc_time.min = p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1].min
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT2].min
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT3].min
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT4].min;

      ini_time.max = p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1].max
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT2].max
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT3].max
		     + p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT4].max;
      acc_time.max = p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1].max
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT2].max
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT3].max
		     + p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT4].max;

      ini_sum  = acc_sum  = 0;

      for( i=0 ; i<4 ; i++ ) {
	 if ( p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1 + i].count==0 )
	    break;
	 fract    = (ini_time.count) / (double)(p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1 + i].count);
	 ini_sum += (p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1 + i].sum * fract);

	 if ( p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1 + i].count==0 )
	    break;
	 fract    = (acc_time.count) / (double)(p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1 + i].count);
	 acc_sum += (p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1 + i].sum * fract);
      }

      ini_time.sum   = (Ulong) ini_sum;
      acc_time.sum   = (Ulong) acc_sum;


      XVEB((V_SEC, 4, "a"));
      XVEB((V_SHOW, "Mechanism uses %u-way authentication\n", (Uint)nway ));


      /******************************************/
      /* security context attributes/flags      */
      /******************************************/

      XVEB((V_SEC, 4, "b"));
      if ( (p_gssfp_ini->ctx_flags_always & SNC_REQUIRED_FLAGS) != SNC_REQUIRED_FLAGS ) {
	 OM_uint32  flags = (p_gssfp_ini->ctx_flags_always & SNC_REQUIRED_FLAGS) ^ SNC_REQUIRED_FLAGS;

	 XVEB((V_SAP, ""));
	 print_ctx_flags( (options.sap_constraints!=0), NULL, " missing context flag(s)", &flags );
      }
      /* ## MISSING: Distinguish Acceptor and Initiator side for 2-library operation */
      XVEB((V_SHOW, "Security Context Attribute results:\n"));
      print_ctx_flags( 2, NULL, "     requested ", &(p_gssfp_ini->ctx_flags_requested) );
      print_ctx_flags( 2, NULL, "     provided  ", &(p_gssfp_ini->ctx_flags_always)    );

      if ( p_gssfp_ini->ctx_flags_donated!=0 ) {
	 print_ctx_flags( 2, NULL, "     donated   ",   &(p_gssfp_ini->ctx_flags_donated) );
      }
      if ( p_gssfp_ini->ctx_flags_denied!=0 ) {
	 print_ctx_flags( 2, NULL, "     denied    ", &(p_gssfp_ini->ctx_flags_denied) );
      }
      if ( p_gssfp_ini->ctx_flags_inconsistent!=0 ) {
	 print_ctx_flags( 2, NULL, "   inconsistent", &(p_gssfp_ini->ctx_flags_inconsistent) );
      }


      /*******************************************/
      /* context establishment performance       */
      /*******************************************/

      XVEB((V_SHOW, "\nPerformance of context establishment calls        min      avg      max :\n"));
      print_single_timing( "gss_init_sec_context()   #1", &(p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT1]),   FALSE );
      print_single_timing( "gss_init_sec_context()   #2", &(p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT2]),   FALSE );
      print_single_timing( "gss_init_sec_context()   #3", &(p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT3]),   FALSE );
      print_single_timing( "gss_init_sec_context()   #4", &(p_gssfp_ini->gtm[GSS_INIT_SEC_CONTEXT4]),   FALSE );
      print_single_timing( "gss_accept_sec_context() #1", &(p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT1]), FALSE );
      print_single_timing( "gss_accept_sec_context() #2", &(p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT2]), FALSE );
      print_single_timing( "gss_accept_sec_context() #3", &(p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT3]), FALSE );
      print_single_timing( "gss_accept_sec_context() #4", &(p_gssfp_acc->gtm[GSS_ACCEPT_SEC_CONTEXT4]), FALSE );

      XVEB((V_SEC, 4, "c"));

      if ( ini_time.min>SNC_MAX_GUI_ESTAB_TIME ) {
	 XVEB((V_SAP, "initiator establishment time exceeds %7.2f ms!\n",
	       (float)(SNC_MAX_GUI_ESTAB_TIME/1000) ));
      } else if ( options.sap_constraints!=FALSE
	          &&  ini_time.min>SNC_MAX_ESTABLISHMENT_TIME ) {
	 XVEB((V_SHOW, "Performance WARNING: initiator establishment time exceeds %7.2f ms!\n",
	       (float)(SNC_MAX_ESTABLISHMENT_TIME/1000) ));
	 gui_only_flag = TRUE;

      } 

      if ( acc_time.min>=SNC_MAX_GUI_ESTAB_TIME ) {
	 XVEB((V_SAP, "acceptor  establishment time exceeds %7.2f ms!\n",
	       (float)(SNC_MAX_GUI_ESTAB_TIME/1000) ));
      } else if ( options.sap_constraints!=FALSE
		  &&  acc_time.min>SNC_MAX_ESTABLISHMENT_TIME ) {
	 XVEB((V_SHOW, "Performance WARNING: acceptor  establishment time exceeds %7.2f ms!\n",
	       (float)(SNC_MAX_ESTABLISHMENT_TIME/1000) ));
	 gui_only_flag = TRUE;

      }

      XVEB((V_SHOW, "Total context establishment overhead              min      avg      max :\n"));
      print_single_timing( "gss_init_sec_context()",   &ini_time, TRUE );
      print_single_timing( "gss_accept_sec_context()", &acc_time, TRUE );
      if ( p_gssfp_ini != p_gssfp_acc ) {
	 print_single_timing( "gss_delete_sec_context() Ini", &(p_gssfp_ini->gtm[GSS_DELETE_SEC_CONTEXT]), TRUE );
	 print_single_timing( "gss_delete_sec_context() Acc", &(p_gssfp_acc->gtm[GSS_DELETE_SEC_CONTEXT]), TRUE );
	 print_single_timing( "gss_inquire_context()    Ini", &(p_gssfp_ini->gtm[GSS_INQUIRE_CONTEXT]), TRUE );
	 print_single_timing( "gss_inquire_context()    Acc", &(p_gssfp_acc->gtm[GSS_INQUIRE_CONTEXT]), TRUE );
      } else {
	 print_single_timing( "gss_delete_sec_context()", &(p_gssfp_ini->gtm[GSS_DELETE_SEC_CONTEXT]), TRUE );
	 print_single_timing( "gss_inquire_context()",    &(p_gssfp_ini->gtm[GSS_INQUIRE_CONTEXT]), TRUE );
      }

      XVEB((V_SHOW, "\n"));


      /*********************************************/
      /* context lifetime                          */
      /*********************************************/

      XVEB((V_SEC, 4, "d"));
      XVEB((V_SHOW, "Observed initial lifetimes for established security contexts:\n"));

      /* ## MISSING: Distinguish Initiator and Acceptor for 2-library operation       */
      /*             Haven't verified whether the flags get always set for Initiator  */
      /*             -- but we're only looking at the initiators values here          */
      if ( p_gssfp_ini->ctx_lifetime_indefinite == p_gssfp_ini->ctx_lifetime_counter ) {

	 XVEB((V_SHOW, "  All security contexts were established with lifetime \"Indefinite\".\n"));

      } else {

	 if ( p_gssfp_ini->ctx_lifetime_inconsistent>0 ) {
	    XVEB((V_SAP, "Context lifetime Ini,Acc inconsistent on %lu contexts!\n",
			 (Ulong)(p_gssfp_ini->ctx_lifetime_inconsistent) ));
	 }
	 if ( p_gssfp_ini->cred_ctx_lifetime_ini_mismatch > 0 ) {
	    XVEB((V_SAP, "Initiator context and credentials lifetime mismatch (%lu)!\n",
			 (Ulong)(p_gssfp_ini->cred_ctx_lifetime_ini_mismatch) ));
	 }
	 if ( p_gssfp_ini->cred_ctx_lifetime_acc_mismatch > 0 ) {
	    XVEB((V_SAP, "Acceptor  context and credentials lifetime mismatch (%lu)!\n",
			 (Ulong)(p_gssfp_ini->cred_ctx_lifetime_acc_mismatch) ));
	 }
	 if ( p_gssfp_ini->ctx_lifetime_skew > 0 ) {
	    XVEB((V_SAP, "Context lifetime skew Ini,Acc on %lu contexts!\n",
			 (Ulong)(p_gssfp_ini->ctx_lifetime_skew) ));
	 } 

	 print_lifetime( 1, "\n                             Elapsed real time ",
		         (OM_uint32)(p_gssfp_ini->ctx_lifetime_stat_end - p_gssfp_ini->ctx_lifetime_stat_begin) );



	 if ( (p_gssfp_ini->ctx_lifetime_ini_max) == (p_gssfp_ini->ctx_lifetime_ini_min) ) {

	    print_lifetime( 1,    "  Initiator context lifetimes constant at      ",
				  p_gssfp_ini->ctx_lifetime_ini_max );
	 } else {

	    XVEB((V_SHOW, "\n"));

	    if ( (p_gssfp_ini->ctx_lifetime_ini_growth) > 0
		 && (p_gssfp_ini->ctx_lifetime_ini_max - p_gssfp_ini->ctx_lifetime_ini_min) > 3 ) {
	       char ltime[128];

	       print_lifetime_only(ltime, (OM_uint32) p_gssfp_ini->ctx_lifetime_ini_growth);
	       /* reverse aging was encountered on security context lifetime */
	       XVEB((V_SHOW, "  Reverse aging (- %s) encountered on initiator contexts!\n", ltime ));
	    } else if ( (p_gssfp_ini->ctx_lifetime_ini_growth)==0 ) {
	       print_lifetime( 1, "  Initiator context         lifetimes decrease ",
			          (OM_uint32)(p_gssfp_ini->ctx_lifetime_ini_initial - p_gssfp_ini->ctx_lifetime_ini_final) );
	    }

	    print_lifetime( 1,	  "  Initiator context initial lifetime           ",
				  p_gssfp_ini->ctx_lifetime_ini_initial);

	    print_lifetime( 1,    "  Initiator context final   lifetime           ",
			          p_gssfp_ini->ctx_lifetime_ini_final );

	    XVEB((V_SHOW, "\n"));

	 }


	 if ( (p_gssfp_acc->ctx_lifetime_acc_max) == (p_gssfp_acc->ctx_lifetime_acc_min) ) {

	    print_lifetime( 1,    "  Acceptor  context lifetimes constant at      ",
				  p_gssfp_acc->ctx_lifetime_acc_max );
	 } else {

	    if ( (p_gssfp_acc->ctx_lifetime_acc_growth) > 0
	         && (p_gssfp_acc->ctx_lifetime_acc_max)-(p_gssfp_acc->ctx_lifetime_acc_min) > 3 ) {
	       char ltime[128];

	       print_lifetime_only(ltime, (OM_uint32) p_gssfp_acc->ctx_lifetime_acc_growth);
	       /* reverse aging encountered on context lifetime */
	       XVEB((V_SHOW, "  Reverse aging (- %s) encountered on acceptor  contexts!\n", ltime ));
	    } else if ( (p_gssfp_acc->ctx_lifetime_acc_growth)==0 ) {
	       print_lifetime( 1, "  Acceptor  context         lifetimes decrease ",
			          (OM_uint32)(p_gssfp_acc->ctx_lifetime_acc_initial - p_gssfp_acc->ctx_lifetime_acc_final) );
	    }

	    print_lifetime( 1,    "  Acceptor  context initial lifetime           ",
			          p_gssfp_acc->ctx_lifetime_acc_initial);

	    print_lifetime( 1,    "  Acceptor  context final   lifetime           ",
				  p_gssfp_acc->ctx_lifetime_acc_final );

	 }

      }


      /*********************************************/
      /* context establishment token sizes         */
      /*********************************************/

      XVEB((V_SEC, 4, "e"));
      if ( p_gssfp_ini->ctx_ini_token_max > SNC_MAX_CONTEXT_TOKEN ) {
	 XVEB((V_SAP, "initiator token exceeds %u bytes!\n",
	       (Uint)SNC_MAX_CONTEXT_TOKEN));
      }
      if ( p_gssfp_acc->ctx_acc_token_max > SNC_MAX_CONTEXT_TOKEN ) {
	 XVEB((V_SAP, "acceptor  token exceeds %u bytes!\n",
	       (Uint)SNC_MAX_CONTEXT_TOKEN));
      }

      msg = no_measurements;
      if ( p_gssfp_ini->ctx_ini_token_min > 0 ) {
	 sprintf(tmpbuf, "[ %3lu .. %3lu ]  bytes",
		       (Ulong)p_gssfp_ini->ctx_ini_token_min,
		       (Ulong)p_gssfp_ini->ctx_ini_token_max );
	 msg = &(tmpbuf[0]);
      }
      XVEB((V_SHOW, "Observed token sizes for    gss_init_sec_context():  %s\n",
	    msg ));

      msg = no_measurements;
      if ( p_gssfp_acc->ctx_acc_token_min > 0 ) {
	 sprintf(tmpbuf, "[ %3lu .. %3lu ]  bytes",
	               (Ulong)p_gssfp_acc->ctx_acc_token_min,
		       (Ulong)p_gssfp_acc->ctx_acc_token_max );
	 msg = &(tmpbuf[0]);
      }
      XVEB((V_SHOW, "Observed token sizes for  gss_accept_sec_context():  %s\n",
	    msg ));


      XVEB((V_SHOW, "\n"));
      
      
      /********************************************/
      /* Statistics for Security context transfer */
      /********************************************/

      XVEB((V_SHOW, "\n----------\n"));
      XVEB((V_SHOW, "Security context transfer: %lu context transfers, %lu cross-process\n",
		    (Ulong)p_gssfp_ini->context_xferred,
		    (Ulong)p_gssfp_ini->context_xferred_child ));

      XVEB((V_SEC, 5, "a"));

      if ( p_gssfp_ini->context_xferable==0 && options.force_xfer==FALSE ) {

	 XVEB((V_SAP, "Security context transfer facilities required!\n\n"));
	 XVEB((V_SHOW, "Security context transfer NOT available!\n" ));

      } else if ( p_gssfp_ini->context_xferred>0 ) {

	 if ( (p_gssfp_ini->gtm[GSS_EXPORT_SEC_CONTEXT_I].min)>SNC_MAX_CTX_XFER_TIME ) {
	    XVEB((V_SAP, "Initiator context export time exceeds %7.2f ms!\n\n",
			 (float)(SNC_MAX_CTX_XFER_TIME * 0.001) ));
	 }
	 if ( (p_gssfp_acc->gtm[GSS_EXPORT_SEC_CONTEXT_A].min)>SNC_MAX_CTX_XFER_TIME ) {
	    XVEB((V_SAP, "Acceptor  context export time exceeds %7.2f ms!\n\n",
			 (float)(SNC_MAX_CTX_XFER_TIME * 0.001) ));
	 }

	 if ( (p_gssfp_ini->gtm[GSS_IMPORT_SEC_CONTEXT_I].min)>SNC_MAX_CTX_XFER_TIME ) {
	    XVEB((V_SAP, "Initiator context import time exceeds %7.2f ms!\n\n",
			 (float)(SNC_MAX_CTX_XFER_TIME * 0.001) ));
	 }
	 if ( (p_gssfp_acc->gtm[GSS_IMPORT_SEC_CONTEXT_A].min)>SNC_MAX_CTX_XFER_TIME ) {
	    XVEB((V_SAP, "Acceptor  context import time exceeds %7.2f ms!\n\n",
			 (float)(SNC_MAX_CTX_XFER_TIME * 0.001) ));
	 }

	 XVEB((V_SHOW, "Performance of security context transfer          min      avg      max :\n"));
	 print_single_timing( "gss_export_sec_context() Ini", &(p_gssfp_ini->gtm[GSS_EXPORT_SEC_CONTEXT_I]), TRUE );
	 print_single_timing( "gss_export_sec_context() Acc", &(p_gssfp_acc->gtm[GSS_EXPORT_SEC_CONTEXT_A]), TRUE );
	 print_single_timing( "gss_import_sec_context() Ini", &(p_gssfp_ini->gtm[GSS_IMPORT_SEC_CONTEXT_I]), TRUE );
	 print_single_timing( "gss_import_sec_context() Acc", &(p_gssfp_acc->gtm[GSS_IMPORT_SEC_CONTEXT_A]), TRUE );

	 if ( p_gssfp_ini->context_xferable==0 ) {
	    XVEB((V_SHOW, "  GSSAPI mechanism failed to indicate GSS_C_TRANS_FLAG attribute!\n"));
	 }

	 XVEB((V_SHOW, "\n"));

	 XVEB((V_SEC, 5, "b"));

	 if ( (p_gssfp_ini->ctx_exported_max[CTX_INITIATOR])>SNC_MAX_EXPORTED_CTX_TOKEN ) {
	    XVEB((V_SAP, "exported initiator context token exceeds %u bytes!\n",
			 (Uint)SNC_MAX_EXPORTED_CTX_TOKEN ));
	 }

	 if ( (p_gssfp_acc->ctx_exported_max[CTX_ACCEPTOR])>SNC_MAX_EXPORTED_CTX_TOKEN ) {
	    XVEB((V_SAP, "exported acceptor  context token exceeds %u bytes!\n",
			 (Uint)SNC_MAX_EXPORTED_CTX_TOKEN ));
	 }

	 msg = no_measurements;
	 if ( p_gssfp_ini->ctx_exported_count[CTX_INITIATOR] > 0 ) {
	    sprintf(tmpbuf, "[ %3lu .. %3lu ]  bytes  (%4lu calls)",
			(Ulong)p_gssfp_ini->ctx_exported_min[CTX_INITIATOR],
			(Ulong)p_gssfp_ini->ctx_exported_max[CTX_INITIATOR],
			(Ulong)p_gssfp_ini->ctx_exported_count[CTX_INITIATOR]);
	    msg = &(tmpbuf[0]);
	 }
	 XVEB((V_SHOW, "Interprocess token sizes for Initiator:  %s\n", msg));

	 msg = no_measurements;
	 if ( p_gssfp_acc->ctx_exported_count[CTX_ACCEPTOR] > 0 ) {
	    sprintf(tmpbuf, "[ %3lu .. %3lu ]  bytes  (%4lu calls)\n",
			(Ulong)p_gssfp_acc->ctx_exported_min[CTX_ACCEPTOR],
			(Ulong)p_gssfp_acc->ctx_exported_max[CTX_ACCEPTOR],
			(Ulong)p_gssfp_acc->ctx_exported_count[CTX_ACCEPTOR]);
	    msg = &(tmpbuf[0]);
	 }
	 XVEB((V_SHOW, "Interprocess token sizes for  Acceptor:  %s\n", msg));

      } else {

	 XVEB((V_SHOW, " none performed\n"));

      }

      XVEB((V_SHOW, "\n"));

      /**********************************************/
      /* Statistics for Message Protection Services */
      /**********************************************/

      XVEB((V_SHOW, "\n----------\nMessage Protection Services: "));

      XVEB((V_SEC, 6, "a"));

      if ( p_gssfp_ini->context_integ >= p_gssfp_ini->context_counter
	   &&  p_gssfp_ini->context_conf >= p_gssfp_ini->context_counter
	   &&  p_gssfp_ini->conf_failure == FALSE ) {

	 p_gssfp_ini->snc_qop = SNC_QOP_PRIVACY;
	 XVEB((V_SHOW, "Confidentiality and Integrity\n"));

      } else if ( p_gssfp_ini->context_integ >= p_gssfp_ini->context_counter ) {

	 p_gssfp_ini->snc_qop = SNC_QOP_INTEGRITY;
	 XVEB((V_SHOW, "Integrity ONLY\n"));

      } else {

	 p_gssfp_ini->snc_qop = SNC_QOP_OPEN;
	 XVEB((V_SHOW, "NOT%s available!\n",
	    ( (p_gssfp_ini->context_integ)==0 && (p_gssfp_ini->context_conf)==0 ) ? "" : " reliably" ));

      }

      XVEB((V_SEC, 6, "b"));
      XVEB((V_SHOW, "Performance of per-message calls                  min      avg      max :\n"));
      if ( p_gssfp_ini!=p_gssfp_acc ) {
	 print_single_timing( "gss_context_time()    Ini", &(p_gssfp_ini->gtm[GSS_CONTEXT_TIME]),    TRUE );
	 print_single_timing( "gss_context_time()    Acc", &(p_gssfp_acc->gtm[GSS_CONTEXT_TIME]),    TRUE );
	 print_single_timing( "gss_wrap_size_limit() Ini", &(p_gssfp_ini->gtm[GSS_WRAP_SIZE_LIMIT]), FALSE );
	 print_single_timing( "gss_wrap_size_limit() Acc", &(p_gssfp_acc->gtm[GSS_WRAP_SIZE_LIMIT]), FALSE );
      } else {
	 print_single_timing( "gss_context_time()",    &(p_gssfp_ini->gtm[GSS_CONTEXT_TIME]),    TRUE );
	 print_single_timing( "gss_wrap_size_limit()", &(p_gssfp_ini->gtm[GSS_WRAP_SIZE_LIMIT]), FALSE );
      }

      if ( p_gssfp_ini->gtm[GSS_CONTEXT_TIME].min > SNC_MAX_GSS_CONTEXT_TIME ) {
	 XVEB((V_SAP, "gss_context_time() exceeds %7.2f ms!\n\n",
		      (float) (SNC_MAX_GSS_CONTEXT_TIME * 0.001) ));
      }

      if ( p_gssfp_ini->context_integ!=0 ) {
         XVEB((V_SEC, 6, "c"));
	 /* In case integrity protection was available on at least some contexts */
	 /* then we may actually have some performance data available            */
	 XVEB((V_SHOW, "Message protection throughput         avg     max :\n"));
	 print_single_speed_line( "gss_getmic()",     &(p_gssfp_ini->getmic_speed),    &(p_gssfp_acc->getmic_speed)	);
	 if ( (p_gssfp_ini->getmic_speed).min > SNC_MAX_MIC_LATENCY ) {
	    XVEB((V_SAP, "gss_getmic()     latency exceeds %7.2f ms!\n\n",
			 (float) (SNC_MAX_MIC_LATENCY * 0.001) ));
	 }
	 print_single_speed_line( "gss_verifymic()",  &(p_gssfp_ini->verifymic_speed), &(p_gssfp_acc->verifymic_speed)	);
	 if ( (p_gssfp_ini->verifymic_speed).min > SNC_MAX_MIC_LATENCY ) {
	    XVEB((V_SAP, "gss_verifymic()  latency exceeds %7.2f ms!\n\n",
			 (float) (SNC_MAX_MIC_LATENCY * 0.001) ));
	 }
	 print_single_speed_line( "gss_wrap(mic)",    &(p_gssfp_ini->wmic_speed),      &(p_gssfp_acc->wmic_speed)	);
	 if ( (p_gssfp_ini->wmic_speed).min > SNC_MAX_WMIC_LATENCY ) {
	    XVEB((V_SAP, "gss_wrap(mic)    latency exceeds %7.2f ms!\n\n",
			    (float) (SNC_MAX_WMIC_LATENCY * 0.001) ));
	 }
	 print_single_speed_line( "gss_unwrap(mic)",  &(p_gssfp_ini->unwmic_speed),    &(p_gssfp_acc->unwmic_speed)	);
	 if ( (p_gssfp_ini->unwmic_speed).min > SNC_MAX_WMIC_LATENCY ) {
	    XVEB((V_SAP, "gss_unwrap(mic)  latency exceeds %7.2f ms!\n\n",
			 (float) (SNC_MAX_WMIC_LATENCY * 0.001) ));
	 }
	 if ( p_gssfp_ini->context_conf!=0 ) {
	    print_single_speed_line( "gss_wrap(conf)",   &(p_gssfp_ini->wconf_speed),  &(p_gssfp_acc->wconf_speed)	);
	    if ( (p_gssfp_ini->wconf_speed).min > SNC_MAX_WCONF_LATENCY ) {
	       XVEB((V_SAP, "gss_unwrap(conf) latency exceeds %7.2f ms!\n\n",
			    (float) (SNC_MAX_WCONF_LATENCY * 0.001) ));
	    }
	    print_single_speed_line( "gss_unwrap(conf)", &(p_gssfp_ini->unwconf_speed),&(p_gssfp_acc->unwconf_speed)	);
	    if ( (p_gssfp_ini->unwconf_speed).min > SNC_MAX_WCONF_LATENCY ) {
	       XVEB((V_SAP, "gss_unwrap(conf) latency exceeds %7.2f ms!\n\n",
			    (float) (SNC_MAX_WCONF_LATENCY * 0.001) ));
	    }
	 }

	 XVEB((V_SHOW, "\n"));

         XVEB((V_SEC, 6, "d"));
	 if ( p_gssfp_ini != p_gssfp_acc ) {
	    XVEB((V_SHOW, "Initiator:\n"));
	 }

	 msg = no_measurements;
	 if ( p_gssfp_ini->mic_size_min > 0 ) {
	    sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
		    (unsigned long)p_gssfp_ini->mic_size_min,
		    (unsigned long)p_gssfp_ini->mic_size_max );
	    msg = &(tmpbuf[0]);
	    if ( (p_gssfp_ini->mic_size_max) > SNC_MAX_MIC_TOKEN ) {
	       XVEB((V_SAP, "MIC token size exceeds %lu bytes !\n",
			    (Ulong) SNC_MAX_MIC_TOKEN ));
	    }
	 }
	 XVEB((V_SHOW, "Token sizes for           gss_getmic()  :  %s\n",msg));

	 msg = no_measurements;
	 if ( p_gssfp_ini->wmic_size_min > 0 ) {
	    sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
			  (Ulong)p_gssfp_ini->wmic_size_min,
			  (Ulong)p_gssfp_ini->wmic_size_max );
	    msg = &(tmpbuf[0]);
	    if ( p_gssfp_ini->wmic_size_max > SNC_MAX_WRAP_INCREASE ) {
	       XVEB((V_SAP, "gss_wrap(conf=FALSE) token size exceeds %lu bytes !\n",
			    (Ulong) SNC_MAX_WRAP_INCREASE ));
	    }
	 }
	 XVEB((V_SHOW, "Message size increase for gss_wrap(mic) :  %s\n",msg));

	 if ( p_gssfp_ini->context_conf!=0 ) {
	    msg = no_measurements;
	    if ( p_gssfp_ini->wconf_size_min > 0 ) {
	       sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
			     (Ulong)p_gssfp_ini->wconf_size_min,
			     (Ulong)p_gssfp_ini->wconf_size_max );
	       msg = &(tmpbuf[0]);
	       if ( p_gssfp_ini->wconf_size_max > SNC_MAX_WRAP_INCREASE ) {
		  XVEB((V_SAP, "gss_wrap(conf=TRUE) token size exceeds %lu bytes !\n",
			     (Ulong) SNC_MAX_WRAP_INCREASE ));
	       }
	    }
	    XVEB((V_SHOW, "Message size increase for gss_wrap(conf):  %s\n",msg));
	 }

	 if ( p_gssfp_ini!=p_gssfp_acc ) {
	    XVEB((V_SHOW, "\nAcceptor:\n"));
	    msg = no_measurements;
	    if ( p_gssfp_acc->mic_size_min > 0 ) {
	       sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
			     (Ulong)p_gssfp_acc->mic_size_min,
			     (Ulong)p_gssfp_acc->mic_size_max );
	       msg = &(tmpbuf[0]);
	       if ( (p_gssfp_acc->mic_size_max) > SNC_MAX_MIC_TOKEN ) {
		  XVEB((V_SAP, "MIC token size exceeds %lu bytes !\n",
			     (Ulong) SNC_MAX_MIC_TOKEN ));
	       }
	    }
	    XVEB((V_SHOW, "Token sizes for           gss_getmic()  :  %s\n",msg));

	    msg = no_measurements;
	    if ( p_gssfp_acc->wmic_size_min > 0 ) {
	       sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
			     (Ulong)p_gssfp_acc->wmic_size_min,
			     (Ulong)p_gssfp_acc->wmic_size_max );
	       msg = &(tmpbuf[0]);
	       if ( p_gssfp_acc->wmic_size_max > SNC_MAX_WRAP_INCREASE ) {
		  XVEB((V_SAP, "gss_wrap(conf=FALSE) token size exceeds %lu bytes !\n",
			     (Ulong) SNC_MAX_WRAP_INCREASE ));
	       }
	    }
	    XVEB((V_SHOW, "Message size increase for gss_wrap(mic) :  %s\n",msg));

	    if ( p_gssfp_acc->context_conf!=0 ) {
	       msg = no_measurements;
	       if ( p_gssfp_acc->wconf_size_min > 0 ) {
		  sprintf(tmpbuf, "[%3lu ..%3lu ]  bytes",
				(Ulong)p_gssfp_acc->wconf_size_min,
				(Ulong)p_gssfp_acc->wconf_size_max );
		  msg = &(tmpbuf[0]);
		  if ( p_gssfp_acc->wconf_size_max > SNC_MAX_WRAP_INCREASE ) {
		     XVEB((V_SAP, "gss_wrap(conf=TRUE) token size exceeds %lu bytes !\n",
				(Ulong) SNC_MAX_WRAP_INCREASE ));
		  }
	       }
	       XVEB((V_SHOW, "Message size increase for gss_wrap(conf):  %s\n",msg));
	    }

	 }

	 /*********************************************************************/
	 /* list any non-default QOP values that have beenn returned from the */
	 /* message unprotection calls gss_verify_mic() and gss_unwrap()      */
	 /*********************************************************************/
	 if ( p_gssfp_ini->mic_qop[0]!=0  ||  p_gssfp_ini->wmic_qop[0]!=0  ||  p_gssfp_ini->wconf_qop[0]!=0
	      || p_gssfp_acc->mic_qop[0]!=0  ||  p_gssfp_acc->wmic_qop[0]!=0  ||  p_gssfp_acc->wconf_qop[0]!=0 ) {
	    XVEB((V_SEC, 6, "e"));
	 }
	    
	 if ( p_gssfp_ini->mic_qop[0]!=0 ) {
	    XVEB((V_SHOW, "   non-default QOP return values for gss_getmic():\n"));
	    for ( i=0 ; i<MAX_QOP_VALUES && p_gssfp_ini->mic_qop[i]!=0 ; i++ ) {
	       XVEB((V_SHOW, "        0x%08lx\n", (Ulong)p_gssfp_ini->mic_qop[i] ));
	    }
	 }

	 if ( p_gssfp_ini->wmic_qop[0]!=0 ) {
	    XVEB((V_SHOW, "   non-default QOP return values for gss_wrap(mic):\n"));
	    for ( i=0 ; i<MAX_QOP_VALUES && p_gssfp_ini->wmic_qop[i]!=0 ; i++ ) {
	       XVEB((V_SHOW, "        0x%08lx\n", (Ulong)p_gssfp_ini->wmic_qop[i] ));
	    }
	 }

	 if ( p_gssfp_ini->wconf_qop[0]!=0 ) {
	    XVEB((V_SHOW, "   non-default QOP return values for gss_wrap(conf):\n"));
	    for ( i=0 ; i<MAX_QOP_VALUES && p_gssfp_ini->wconf_qop[i]!=0 ; i++ ) {
	       XVEB((V_SHOW, "        0x%08lx\n", (Ulong)p_gssfp_ini->wconf_qop[i] ));
	    }
	 }

      }

      XVEB((V_SHOW, "\n"));

   } /* p_gssfp->context_counter > 0 */

   XVEB((V_SHOW, "----------\n"));

   /*******************************************************/
   /* Completeness: Performance Statistics for Misc calls */
   /*******************************************************/

   XVEB((V_SEC, 7, "a"));
   XVEB((V_SHOW, "Performance of remaining GSS-API calls            min      avg      max :\n"));
   if ( p_gssfp_ini==p_gssfp_acc ) {

      print_single_timing( "gss_display_status()",  &(p_gssfp_ini->gtm[GSS_DISPLAY_STATUS]),   TRUE );
      print_single_timing( "gss_release_buffer()",  &(p_gssfp_ini->gtm[GSS_RELEASE_BUFFER]),   TRUE );
      print_single_timing( "gss_release_oid_set()", &(p_gssfp_ini->gtm[GSS_RELEASE_OID_SET]),  TRUE );
      print_single_timing( "gss_indicate_mechs()",  &(p_gssfp_ini->gtm[GSS_INDICATE_MECHS]),   TRUE );

   } else {

      print_single_timing( "gss_display_status()  Ini", &(p_gssfp_ini->gtm[GSS_DISPLAY_STATUS]),   TRUE );
      print_single_timing( "gss_display_status()  Acc", &(p_gssfp_acc->gtm[GSS_DISPLAY_STATUS]),   TRUE );
      print_single_timing( "gss_release_buffer()  Ini", &(p_gssfp_ini->gtm[GSS_RELEASE_BUFFER]),   TRUE );
      print_single_timing( "gss_release_buffer()  Acc", &(p_gssfp_acc->gtm[GSS_RELEASE_BUFFER]),   TRUE );
      print_single_timing( "gss_release_oid_set() Ini", &(p_gssfp_ini->gtm[GSS_RELEASE_OID_SET]),  TRUE );
      print_single_timing( "gss_release_oid_set() Acc", &(p_gssfp_acc->gtm[GSS_RELEASE_OID_SET]),  TRUE );
      print_single_timing( "gss_indicate_mechs()  Ini", &(p_gssfp_ini->gtm[GSS_INDICATE_MECHS]),   TRUE );
      print_single_timing( "gss_indicate_mechs()  Acc", &(p_gssfp_acc->gtm[GSS_INDICATE_MECHS]),   TRUE );

   }

   XVEB((V_SHOW, "\n----------\nDisplaying of status information via gss_display_status():\n"));

   XVEB((V_SEC, 7, "b"));
   if ( (p_gssfp_ini->dspstat_linebreak)>0 ) {
      XVEB((V_SAP, "gss_display_status() emits messages with embedded linebreaks!\n"));
   }
   if ( (p_gssfp_ini->dspstat_embedded_nul)>0 ) {
      XVEB((V_SAP, "gss_display_status() emits messages with embedded NUL characters!\n"));
   }
   if ( (p_gssfp_ini->dspstat_trailing_nul)>0 ) {
      XVEB((V_SAP, "gss_display_status() emits messages with trailing NUL characters!\n"));
   }
   if ( (p_gssfp_ini->dspstat_one_max_lines)>1 ) {
      XVEB((V_SAP, "gss_display_status() returns multilines for singular status codes!\n"));
   }
   if ( (p_gssfp_ini->dspstat_one_counter)>0 ) {
      XVEB((V_SHOW, "  gss_display_status(major) output message size [%3lu ..%3lu ] avg=%3lu chars\n",
		    (Ulong)(p_gssfp_ini->dspstat_one_min_linelen),
		    (Ulong)(p_gssfp_ini->dspstat_one_max_linelen),
		    (Ulong)((p_gssfp_ini->dspstat_one_sum_linelen)/(p_gssfp_ini->dspstat_one_counter)) ));

   }

   XVEB((V_SHOW, "\n"));

   show_snc_limits( "" );

   return;

} /* print_gssapi_statistics() */



/*
 * show_command_line()
 *
 *
 */
void
show_command_line( int argc, char **argv )
{
   int i;

   for ( i=0 ; i<argc ; i++ ) {
      XVEB((V_SHOW, "    argv[%2d] = \"%.250s\"\n", (int)i, argv[i] ));
   }

   return;

} /* show_command_line() */






char * feature_status[] = {
   "",
   "    (ok)",
   " ** ERROR **",
   "    WHY?"
};
#define FEATURE_UNKNOWN 0
#define FEATURE_OK      1
#define FEATURE_MISSING 2
#define FEATURE_PRESENT 3

/*
 * print_sncadapter_info()
 *
 *
 */
int
print_sncadapter_info( DLL_GSSFP_T  * p_gssfp,  char   * p_prefix )
{
   int       rc      = 0;
   int       mutual_state = FEATURE_UNKNOWN;
   int       export_state = FEATURE_UNKNOWN;
   int       replay_state = FEATURE_UNKNOWN;
   int       conf_state   = FEATURE_UNKNOWN;
   int	     integ_state  = FEATURE_UNKNOWN;

   if ( p_gssfp->snc_adapter_flag==FALSE )
      return(rc);

   if ( p_gssfp->context_counter>0 ) {
      if ( p_gssfp->info.export_sec_context==0 ) {
	 export_state = FEATURE_MISSING;
      } else {
	 export_state = (p_gssfp->context_xferred)  > 0                        ? FEATURE_OK : FEATURE_MISSING;
      }
      if ( export_state==FEATURE_MISSING ) {
	 XVEB((V_SAP, "SNC Adapter wrong for mechanism behaviour : Context Export\n"));
      }

      if ( p_gssfp->info.replay_prot==0 ) {
	 replay_state = ((p_gssfp->ctx_flags_always)&GSS_C_REPLAY_FLAG)==0     ? FEATURE_OK : FEATURE_PRESENT;
      } else {
	 replay_state = ((p_gssfp->ctx_flags_denied)&GSS_C_REPLAY_FLAG)==0     ? FEATURE_OK : FEATURE_MISSING;
      }
      if ( replay_state==FEATURE_MISSING ) {
	 XVEB((V_SAP, "SNC Adapter wrong for mechanism behaviour : Data Replay Protection\n"));
      }

      if ( p_gssfp->info.mutual_auth==0 ) {
	 mutual_state = ((p_gssfp->ctx_flags_always)&GSS_C_MUTUAL_FLAG)==0     ? FEATURE_OK : FEATURE_PRESENT;
      } else {
	 mutual_state = ((p_gssfp->ctx_flags_denied)&GSS_C_MUTUAL_FLAG)==0     ? FEATURE_OK : FEATURE_MISSING;
      }
      if ( mutual_state==FEATURE_MISSING ) {
	 XVEB((V_SAP, "SNC Adapter wrong for mechanism behaviour : Mutual Authentication\n"));
      }

      if ( p_gssfp->info.conf_avail==0 ) {
	 conf_state = ((p_gssfp->context_conf)!=(p_gssfp->context_counter))  ? FEATURE_OK : FEATURE_PRESENT;
      } else {
	 conf_state = ((p_gssfp->context_conf)==(p_gssfp->context_counter))  ? FEATURE_OK : FEATURE_MISSING;
      }
      if ( conf_state==FEATURE_MISSING ) {
	 XVEB((V_SAP, "SNC Adapter wrong for mechanism behaviour : Confidentiality Protection\n"));
      }

      if ( p_gssfp->info.integ_avail==0 ) {
	 integ_state  = ((p_gssfp->context_integ)!=(p_gssfp->context_counter)) ? FEATURE_OK : FEATURE_PRESENT;
      } else {
	 integ_state  = ((p_gssfp->context_integ)==(p_gssfp->context_counter)) ? FEATURE_OK : FEATURE_MISSING;
      }
      if ( integ_state==FEATURE_MISSING ) {
	 XVEB((V_SAP, "SNC Adapter wrong for mechanism behaviour : Integrity Protection\n"));
      }
   }

   XVEB((V_SHOW, "%s-------------------------------------------------------------\n", p_prefix));

   XVEB((V_SHOW, "%s  Name = \"%s\"\n", p_prefix,
	         (p_gssfp->info.adapter_name)==NULL
	         ? "MISSING !?" : (p_gssfp->info.adapter_name) ));

   XVEB((V_SHOW, "\n"));
   XVEB((V_SHOW, "%s              supported SAP R/3 Releases : 3.1I, 4.0B, 4.5x, 4.6x\n",
		       p_prefix ));
   XVEB((V_SHOW, "%s                             Mech Prefix : \"%s\"   %s\n", p_prefix,
		 (p_gssfp->info.mech_prefix_string)==NULL
		 ? "MISSING !?" : (p_gssfp->info.mech_prefix_string),
		 ( (p_gssfp->info.mech_prefix_string)!=NULL
		   && strlen(p_gssfp->info.mech_prefix_string)<=7 )
		   ? feature_status[FEATURE_OK] : "(ERROR: len>7)" ));
   XVEB((V_SHOW, "%s                             SAPGSS_ID   : %d\n", p_prefix,
	         (int)(p_gssfp->info.mech_id) ));

   XVEB((V_SHOW, "%s  Support for      context import/export : %s   %s\n", p_prefix,
	         (p_gssfp->info.export_sec_context)==0 ? "No " : "Yes",
		 feature_status[export_state] ));
   XVEB((V_SHOW, "%s  Support for      mutual authentication : %s   %s\n", p_prefix,
	         (p_gssfp->info.mutual_auth)==0 ? "No " : "Yes",
		 feature_status[mutual_state] ));
   XVEB((V_SHOW, "%s  Support for     data replay protection : %s   %s\n", p_prefix,
		 (p_gssfp->info.replay_prot)==0 ? "No " : "Yes",
		 feature_status[replay_state] ));
   XVEB((V_SHOW, "%s  Support for confidentiality protection : %s   %s\n", p_prefix,
		 (p_gssfp->info.conf_avail)==0  ? "No " : "Yes",
		 feature_status[conf_state] ));
   XVEB((V_SHOW, "%s  Support for       integrity protection : %s   %s\n", p_prefix,
		 (p_gssfp->info.integ_avail)==0  ? "No " : "Yes",
		 feature_status[integ_state] ));

   XVEB((V_SHOW, "\n"));

   if ( p_gssfp->info.nt_canonical_name!=GSS_C_NO_OID ) {
      print_oid( 1, "canonical", p_gssfp->info.nt_canonical_name );
      if ( 0!=compare_oid( p_gssfp->info.nt_canonical_name, p_gssfp->can_nametype ) ) {
	 XVEB((V_SAP, "   canonical nametype OID in SNC-Adapter doesn't match mechanism!\n"));
	 print_oid( 1, "  mechanism returned", p_gssfp->can_nametype );
      }
   } else {
      XVEB((V_SAP, "  canonical nametype OID **MISSING**!\n"));
   }

   if ( p_gssfp->info.nt_private_name1!=GSS_C_NO_OID ) {
      if ( 0!=compare_oid( p_gssfp->info.nt_canonical_name, p_gssfp->info.nt_private_name1 ) ) {
	 XVEB((V_SAP, "  canonical and 1st private nametype OIDs must be identical!\n"));
      }
      XVEB((V_SHOW, "%s  Private nametype OIDs:\n", p_prefix));
      print_oid( 1, "   \"p:\"", p_gssfp->info.nt_private_name1 );
      if ( p_gssfp->info.nt_private_name2!=GSS_C_NO_OID ) {
	 print_oid( 1, "   \"x:\"", p_gssfp->info.nt_private_name2 );
	 if ( p_gssfp->info.nt_private_name3!=GSS_C_NO_OID ) {
	    print_oid( 1, "   \"y:\"", p_gssfp->info.nt_private_name3 );
	    if ( p_gssfp->info.nt_private_name4!=GSS_C_NO_OID ) {
	       print_oid( 1, "   \"z:\"", p_gssfp->info.nt_private_name4 );
	    }
	 }
      }

   } else {

      XVEB((V_SAP, "%s   NO private nametype OIDs defined!\n", p_prefix));

   }

   if ( p_gssfp->canonical_names_calls==FALSE
        ||  p_gssfp->info.mech_id==SAPGSS_ID_KERBEROS5_1
	||  p_gssfp->info.mech_id==SAPGSS_ID_SECUDE_1 ) {
      XVEB((V_SHOW, "\n%s   Canonical Printable nametype OID: (SNC-INTERNAL USE ONLY)\n", p_prefix));
      print_oid(1,  "   (c:)", p_gssfp->info.nt_canonical_name );
   }

   XVEB((V_SHOW, "%s-------------------------------------------------------------\n", p_prefix));
   XVEB((V_SHOW, "\n"));

   return(rc);

} /* print_sncadapter_info() */



/*
 * create_sncadapter_info()
 *
 *
 */
void
create_sncadapter_info( DLL_GSSFP_T   * p_gssfp,   char   * p_prefix )
{









} /* create_sncadapter_info() */



/*************************************************************************/
/* Information about the SNC-builtin adapters				 */
/*************************************************************************/
struct snc_builtin_info_s {
   char           *  label;
   char		  *  sap_release;
   char		  *  mech_prefix;
   SAPGSS_MECH_ID    mech_id;
   gss_OID_desc	     mech;
   gss_OID_desc	     cname;
   gss_OID_desc	     prv_name_1;
   gss_OID_desc	     prv_name_2;
   gss_OID_desc	     prv_name_3;
   gss_OID_desc	     prv_name_4;
   int		     export_avail;
   int		     mutual_avail;
   int		     replay_avail;
   int		     conf_avail;
   int		     integ_avail;
};


struct snc_builtin_info_s snc_builtin_info[] =
{
   {
     /* label        */   "Kerberos 5 (pre-rfc1964)",
     /* sap_release  */	  "3.1x, 4.0x, 4.5x, 4.6x",
     /* mech_prefix  */   "krb5",
     /* mech_id      */	  SAPGSS_ID_KERBEROS5_1,
     /* mech         */   {  5, "\053\005\001\005\002"                     },
     /* cname        */   { 10, "\052\206\110\206\367\022\001\002\002\001" },
     /* prv_name_1   */   { 10, "\052\206\110\206\367\022\001\002\002\001" },
     /* prv_name_2   */   {  0, 0 },
     /* prv_name_3   */   {  0, 0 },
     /* prv_name_4   */   {  0, 0 },
     /* export_avail */   TRUE,
     /* mutual_avail */   TRUE,
     /* replay_avail */   TRUE,
     /* conf_avail   */   TRUE,
     /* integ_avail  */   TRUE
   },

   {
     /* label        */   "Kerberos 5 (v2 - rfc1964)",
     /* sap_release  */	  "3.1x, 4.0x, 4.5x, 4.6x",
     /* mech_prefix  */   "krb5",
     /* mech_id      */	  SAPGSS_ID_KERBEROS5_1,
     /* mech         */   {  9, "\052\206\110\206\367\022\001\002\002"     },
     /* cname        */   { 10, "\052\206\110\206\367\022\001\002\002\001" },
     /* prv_name_1   */   { 10, "\052\206\110\206\367\022\001\002\002\001" },
     /* prv_name_2   */   {  0, 0 },
     /* prv_name_3   */   {  0, 0 },
     /* prv_name_4   */   {  0, 0 },
     /* export_avail */   TRUE,
     /* mutual_avail */   TRUE,
     /* replay_avail */   TRUE,
     /* conf_avail   */   TRUE,
     /* integ_avail  */   TRUE
   },

   {
     /* label        */   "Secude 5",
     /* sap_release  */	  "3.1x, 4.0x, 4.5x, 4.6x",
     /* mech_prefix  */   "secude",
     /* mech_id      */	  SAPGSS_ID_SECUDE_1,
     /* mech         */   {  6, "\053\044\003\001\045\001" },
     /* cname        */   {  6, "\053\044\003\001\046\001" },
     /* prv_name_1   */   {  6, "\053\044\003\001\046\001" },
     /* prv_name_2   */   {  0, 0 },
     /* prv_name_3   */   {  0, 0 },
     /* prv_name_4   */   {  0, 0 },
     /* export_avail */   TRUE,
     /* mutual_avail */   TRUE,
     /* replay_avail */   TRUE,
     /* conf_avail   */   TRUE,
     /* integ_avail  */   TRUE
   },

   {
     /* label        */   "SAPntlm SSO (NT4/W2K/Win9x/WinME)",
     /* sap_release  */	  "3.1I, 4.0B, 4.5x, 4.6x, 6.x",
     /* mech_prefix  */   "sapntlm",
     /* mech_id      */	  SAPGSS_ID_SAPNTLM,
     /* mech         */   { 10, "\053\006\001\004\001\205\066\002\001\002"     },
     /* cname        */   { 11, "\053\006\001\004\001\205\066\002\001\002\001" },
     /* prv_name_1   */   { 11, "\053\006\001\004\001\205\066\002\001\002\001" },
     /* prv_name_2   */   {  0, 0 },
     /* prv_name_3   */   {  0, 0 },
     /* prv_name_4   */   {  0, 0 },
     /* export_avail */   TRUE,
     /* mutual_avail */   FALSE,
     /* replay_avail */   FALSE,
     /* conf_avail   */   FALSE,
     /* integ_avail  */   FALSE
   },


   {  0, } /* empty entry */
      
};


/*
 * find_builtin_snc_adapter()
 *
 * Description:
 *   Find the mechanism which SNC would pick to talk to this mechanism
 *
 */
int
find_builtin_snc_adapter( gss_OID_set p_mech_set )
{
   int                           i;
   struct snc_builtin_info_s   * sbis;

   for ( sbis = snc_builtin_info ; sbis->label!=0 ; sbis++ ) {
      i = oid_in_oid_set(p_mech_set, &(sbis->mech));
      if ( i>=0 ) 
	 return( i );
   }

   return( -1 );

} /* find_builtin_snc_adapter() */



/*
 * verify_snc_builtin_info()
 *
 *
 */
void
verify_snc_builtin_info( DLL_GSSFP_T    * p_gssfp,    char   * p_prefix )
{
   struct snc_builtin_info_s  *builtin;

   if ( p_gssfp->snc_adapter_flag!=FALSE )
      return;

   for ( builtin = &(snc_builtin_info[0]) ; (builtin->label)!=0 ; builtin++ ) {

      if ( compare_oid(p_gssfp->mech, &(builtin->mech) )==0 ) {

	 p_gssfp->snc_builtin_flag = TRUE;

	 XVEB((V_SHOW, "%s-------------------------------------------------------------\n", p_prefix));

	 XVEB((V_SHOW, "%s  Name = \"Builtin SNC-Adapter for %s\"\n",
		       p_prefix, (builtin->label) ));

         XVEB((V_SHOW, "\n"));

	 XVEB((V_SHOW, "%s              supported SAP R/3 Releases : %s\n",
		       p_prefix, (builtin->sap_release) ));
	 XVEB((V_SHOW, "%s                             Mech Prefix : \"%s\"\n",
		       p_prefix, (builtin->mech_prefix) ));
         XVEB((V_SHOW, "%s                             SAPGSS_ID   : %d\n",
		       p_prefix, (int)(builtin->mech_id) ));

	 if ( p_gssfp->context_xferred==0 ) {
	    XVEB((V_SAP, "SNC INcompatible: context xfer missing!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Support for      context import/export : %s\n",
			  p_prefix, (builtin->export_avail)==0 ? "No " : "Yes" ));
	 }

	 if ( builtin->mutual_avail &&
	      ((p_gssfp->ctx_flags_denied)&GSS_C_MUTUAL_FLAG)!=0 ) {
	    XVEB((V_SAP, "SNC INcompatible: mutual authentication missing!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Support for      mutual authentication : %s\n",
			  p_prefix, (builtin->mutual_avail)==0 ? "No " : "Yes" ));
	 }

	 if ( builtin->replay_avail &&
	      ((p_gssfp->ctx_flags_denied)&GSS_C_REPLAY_FLAG)!=0 ) {
	    XVEB((V_SAP, "SNC INcompatible: data replay protection missing!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Support for     data replay protection : %s\n",
			  p_prefix, (builtin->replay_avail)==0 ? "No " : "Yes" ));
	 }

	 if ( builtin->conf_avail &&
	      ((p_gssfp->ctx_flags_denied)&GSS_C_CONF_FLAG)!=0 ) {
	    XVEB((V_SAP, "SNC INcompatible: confidentiality protection missing!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Support for confidentiality protection : %s\n",
			  p_prefix, (builtin->conf_avail)==0 ? "No " : "Yes" ));
	 }

	 if ( builtin->integ_avail &&
	      ((p_gssfp->ctx_flags_denied)&GSS_C_INTEG_FLAG)!=0 ) {
	    XVEB((V_SAP, "SNC INcompatible: integrity protection missing!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Support for       integrity protection : %s\n",
			  p_prefix, (builtin->integ_avail)==0 ? "No " : "Yes" ));
	 }

	 XVEB((V_SHOW, "\n"));

	 if ( compare_oid(p_gssfp->can_nametype, &(builtin->prv_name_1))!=0 ) {
	    XVEB((V_SAP, "SNC INcompatible: canonical nametype OID doesn't match!\n"));
	 } else {
	    XVEB((V_SHOW, "%s  Private nametype OIDs:\n", p_prefix));
	    print_oid( 1, "   \"p:\"", &(builtin->prv_name_1) );

	 }

	 XVEB((V_SHOW, "%s-------------------------------------------------------------\n", p_prefix));

	 XVEB((V_SHOW, "\n"));

	 break;

      } /* found builtin_info */

   } /* for( builtin ) */
   
   return;

} /* verify_snc_builtin_info() */




/*
 * show_snc_limits()
 *
 *
 */
void
show_snc_limits( char    * p_prefix )
{
   if ( options.sap_constraints==FALSE )
      return;

   XVEB((V_SHOW, "%s-------------------------------------------------------------\n",
		 p_prefix ));
   XVEB((V_SHOW, "%s  Current limits for SNC-interoperability\n", p_prefix ));
   XVEB((V_SHOW, "%s    with %s:\n", p_prefix, SNC_LIMITS_LABEL ));

   XVEB((V_SHOW, "\n" ));

   XVEB((V_SHOW, "%s  max. length of printable names           = %6u   octets\n",
	         p_prefix, (Uint)SNC_NAME_MAXLEN ));
   XVEB((V_SHOW, "%s  max. length of exported (binary) names   = %6u   octets\n",
		 p_prefix, (Uint)SNC_ACLKEY_MAXLEN ));
   XVEB((V_SHOW, "%s  max. size of MIC token by gss_getmic()   = %6u   octets\n",
	         p_prefix, (Uint)SNC_MAX_MIC_TOKEN ));
   XVEB((V_SHOW, "%s  max. message size increase by gss_wrap() = %6u   octets\n",
	         p_prefix, (Uint)SNC_MAX_WRAP_INCREASE ));
   XVEB((V_SHOW, "%s  max. size of context establishment token = %6u   octets\n",
	         p_prefix, (Uint)SNC_MAX_CONTEXT_TOKEN ));
   XVEB((V_SHOW, "%s  max. size of exported context token      = %6u   octets\n",
	         p_prefix, (Uint)SNC_MAX_EXPORTED_CTX_TOKEN ));
   XVEB((V_SHOW, "%s  max. context establishment time          = %8.1f millisec\n",
	         p_prefix, (float)(SNC_MAX_ESTABLISHMENT_TIME * 0.001) ));
   XVEB((V_SHOW, "%s  max. CPU time import/export_sec_context  = %8.1f millisec  (%4.1f)\n",
		 p_prefix, (float)(SNC_MAX_CTX_XFER_TIME * 0.001),
		 (float)(SNC_MAX_CTX_XFER_TIME * 0.001)/perf_correction ));
   XVEB((V_SHOW, "%s  max. CPU time for gss_context_time()     = %8.1f millisec  (%4.1f)\n",
	         p_prefix, (float)(SNC_MAX_GSS_CONTEXT_TIME * 0.001),
		 (float)(SNC_MAX_GSS_CONTEXT_TIME * 0.001)/perf_correction ));
   XVEB((V_SHOW, "%s  max. getmic()/verifymic() latency        = %8.1f millisec  (%4.1f)\n",
	         p_prefix, (float)(SNC_MAX_MIC_LATENCY * 0.001),
		 (float)(SNC_MAX_MIC_LATENCY * 0.001)/perf_correction ));
   XVEB((V_SHOW, "%s  max. wrap(mic)/unwrap(mic) latency       = %8.1f millisec  (%4.1f)\n",
	         p_prefix, (float)(SNC_MAX_WMIC_LATENCY * 0.001),
		 (float)(SNC_MAX_WMIC_LATENCY * 0.001)/perf_correction ));
   XVEB((V_SHOW, "%s  max. wrap(conf)/unwrap(conf) latency     = %8.1f millisec  (%4.1f)\n",
	         p_prefix, (float)(SNC_MAX_WCONF_LATENCY * 0.001),
		 (float)(SNC_MAX_WCONF_LATENCY * 0.001)/perf_correction ));


   XVEB((V_SHOW, "%s-------------------------------------------------------------\n",
		 p_prefix ));
   XVEB((V_SHOW, "\n" ));

   return;

} /* show_snc_limits() */
