krb5-clients/1089: Patch to kinit.c using previously sent change

bbense@stanford.edu bbense at stanford.edu
Tue Apr 16 16:10:29 EDT 2002


>Number:         1089
>Category:       krb5-clients
>Synopsis:       patch to use appdefaults
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    krb5-unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   unknown
>Arrival-Date:   Tue Apr 16 16:11:01 EDT 2002
>Last-Modified:
>Originator:     Booker C. Bense
>Organization:
	Stanford University
>Release:        krb5-1.2.2
>Environment:
	UNIX
System: SunOS shred.Stanford.EDU 5.7 Generic_106541-15 sun4u sparc SUNW,Ultra-5_10
Architecture: sun4

>Description:
	Patch to use appdefaults api previous sent. I have a similar
	patch for login.c if you are interested. 
>How-To-Repeat:
>Fix:
	This patch uses the appdefaults api to control the behaviour
of kinit. 

===================================================================
RCS file: /afs/ir/dev/cvs/kerberos/krb5/clients/kinit/kinit.c,v
retrieving revision 1.1.1.3
retrieving revision 1.19
diff -u -r1.1.1.3 -r1.19
--- /usr/users/bbense/work/kerberos/krb5/clients/kinit/kinit.c	5 Jul 2000 22:46:08 -0000	1.1.1.3
+++ /usr/users/bbense/work/kerberos/krb5/clients/kinit/kinit.c	31 Aug 2001 16:24:02 -0000	1.19
@@ -34,9 +34,19 @@
 #else
 #undef HAVE_KRB524
 #endif
+
+#ifdef STANFORD
+#ifndef ORGANIZATION
+#define DEFAULT_AKLOG_PROGRAM "/etc/leland/aklog" 
+#define ORGANIZATION "Stanford University (Leland)"
+#endif /*ORGANIZATION*/
+#endif 
+
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
+#include <sys/types.h> 
+#include  <sys/wait.h> 
 
 #ifdef GETOPT_LONG
 #include <getopt.h>
@@ -91,6 +101,24 @@
 #endif /* _WIN32 */
 #endif /* HAVE_PWD_H */
 
+/* Define the strings for default searching (got these from appl/bsd/login.c) */ 
+/* This is really a run-time option */ 
+#define KINIT_USE_KRB524     "krb4_convert"
+/* These can be controlled via command line options. */ 
+#define KINIT_DEFAULT_COUNT   6
+#define KINIT_GET_KRB5TKT    "krb5_get_tickets"
+#define KINIT_GETK5_INDEX     0 
+#define KINIT_GET_KRB4TKT    "krb4_get_tickets"
+#define KINIT_GETK4_INDEX     1
+#define KINIT_DEFAULT_LIFE   "default_lifetime"
+#define KINIT_LIFETM_INDEX    2
+#define KINIT_GET_TOKEN      "krb_run_aklog"
+#define KINIT_GETTK_INDEX     3
+#define KINIT_TOKEN_PROGRAM  "aklog_path"
+#define KINIT_TOKPG_INDEX     4
+#define KINIT_FORWARDABLE    "krb5_get_forwardable"
+#define KINIT_FORWD_INDEX     5
+
 static char *progname;
 
 static char* progname_v5 = 0;
@@ -99,8 +127,9 @@
 static char* progname_v524 = 0;
 #endif
 
-static int got_k5 = 0;
+
 static int got_k4 = 0;
+static int got_k5 = 0;
 
 static int default_k5 = 1;
 #if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
@@ -112,7 +141,11 @@
 static int authed_k5 = 0;
 static int authed_k4 = 0;
 
+#ifdef STANFORD
+#define KRB4_BACKUP_DEFAULT_LIFE_SECS 25*60*60 /* 25 hours */
+#else
 #define KRB4_BACKUP_DEFAULT_LIFE_SECS 10*60*60 /* 10 hours */
+#endif 
 
 typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
 
@@ -140,6 +173,12 @@
     char* k4_cache_name;
 
     action_type action;
+
+    char* token_program; 
+    int get_token; 
+    int use_k4;
+    int use_k5; 
+
 };
 
 struct k5_data
@@ -210,11 +249,17 @@
 	    "[-A" USAGE_LONG_ADDRESSES "] "
 	    USAGE_BREAK
 	    "[-v] [-R] "
+#ifdef STANFORD
+	    "[-k [-K keytab_file]] "
+	    USAGE_BREAK
+	    "[-t [-T program]]"
+#else
 	    "[-k [-t keytab_file]] "
+#endif 	
 	    USAGE_BREAK
 	    "[-c cachename] "
-	    "[-S service_name] [principal]"
-	    "\n\n", 
+            "[-S service_name] [principal]"
+            "\n\n", 
 	    progname);
 
 #define KRB_AVAIL_STRING(x) ((x)?"available":"not available")
@@ -237,7 +282,7 @@
 #define ULINE(indent, col1, col2) \
 fprintf(stderr, USAGE_OPT_FMT, indent, col1, col2)
 
-    ULINE("    ", "options:", "valid with Kerberos:");
+    ULINE("    ", "options:", "valid with Kerberos:"); 
     fprintf(stderr, "\t-5 Kerberos 5 ()\n", KRB_AVAIL_STRING(got_k5));
     fprintf(stderr, "\t-4 Kerberos 4 ()\n", KRB_AVAIL_STRING(got_k4));
     fprintf(stderr, "\t   (Default behavior is to try )\n",
@@ -257,7 +302,13 @@
     ULINE("\t", "-v validate",                  OPTTYPE_KRB5);
     ULINE("\t", "-R renew",                     OPTTYPE_BOTH);
     ULINE("\t", "-k use keytab",                OPTTYPE_BOTH);
+#ifdef STANFORD
+    ULINE("\t", "-K filename of keytab to use", OPTTYPE_BOTH);
+    ULINE("\t", "-t get afs token", OPTTYPE_BOTH);
+    ULINE("\t", "-T program to run to get afstoken", OPTTYPE_BOTH);
+#else 
     ULINE("\t", "-t filename of keytab to use", OPTTYPE_BOTH);
+#endif 
     ULINE("\t", "-c Kerberos 5 cache name",     OPTTYPE_KRB5);
     /* This options is not yet available: */
     /* ULINE("\t", "-C Kerberos 4 cache name",     OPTTYPE_KRB4); */
@@ -266,10 +317,11 @@
 }
 
 char *
-parse_options(argc, argv, opts)
+parse_options(argc, argv, opts,default_list)
     int argc;
     char **argv;
     struct k_opts* opts;
+    krb5_appdefault_list_item *default_list; 
 {
     krb5_error_code code;
     int errflg = 0;
@@ -277,7 +329,11 @@
     int use_k5 = 0;
     int i;
 
+#ifdef STANFORD
+    while ((i = GETOPT(argc, argv, "r:fpFP54AVl:s:c:kK:tT:RS:v"))
+#else 
     while ((i = GETOPT(argc, argv, "r:fpFP54AVl:s:c:kt:RS:v"))
+#endif 	
 	   != -1) {
 	switch (i) {
 	case 'V':
@@ -289,6 +345,9 @@
 	    if (code != 0 || opts->lifetime == 0) {
 		fprintf(stderr, "Bad lifetime value \n", optarg);
 		errflg++;
+	    } else { 
+		    /* Don't read in any default */ 
+		    default_list[KINIT_LIFETM_INDEX].store = NULL ; 
 	    }
 	    break;
 	case 'r':
@@ -301,6 +360,7 @@
 	    break;
 	case 'f':
 	    opts->forwardable = 1;
+	    default_list[KINIT_FORWD_INDEX].store = NULL ; 
 	    break;
 	case 'F':
 	    opts->not_forwardable = 1;
@@ -338,6 +398,35 @@
 	case 'k':
 	    opts->action = INIT_KT;
 	    break;
+#ifdef STANFORD
+	case 'K':
+	    if (opts->keytab_name)
+	    {
+		fprintf(stderr, "Only one -K option allowed.\n");
+		errflg++;
+	    } else {
+		opts->keytab_name = optarg;
+	    }
+	    break;
+	case 't':            /* get afs token */ 
+	    
+	    opts->get_token = 1 ;
+	    default_list[KINIT_GETTK_INDEX].store = NULL ; 
+	    break;
+	case 'T':            
+	    if (opts->token_program != NULL)
+	    {
+		fprintf(stderr, "Only one -T option allowed.\n");
+		errflg++;
+	    } else {
+	      /* -T implies -t or does it ?*/ 
+	        opts->get_token = 1; 
+		default_list[KINIT_GETTK_INDEX].store = NULL ; 
+		opts->token_program = optarg;
+		default_list[KINIT_TOKPG_INDEX].store = NULL ; 
+	    }
+	    break;
+#else
 	case 't':
 	    if (opts->keytab_name)
 	    {
@@ -347,6 +436,7 @@
 		opts->keytab_name = optarg;
 	    }
 	    break;
+#endif 
 	case 'R':
 	    opts->action = RENEW;
 	    break;
@@ -387,7 +477,11 @@
 #endif
 		exit(3);
 	    }
-	    use_k4 = 1;
+	    opts->use_k4 = 1;
+	    default_list[KINIT_GETK4_INDEX].store = NULL ;
+	    /* -4 implies K4 only */ 
+	    opts->use_k5 = 0;
+	    default_list[KINIT_GETK5_INDEX].store = NULL ;
 	    break;
 	case '5':
 	    if (!got_k5)
@@ -395,7 +489,11 @@
 		fprintf(stderr, "Kerberos 5 support could not be loaded\n");
 		exit(3);
 	    }
-	    use_k5 = 1;
+	    opts->use_k5 = 1;
+	    default_list[KINIT_GETK5_INDEX].store = NULL ;
+	    /* -5 implies K5 only */ 
+	    opts->use_k4 = 0 ; 
+	    default_list[KINIT_GETK4_INDEX].store = NULL ;
 	    break;
 	default:
 	    errflg++;
@@ -424,16 +522,16 @@
 		argv[optind+1]);
 	errflg++;
     }
-
+    /****** Need to rexamine this *******/ 
     /* At this point, if errorless, we know we only have one option
        selection */
-    if (!use_k5 && !use_k4) {
-	use_k5 = default_k5;
-	use_k4 = default_k4;
+    if (!opts->use_k5 && !opts->use_k4) {
+	opts->use_k5 = default_k5;
+	opts->use_k4 = default_k4;
     }
 
     /* Now, we encode the OPTTYPE stuff here... */
-    if (!use_k5 &&
+    if (!opts->use_k5 &&
 	(opts->starttime || opts->rlife || opts->forwardable || 
 	 opts->proxiable || opts->addresses || opts->not_forwardable || 
 	 opts->not_proxiable || opts->no_addresses || 
@@ -442,7 +540,7 @@
 	fprintf(stderr, "Specified option that requires Kerberos 5\n");
 	errflg++;
     }
-    if (!use_k4 &&
+    if (!opts->use_k4 &&
 	opts->k4_cache_name)
     {
 	fprintf(stderr, "Specified option that require Kerberos 4\n");
@@ -450,9 +548,9 @@
     }
     if (
 #ifdef HAVE_KRB524
-	!use_k5
+	!opts->use_k5
 #else
-	use_k4
+	opts->use_k4
 #endif
 	&& (opts->service_name || opts->keytab_name || 
 	    (opts->action == INIT_KT) || (opts->action == RENEW))
@@ -466,13 +564,91 @@
 	usage();
     }
 
-    got_k5 = got_k5 && use_k5;
-    got_k4 = got_k4 && use_k4;
-
     opts->principal_name = (optind == argc-1) ? argv[optind] : 0;
     return opts->principal_name;
 }
 
+/* 
+ *  Initialize defaults_list for use with krb5_appdefaults_read 
+ */ 
+
+void
+init_defaults(opts,default_list) 
+  krb5_appdefault_list_item *default_list;
+  struct k_opts* opts ; 
+  
+{
+  
+    /* Get K5 tgt */ 
+    default_list[KINIT_GETK5_INDEX].option = KINIT_GET_KRB5TKT ; 
+    default_list[KINIT_GETK5_INDEX].default_value = "yes" ; 
+    default_list[KINIT_GETK5_INDEX].parse_function = krb5_string_to_boolean ; 
+    default_list[KINIT_GETK5_INDEX].store =(void *) &(opts->use_k5); 
+
+    /* Get k4 tgt */ 
+    default_list[KINIT_GETK4_INDEX].option = KINIT_GET_KRB4TKT ; 
+#ifdef STANFORD
+    default_list[KINIT_GETK4_INDEX].default_value = "yes" ;
+#else 
+    default_list[KINIT_GETK4_INDEX].default_value = "no" ;
+#endif  
+    default_list[KINIT_GETK4_INDEX].parse_function = krb5_string_to_boolean ; 
+    default_list[KINIT_GETK4_INDEX].store =(void *) &(opts->use_k4); 
+
+    /* Lifetime */
+    default_list[KINIT_LIFETM_INDEX].option = KINIT_DEFAULT_LIFE ;
+#ifdef STANFORD
+    default_list[KINIT_LIFETM_INDEX].default_value = "25hrs" ; 
+#else 
+    default_list[KINIT_LIFETM_INDEX].default_value = "10hrs" ; 
+#endif    
+    default_list[KINIT_LIFETM_INDEX].parse_function = krb5_string_to_deltat ; 
+    default_list[KINIT_LIFETM_INDEX].store =(void *) &(opts->lifetime); 
+
+    /* run aklog */ 
+
+    default_list[KINIT_GETTK_INDEX].option = KINIT_GET_TOKEN ; 
+    default_list[KINIT_GETTK_INDEX].default_value = "no" ; 
+    default_list[KINIT_GETTK_INDEX].parse_function = krb5_string_to_boolean ; 
+    default_list[KINIT_GETTK_INDEX].store =(void *) &(opts->get_token); 
+
+    /* aklog path :strdup and free stringval*/
+
+    default_list[KINIT_TOKPG_INDEX].option = KINIT_TOKEN_PROGRAM ; 
+    default_list[KINIT_TOKPG_INDEX].default_value = "/usr/pubsw/bin/aklog" ; 
+    default_list[KINIT_TOKPG_INDEX].parse_function = krb5_string_to_string ; 
+    default_list[KINIT_TOKPG_INDEX].store =(void *) &(opts->token_program); 
+  
+    /* Get forwardable tgt */ 
+
+    default_list[KINIT_FORWD_INDEX].option = KINIT_FORWARDABLE ; 
+    default_list[KINIT_FORWD_INDEX].default_value = "no" ; 
+    default_list[KINIT_FORWD_INDEX].parse_function = krb5_string_to_boolean ; 
+    default_list[KINIT_FORWD_INDEX].store =(void *) &(opts->forwardable); 
+   
+}
+
+
+int
+read_defaults(opts,default_list,k5)
+ struct k_opts* opts; 
+ struct k5_data* k5; 
+ krb5_appdefault_list_item *default_list; 
+{ 
+	int rcode;
+	if ( k5->me != NULL ) { 
+		rcode = krb5_appdefault_read(k5->ctx,progname,
+			       krb5_princ_realm(k5->ctx,k5->me),
+			       default_list,KINIT_DEFAULT_COUNT);
+	} else { 
+		rcode = krb5_appdefault_read(k5->ctx,progname,
+			       NULL,
+			       default_list,KINIT_DEFAULT_COUNT);
+	}
+  return rcode ; 
+}
+
+
 int
 k5_begin(opts, k5, k4)
     struct k_opts* opts;
@@ -482,13 +658,15 @@
     char* progname = progname_v5;
     krb5_error_code code = 0;
 
-    if (!got_k5)
+    if (!opts->use_k5)
 	return 0;
 
+    
     if (code = krb5_init_context(&k5->ctx)) {
 	com_err(progname, code, "while initializing Kerberos 5 library");
 	return 0;
     }
+
     if (opts->k5_cache_name)
     {
 	code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc);
@@ -553,19 +731,26 @@
 	com_err(progname, code, "when unparsing name");
 	return 0;
     }
+#ifndef STANFORD
+    /* I'm not sure this is the right way to do this. If opts->principal_name
+       is available on the cmd line, we need to preserve it for k4_begin.
+       If it's not we want it to be null when k4_begin runs. This ifdef
+       seems to me to be a signal that the design is wrong. opts->principal
+       name should only be used for input, not output. If it's not set
+       by the cmd line it should be left alone. 
+    */ 
     opts->principal_name = k5->name;
+#endif 
 
 #ifdef KRB5_KRB4_COMPAT
-    if (got_k4)
-    {
-	/* Translate to a Kerberos 4 principal */
-	code = krb5_524_conv_principal(k5->ctx, k5->me,
-				       k4->aname, k4->inst, k4->realm);
-	if (code) {
+    
+    /* Translate to a Kerberos 4 principal */
+    code = krb5_524_conv_principal(k5->ctx, k5->me,
+				   k4->aname, k4->inst, k4->realm);
+    if (code) {
 	    k4->aname[0] = 0;
 	    k4->inst[0] = 0;
 	    k4->realm[0] = 0;
-	}
     }
 #endif
     return 1;
@@ -596,12 +781,16 @@
     int k_errno = 0;
 #endif
 
-    if (!got_k4)
+    if (!opts->use_k4)
 	return 0;
 
 #ifdef KRB5_KRB4_COMPAT
+#ifndef STANFORD
+    /* Since we want K4 to work in the face of a bad krb5.conf file */
+    /* We can't believe the answer that we get from k5_begin */  
     if (k4->aname[0])
 	goto skip;
+#endif 
 
     if (opts->principal_name)
     {
@@ -643,15 +832,21 @@
 	}
     }
 
+#ifdef STANFORD
+    krb_get_lrealm(k4->realm, 1) ; 
+#else
     if (!k4->realm[0])
 	krb_get_lrealm(k4->realm, 1);
-
+#endif 
     if (k4->inst[0])
 	sprintf(k4->name, ".@", k4->aname, k4->inst, k4->realm);
     else
-	sprintf(k4->name, "@", k4->aname, k4->realm);
-    opts->principal_name = k4->name;
-
+	sprintf(k4->name, "@", k4->aname, k4->realm); 
+#ifdef STANFORD
+    /* opts->principal_name should not be used for output only input*/ 
+    if ( opts->principal_name == NULL)
+	opts->principal_name = k4->name;
+#endif 
  skip:
     if (k4->aname[0] && !k_isname(k4->aname))
     {
@@ -727,7 +922,7 @@
     krb5_error_code code = 0;
     krb5_get_init_creds_opt options;
 
-    if (!got_k5)
+    if (!opts->use_k5 || k5->me == NULL)
 	return 0;
 
     krb5_get_init_creds_opt_init(&options);
@@ -868,7 +1063,7 @@
     int k_errno = 0;
 #endif
 
-    if (!got_k4)
+    if (!opts->use_k4)
 	return 0;
 
     if (opts->starttime)
@@ -876,15 +1071,8 @@
 
 #ifdef KRB5_KRB4_COMPAT
     if (!k4->lifetime)
-	k4->lifetime = opts->lifetime;
-    if (!k4->lifetime)
-	k4->lifetime = KRB4_BACKUP_DEFAULT_LIFE_SECS;
-
-    k4->lifetime /= (5 * 60);
-    if (k4->lifetime < 1)
-	k4->lifetime = 1;
-    if (k4->lifetime > 255)
-	k4->lifetime = 255;
+	k4->lifetime = krb_time_to_life(0,opts->lifetime);
+        
 
     switch (opts->action)
     {
@@ -894,7 +1082,7 @@
 	    krb5_error_code code;
 	    char prompt[1024];
 
-	    sprintf(prompt, "Password for : ", opts->principal_name);
+	    sprintf(prompt, "Password for : ", k4->name);
 	    stash_password[0] = 0;
 	    /*
 	      Note: krb5_read_password does not actually look at the
@@ -906,7 +1094,7 @@
 	    if (code || pwsize == 0)
 	    {
 		fprintf(stderr, "Error while reading password for ''\n",
-			opts->principal_name);
+			k4->name);
 		memset(stash_password, 0, sizeof(stash_password));
 		return 0;
 	    }
@@ -953,8 +1141,9 @@
 
 #ifdef HAVE_KRB524
 /* Convert krb5 tickets to krb4. */
-int try_convert524(k5)
+int try_convert524(opts,k5)
     struct k5_data* k5;
+    struct k_opts* opts; 
 {
     char * progname = progname_v524;
     krb5_error_code code = 0;
@@ -964,7 +1153,7 @@
     krb5_creds increds;
     CREDENTIALS v4creds;
 
-    if (!got_k4 || !got_k5)
+    if (!opts->use_k4 || !got_k5)
 	return 0;
 
     memset((char *) &increds, 0, sizeof(increds));
@@ -1052,6 +1241,9 @@
     struct k_opts opts;
     struct k5_data k5;
     struct k4_data k4;
+    
+    krb5_appdefault_list_item default_list[ KINIT_DEFAULT_COUNT]; 
+    int retval ; 
 
     progname = GET_PROGNAME(argv[0]);
     progname_v5 = getvprogname("5");
@@ -1082,16 +1274,44 @@
 
     memset(&k5, 0, sizeof(k5));
     memset(&k4, 0, sizeof(k4));
+    memset(&default_list,0,sizeof(default_list)); 
+
+    init_defaults(&opts,default_list) ; 
 
-    parse_options(argc, argv, &opts);
+    parse_options(argc, argv, &opts,default_list);
 
     got_k5 = k5_begin(&opts, &k5, &k4);
-    got_k4 = k4_begin(&opts, &k4);
 
+    /* need K5 principal */ 
+
+    retval = read_defaults(&opts,default_list,&k5) ;
+    
+    got_k4 = k4_begin(&opts, &k4);
+#ifdef STANFORD
+    /* Happy greeting message */ 
+    { 
+      char host[MAXHOSTNAMELEN] ;
+      host[0] ='\0'; 
+      if ( opts.action != VALIDATE ) { 
+	if ( gethostname(host,MAXHOSTNAMELEN)) { 
+	  strncat(host,"unknown",MAXHOSTNAMELEN);
+	}
+	printf(" ()\n",ORGANIZATION,host); 
+      }
+    }
+#endif 
+    
     authed_k5 = k5_kinit(&opts, &k5);
 #ifdef HAVE_KRB524
-    if (authed_k5)
-	authed_k4 = try_convert524(&k5);
+    /* Check the config file default */ 
+    if (authed_k5) { 
+      krb5_appdefault_boolean(k5.ctx,progname, 
+			      krb5_princ_realm(k5.ctx,k5.me),KINIT_USE_KRB524,
+			      TRUE, &retval) ; 
+      if ( retval ) { 
+	authed_k4 = try_convert524(&opts,&k5);
+      }
+    }
 #endif
     if (!authed_k4)
 	authed_k4 = k4_kinit(&opts, &k4, k5.ctx);
@@ -1106,8 +1326,48 @@
 
     k5_end(&k5);
     k4_end(&k4);
-
-    if ((got_k5 && !authed_k5) || (got_k4 && !authed_k4))
+    /* This was ||, I think && is a better choice. */ 
+    if ((opts.use_k5 && !authed_k5) && (opts.use_k4 && !authed_k4))
 	exit(1);
+
+    if ( opts.get_token ) {
+      /* Since we have unistd.h from above use access rather than stat */ 
+      if ( access( opts.token_program, X_OK ) == 0 ) { 
+	  /* Some linuxes use bash as the /bin/sh for the system
+	   * call. This interacts badly with afs tokens, due
+	   * to a bug in the getgroups call. 
+	   */  
+	my_system( opts.token_program) ;       
+      } else { 
+	fprintf(stderr,"Cannot execute :: to get token.\n",opts.token_program); 
+      }
+      
+    }
+
     return 0;
 }
+
+int
+my_system( char *cmd) { 
+
+    int status ; 
+    int pid,child; 
+    /* Low budget version of system call */ 
+
+    if ( (pid = fork()) < 0 ) { /* syserr */ 
+	fprintf(stderr,"fork failed.\n" ); 
+	return (-1) ; 
+    } else if ( pid == 0 ) { /*child */ 
+	if ( execl(cmd,cmd,(char * )0 ) ) { 
+	    fprintf(stderr,"error execing \n",cmd);
+	} 
+    } else { /* parent */  
+	child = wait(&status); 
+	if ( child != pid ) { /* This branch should never happen */  
+	    fprintf(stderr,"Got funky children pid != child\n"); 
+	    return(-1) ; 
+	}
+	status = WEXITSTATUS(status); 
+    }
+  return status ; 
+} 

>Audit-Trail:
>Unformatted:



More information about the krb5-bugs mailing list