/*
 *
 * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information,
 * please see the file <mit-copyright.h>.
 *
 * sample_client:
 * A sample Kerberos client, which connects to a server on a remote host,
 * at port "sample" (be sure to define it in /etc/services)
 * and authenticates itself to the server. The server then writes back
 * (in ASCII) the authenticated name.
 *
 * Usage:
 * sample_client <hostname> <checksum>
 *
 * <hostname> is the name of the foreign host to contact.
 *
 * <checksum> is an integer checksum to be used for the call to krb_mk_req()
 *	and mutual authentication
 *
 */

#include "sample.h"

RCSID("$Id: sample_client.c,v 1.13 1998/05/01 05:20:43 assar Exp $");

static void
usage (void)
{
  fprintf (stderr, "Usage: %s [-s service] [-p port] hostname checksum\n",
	   __progname);
  exit (1);
}

int
main(int argc, char **argv)
{
    struct hostent *hp;
    struct sockaddr_in sin, lsin;
    char *remote_host;
    int status;
    int sock, namelen;
    KTEXT_ST ticket;
    char buf[512];
    long authopts;
    MSG_DAT msg_data;
    CREDENTIALS cred;
    des_key_schedule sched;
    u_int32_t cksum;
    int c;
    char service[SNAME_SZ];
    char *p;
    u_int16_t port;
    struct servent *serv;

    set_progname (argv[0]);
    strcpy (service, SAMPLE_SERVICE);
    port = 0;

    while ((c = getopt(argc, argv, "s:p:")) != EOF)
	switch(c) {
	case 's' :
	    strncpy (service, optarg, sizeof(service));
	    break;
	case 'p' :
	    serv = getservbyname (optarg, "tcp");
	    if (serv)
		port = serv->s_port;
	    else
		port = htons(atoi(optarg));
	    break;
	case '?' :
	default :
	    usage();
	}

    argc -= optind;
    argv += optind;

    if (argc != 2)
	usage ();
    
    /* convert cksum to internal rep */
    cksum = atoi(argv[1]);

    printf("Setting checksum to %ld\n", (long)cksum);

    /* clear out the structure first */
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    if (port)
	sin.sin_port = port;
    else
	sin.sin_port = k_getportbyname (service, "tcp", htons(SAMPLE_PORT));

    /* look up the server host */
    hp = gethostbyname(argv[0]);
    if (hp == NULL)
	errx (1, "gethostbyname(%s): %s", argv[0],
	      hstrerror(h_errno));

    /* copy the hostname into non-volatile storage */
    remote_host = strdup(hp->h_name);
    if (remote_host == NULL)
	errx (1, "strdup: out of memory");

    /* set up the address of the foreign socket for connect() */
    sin.sin_family = hp->h_addrtype;

    while ((p = *(hp->h_addr_list++))) {
	memcpy(&sin.sin_addr, p, sizeof(sin.sin_addr));
	fprintf (stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));

	/* open a TCP socket */
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	    err (1, "socket");

	/* connect to the server */
	if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
	    break;
	close (sock);
    }

    if (p == NULL)
	err (1, "connect");

    /* find out who I am, now that we are connected and therefore bound */
    namelen = sizeof(lsin);
    if (getsockname(sock, (struct sockaddr *) &lsin, &namelen) < 0) {
	close (sock);
	err (1, "getsockname");
    }

    /* call Kerberos library routine to obtain an authenticator,
       pass it over the socket to the server, and obtain mutual
       authentication. */

    authopts = KOPT_DO_MUTUAL;
    status = krb_sendauth(authopts, sock, &ticket,
			  service, remote_host,
			  NULL, cksum, &msg_data, &cred,
			  sched, &lsin, &sin, SAMPLE_VERSION);
    if (status != KSUCCESS)
	errx (1, "cannot authenticate to server: %s",
	      krb_get_err_text(status));

    /* After we send the authenticator to the server, it will write
       back the name we authenticated to. Read what it has to say. */
    status = read(sock, buf, sizeof(buf));
    if (status < 0)
	errx(1, "read");

    /* make sure it's null terminated before printing */
    if (status < sizeof(buf))
	buf[status] = '\0';
    else
	buf[sizeof(buf) - 1] = '\0';

    printf("The server says:\n%s\n", buf);

    close(sock);
    return 0;
}
