[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] reauth functionality for kinit




IIRC, kth-krb4's kinit had "reauth" functionality; it could fork a
child and wake up and obtain new creds periodically as long as the
process ran.

This is very useful and heimdal's kinit currently doesn't have it.
We've implemented this locally, here's the patch.  Ours is ugly in
several ways and I don't necessarily think that it should go into
heimdal as-is but I think that the functionality ought to be there and
I thought I'd share what we've done.



john


diff -ru heimdal-0.6/kuser/kinit.c /afs/club/system/src/local/heimdal/006/kuser/kinit.c
--- heimdal-0.6/kuser/kinit.c	2003-05-08 14:58:37.000000000 -0400
+++ /afs/club/system/src/local/heimdal/006/kuser/kinit.c	2003-05-24 18:57:48.000000000 -0400
@@ -42,6 +42,8 @@
 int version_flag	= 0;
 int help_flag		= 0;
 int addrs_flag		= 1;
+int debug_flag          = 0;
+int nofork_flag         = 0;
 struct getarg_strings extra_addresses;
 int anonymous_flag	= 0;
 char *lifetime 		= NULL;
@@ -59,6 +61,20 @@
 #endif
 int fcache_version;
 
+#define PASSWD_LEN 256
+
+int got_sigchild = 0;
+int got_sigalarm = 0;
+
+void sighandler(int sig);
+void sighandler(int sig) {
+  switch(sig) {
+  case SIGALRM: got_sigalarm = 1; break;
+  case SIGCHLD: got_sigchild = 1; break;
+  }
+}
+
+
 static struct getargs args[] = {
 #ifdef KRB4
     { "524init", 	'4', arg_flag, &get_v4_tgt,
@@ -121,6 +137,12 @@
     { "anonymous",	0,   arg_flag,	&anonymous_flag,
       "request an anonymous ticket" },
 
+    { "debug",          0,   arg_flag,  &debug_flag,
+      "print some debugging information" },
+
+    { "nofork",         'n', arg_flag,  &nofork_flag,
+      "don't fork child procs" },
+
     { "version", 	0,   arg_flag, &version_flag },
     { "help",		0,   arg_flag, &help_flag }
 };
@@ -390,20 +412,25 @@
     return ret;
 }
 
+int got_passwd = 0;
+
 static krb5_error_code
 get_new_tickets(krb5_context context, 
 		krb5_principal principal,
 		krb5_ccache ccache,
-		krb5_deltat ticket_life)
+		krb5_deltat ticket_life,
+		char *passwd)
 {
     krb5_error_code ret;
     krb5_get_init_creds_opt opt;
     krb5_addresses no_addrs;
     krb5_creds cred;
-    char passwd[256];
+
     krb5_deltat start_time = 0;
     krb5_deltat renew = 0;
 
+
+
     memset(&cred, 0, sizeof(cred));
 
     krb5_get_init_creds_opt_init (&opt);
@@ -486,11 +513,13 @@
 	asprintf (&prompt, "%s's Password: ", p);
 	free (p);
 
-	if (des_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){
+	if(!got_passwd) {
+	  if (des_read_pw_string(passwd, PASSWD_LEN - 1, prompt, 0)){
 	    memset(passwd, 0, sizeof(passwd));
 	    exit(1);
+	  }
+	  got_passwd = 1;
 	}
-
 	free (prompt);
 
 	ret = krb5_get_init_creds_password (context,
@@ -516,7 +545,7 @@
 	    return exit_val;
     }
 #endif
-    memset(passwd, 0, sizeof(passwd));
+    //    memset(passwd, 0, sizeof(passwd));
 
     switch(ret){
     case 0:
@@ -571,9 +600,12 @@
     krb5_principal principal;
     int optind = 0;
     krb5_deltat ticket_life = 0;
+    char passwd[PASSWD_LEN];
+    int exitcode = 0;
 
     setprogname (argv[0]);
-    
+
+
     ret = krb5_init_context (&context);
     if (ret)
 	errx(1, "krb5_init_context failed: %d", ret);
@@ -581,6 +613,11 @@
     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
 	usage(1);
     
+ 
+    if(lifetime && debug_flag) {
+      printf("ticket life %s\n", lifetime);
+    }
+
     if (help_flag)
 	usage (0);
 
@@ -641,13 +678,19 @@
 	    errx (1, "unparsable time: %s", lifetime);
 
 	ticket_life = tmp;
+ 
+	if(lifetime && debug_flag) {
+	  printf("ticket life %s\n", lifetime);
+	}
     }
+
 #ifdef KRB4
     if(get_v4_tgt == -1)
 	krb5_appdefault_boolean(context, "kinit", 
 				krb5_principal_get_realm(context, principal), 
 				"krb4_get_tickets", TRUE, &get_v4_tgt);
 #endif
+
     if(do_afslog == -1)
 	krb5_appdefault_boolean(context, "kinit", 
 				krb5_principal_get_realm(context, principal), 
@@ -681,7 +724,7 @@
 #ifdef KRB4
     if(!convert_524)
 #endif
-	get_new_tickets(context, principal, ccache, ticket_life);
+	get_new_tickets(context, principal, ccache, ticket_life, passwd);
 
 #ifdef KRB4
     if(get_v4_tgt)
@@ -689,17 +732,113 @@
 #endif
     if(do_afslog && k_hasafs())
 	krb5_afslog(context, ccache, NULL, NULL);
+
     if(argc > 1) {
-	simple_execvp(argv[1], argv+1);
+      int next_sleep_time = ticket_life / 2;
+
+      if(nofork_flag) {
+	memset(passwd, 0, PASSWD_LEN);
+	execvp(argv[1], argv+1);
+	exit(1);
+      }
+      else if(!fork()) {
+	execvp(argv[1], argv+1);
+	exit(1);
+      }
+
+      while(1) {
+	int rv, status;
+	sigset_t sset;
+	signal(SIGCHLD, sighandler);
+	signal(SIGALRM, sighandler);
+
+	alarm(next_sleep_time);
+
+	sigemptyset(&sset);
+	sigsuspend(&sset);
+
+	if(got_sigchild) {
+	  while(1) {
+	    rv = waitpid(-1, &status, WNOHANG);
+	    if(rv > 0) {
+	      // we only have one child
+	      if(WIFEXITED(status)) {
+		exitcode = WEXITSTATUS(status);
+	      }
+	      else if(WIFSIGNALED(status)) {
+		exitcode = 1;
+	      }
+	      goto done;
+	    }
+	    else if(rv == -1) { 
+	      if(errno == ECHILD) {
+		perror("wait() -- ECHILD");
+		exitcode = 1;
+		goto done;
+	      }
+	      else {
+		exitcode = 1;
+		perror("waitpid");
+		goto done;
+	      }
+	    }
+	    else if(rv == 0) {
+	      // WNOHANG -- no child -- don't do anything
+	      if(debug_flag) {
+		printf("wait -- 0");
+	      }
+	    }
+
+	  }
+	  got_sigchild = 0;
+	}
+
+	if(got_sigalarm) {
+	  if(debug_flag) { printf("getting new tickets... "); }
+
+	  if(get_new_tickets(context, principal, ccache, ticket_life, passwd) != 0) {
+
+	    if(60 < next_sleep_time) {
+	      next_sleep_time = 60;
+	    }
+	    if(debug_flag) { printf("failed.  "); }
+	  }
+	  else {
+
+#ifdef KRB4
+	    if(get_v4_tgt)
+	      do_524init(context, ccache, NULL, server);
+	    if(do_afslog && k_hasafs())
+	      krb5_afslog(context, ccache, NULL, NULL);
+#endif
+
+	    if(debug_flag) { printf("succeeded.  "); }
+	    next_sleep_time = ticket_life / 2;
+	  }
+	  if(debug_flag) { 
+	    printf("Will renew again in %d\n", next_sleep_time); 
+	  }
+	  got_sigalarm = 0;
+	}
+	
+      } // sleep/ticket renew loop
+      
+    done:
 	krb5_cc_destroy(context, ccache);
+	memset(passwd, 0, PASSWD_LEN);  
+
 #ifdef KRB4
 	dest_tkt();
 #endif
 	if(k_hasafs())
 	    k_unlog();
-    } else 
+    } 
+    else { 
 	krb5_cc_close (context, ccache);
+    }
     krb5_free_principal(context, principal);
     krb5_free_context (context);
-    return 0;
+
+
+    exit(exitcode);
 }
Only in /afs/club/system/src/local/heimdal/006/kuser/: kinit.c~
diff -ru heimdal-0.6/kuser/kuser_locl.h /afs/club/system/src/local/heimdal/006/kuser/kuser_locl.h
--- heimdal-0.6/kuser/kuser_locl.h	2003-01-21 09:13:51.000000000 -0500
+++ /afs/club/system/src/local/heimdal/006/kuser/kuser_locl.h	2003-05-16 16:57:04.000000000 -0400
@@ -87,4 +87,7 @@
 #include <kafs.h>
 #include "crypto-headers.h" /* for des_read_pw_string */
 
+#include <sys/types.h>
+#include <sys/wait.h>
+
 #endif /* __KUSER_LOCL_H__ */
Only in /afs/club/system/src/local/heimdal/006/kuser/: kuser_locl.h~