/* ckinit.c -- This source file is for ckinit, a charon initialization
 * program that uses /dev/tty as the I/O stream.  It is used to get
 * new kerberos tickets while someone is already logged in using the
 * charon protocol.
 *
 * Created by:	Derek Atkins <warlord@MIT.EDU>
 *
 * $Source: /afs/net.mit.edu/user/warlord/Thesis/src/ckinit/RCS/ckinit.c,v $
 * $Author: warlord $
 *
 */

#include <warlord-copyright.h>

#if !defined(lint) && !defined(SABER)
static char ckinit_c[] = "$Id: ckinit.c,v 1.10 93/12/11 15:10:21 warlord Exp $";
#endif

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <pwd.h>
#include <krb.h>
#include <charon.h>

#if defined(sun) && defined(sparc) && defined(POSIX) /* SOLARIS */
#define ZERO(a,l) memset((char *)(a), 0, (l))
#else
#define ZERO(a,l) bzero((char *)(a), (l))
#endif

static void *tty_state = NULL;
extern char *getenv();

static void 
usage(char *whoami)
{
  fprintf(stderr, "Usage: %s [-k realm_of_host] [-p principal]\n", whoami);
  fprintf(stderr, "\t[-f ticket_file] [-l lifetime]\n");
  
  exit(1);
}

/* If we get a signal, we should do this, so that we can exit
 * cleanly.
 */
int
error_exit()
{
  crn_revert_echo(tty_state);
  exit(1);
}

/* I should mention that a lot of this is based off of rkinit!
 *
 * Effects:	Get kerberos tickets for a user!  Possible options to
 *		this program include:
 *
 *	-k == set the kerberos realm of this host
 *	-p == set kerberos principal (of form princ.inst@realm)
 *	-f == ticket file to store tickets
 *	-l == ticket lifetime
 *
 *		If no principal is passed in, then look in the ticket
 *		file for a name.  If not there, then use username
 *		and NULL instance, and host-realm.
 *
 *		Use default lifetime if none is specified.
 */
main(int argc, char *argv[])
{
  char *whoami;			/* program name. */

  char principal[MAX_K_NAME_SZ]; /* principal name */
  char a_name[ANAME_SZ];	/* These are principal, */
  char inst[INST_SZ];		/* instance, and the */
  char realm[REALM_SZ];		/* realm to use for tickets */
  char hostrealm[REALM_SZ];	/* realm of host */
  char *debug_file = NULL;	/* place to put debug info */
  
  char *ticketfile = NULL;	/* ticket file name */
  int lifetime = DEFAULT_TKT_LIFE; /* ticket lifetime */
  int i, status = 0;
  struct passwd *pwd;		/* local passwd info */

  /* Clear out these buffers */
  ZERO(principal, sizeof(principal));
  ZERO(a_name, sizeof(a_name));
  ZERO(inst, sizeof(inst));
  ZERO(realm, sizeof(realm));
  ZERO(realm, sizeof(hostrealm));

  /* Set the program name. */
  if ((whoami = strrchr(argv[0], '/')) == NULL)
    whoami = argv[0];
  else
    whoami++;

  /* Deal with the command-line options */
  for (i = 1; i < argc; i++) {

    /* make sure that its an option! */
    if (argv[i][0] != '-')
      usage(whoami);

    switch(argv[i][1]) {

    case 'k':			/* realm */
      if (++i >= argc)
	usage(whoami);
      strncpy(hostrealm, argv[i], sizeof(hostrealm) -1);
      break;

    case 'p':			/* principal */
      if (++i >= argc)
	usage(whoami);
      strncpy(principal, argv[i], sizeof(principal) -1);
      break;

    case 'f':			/* ticket file */
      if (++i >= argc)
	usage(whoami);
      ticketfile = argv[i];
      break;

    case 'l':			/* lifetime */
      if (++i >= argc)
	usage(whoami);
      lifetime = atoi(argv[i])/5;
      if (lifetime = 0)
	lifetime = 1;
      else if (lifetime > 255)
	lifetime = 255;
      break;

    case 'd':			/* debug */
      if (++i >= argc)
	usage(whoami);
      debug_file = argv[i];
      break;

    default:
      usage(whoami);
    } /* switch */
  } /* for */

  if ((pwd = getpwuid(getuid())) == NULL) {
    fprintf(stderr, "%s: Cannot find your entry in the password file.\n");
    exit(1);
  }

  /* Make sure we have an a_name, inst, and realm to pass in.
   * (we really only need an a_name, since the library will deal
   * with everything else.
   */
  if (! principal[0]) {

    /* No principal passed in -- look in ticket file */
    if ((status = krb_get_tf_fullname(TKT_FILE, a_name, inst, realm))
      != KSUCCESS) {
      /* No ticket file.  use username@hostrealm */
      strncpy(a_name, pwd->pw_name, sizeof(a_name) - 1);
      strcpy(realm, hostrealm);
    }
  } else {
    if ((status = kname_parse(a_name, inst, realm, principal))
	!= KSUCCESS) {
      fprintf(stderr, "%s: %s\n", whoami, krb_err_txt[status]);
      exit(1);
    }
  }

  tty_state = crn_kill_echo(0);

  /* trap a lot of signals */
  signal(SIGHUP, error_exit);
  signal(SIGINT, error_exit);
  signal(SIGQUIT, error_exit);
  signal(SIGKILL, error_exit);
  signal(SIGTERM, error_exit);

  if (debug_file != NULL)
    crn_rpc_set_debug_file(debug_file);

  status = crn_srv_get_tickets(a_name, inst, realm, hostrealm,
			       lifetime, ticketfile, 0, 0, 0);

  crn_revert_echo(tty_state);

  return(status);
}
