#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <k5-int.h>
#include "com_err.h"
#include "simple.h"
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#define MSG "hi there!"
void usage (char *);
void
usage(name)
char *name;
{
fprintf(stderr, "usage: %s [-p port] [-h host] [-m message] [-s service] [host]\n", name);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int sock, i;
unsigned int len;
int flags = 0;
struct servent *serv;
struct hostent *host;
char *cp;
char full_hname[MAXHOSTNAMELEN];
#ifdef BROKEN_STREAMS_SOCKETS
char my_hostname[MAXHOSTNAMELEN];
#endif
struct sockaddr_in s_sock;
struct sockaddr_in c_sock;
extern int opterr, optind;
extern char * optarg;
int ch;
short port = 0;
char *message = MSG;
char *hostname = 0;
char *service = SIMPLE_SERVICE;
char *progname = 0;
krb5_error_code retval;
krb5_data packet, inbuf;
krb5_ccache ccdef;
krb5_address addr, *portlocal_addr;
krb5_rcache rcache;
krb5_data rcache_name;
krb5_context context;
krb5_auth_context auth_context = NULL;
retval = krb5_init_context(&context);
if (retval) {
com_err(argv[0], retval, "while initializing krb5");
exit(1);
}
progname = argv[0];
opterr = 0;
while ((ch = getopt(argc, argv, "p:m:h:s:")) != -1)
switch (ch) {
case 'p':
port = atoi(optarg);
break;
case 'm':
message = optarg;
break;
case 'h':
hostname = optarg;
break;
case 's':
service = optarg;
break;
case '?':
default:
usage(progname);
exit(1);
break;
}
argc -= optind;
argv += optind;
if (argc > 0) {
if (hostname)
usage(progname);
hostname = argv[0];
}
if (hostname == 0) {
fprintf(stderr, "You must specify a hostname to contact.\n\n");
usage(progname);
exit(1);
}
if ((host = gethostbyname(hostname)) == (struct hostent *) 0) {
fprintf(stderr, "%s: unknown host\n", hostname);
exit(1);
}
strncpy(full_hname, host->h_name, sizeof(full_hname)-1);
full_hname[sizeof(full_hname)-1] = '\0';
for (cp = full_hname; *cp; cp++)
if (isupper((int) *cp))
*cp = tolower((int) *cp);
(void) memset((char *)&s_sock, 0, sizeof(s_sock));
memcpy((char *)&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
#ifdef DEBUG
printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
#endif
s_sock.sin_family = AF_INET;
if (port == 0) {
if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) {
fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT);
exit(1);
}
s_sock.sin_port = serv->s_port;
} else {
s_sock.sin_port = htons(port);
}
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
com_err(progname, errno, "opening datagram socket");
exit(1);
}
memset((char *)&c_sock, 0, sizeof(c_sock));
c_sock.sin_family = AF_INET;
#ifdef BROKEN_STREAMS_SOCKETS
if (gethostname(my_hostname, sizeof(my_hostname)) < 0) {
perror("gethostname");
exit(1);
}
if ((host = gethostbyname(my_hostname)) == (struct hostent *)0) {
fprintf(stderr, "%s: unknown host\n", hostname);
exit(1);
}
memcpy((char *)&c_sock.sin_addr, host->h_addr, sizeof(c_sock.sin_addr));
#endif
if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
com_err(progname, errno, "while binding datagram socket");
exit(1);
}
inbuf.data = hostname;
inbuf.length = strlen(hostname);
if ((retval = krb5_cc_default(context, &ccdef))) {
com_err(progname, retval, "while getting default ccache");
exit(1);
}
if ((retval = krb5_mk_req(context, &auth_context, 0, service, full_hname,
&inbuf, ccdef, &packet))) {
com_err(progname, retval, "while preparing AP_REQ");
exit(1);
}
printf("Got credentials for %s.\n", service);
if (connect(sock, (struct sockaddr *)&s_sock, sizeof(s_sock)) == -1) {
com_err(progname, errno, "while connecting to server");
exit(1);
}
if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
flags)) < 0)
com_err(progname, errno, "while sending KRB_AP_REQ message");
printf("Sent authentication data: %d bytes\n", i);
krb5_free_data_contents(context, &packet);
memset((char *) &c_sock, 0, sizeof(c_sock));
len = sizeof(c_sock);
if (getsockname(sock, (struct sockaddr *)&c_sock, &len) < 0) {
com_err(progname, errno, "while getting socket name");
exit(1);
}
addr.addrtype = ADDRTYPE_IPPORT;
addr.length = sizeof(c_sock.sin_port);
addr.contents = (krb5_octet *)&c_sock.sin_port;
if ((retval = krb5_auth_con_setports(context, auth_context,
&addr, NULL))) {
com_err(progname, retval, "while setting local port\n");
exit(1);
}
addr.addrtype = ADDRTYPE_INET;
addr.length = sizeof(c_sock.sin_addr);
addr.contents = (krb5_octet *)&c_sock.sin_addr;
if ((retval = krb5_auth_con_setaddrs(context, auth_context,
&addr, NULL))) {
com_err(progname, retval, "while setting local addr\n");
exit(1);
}
if ((retval = krb5_gen_portaddr(context, &addr,
(krb5_pointer) &c_sock.sin_port,
&portlocal_addr))) {
com_err(progname, retval, "while generating port address");
exit(1);
}
if ((retval = krb5_gen_replay_name(context,portlocal_addr,
"_sim_clt",&cp))) {
com_err(progname, retval, "while generating replay cache name");
exit(1);
}
rcache_name.length = strlen(cp);
rcache_name.data = cp;
if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) {
com_err(progname, retval, "while getting server rcache");
exit(1);
}
krb5_auth_con_setrcache(context, auth_context, rcache);
inbuf.data = message;
inbuf.length = strlen(message);
if ((retval = krb5_mk_safe(context, auth_context, &inbuf, &packet, NULL))){
com_err(progname, retval, "while making KRB_SAFE message");
exit(1);
}
if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
flags)) < 0)
com_err(progname, errno, "while sending SAFE message");
printf("Sent checksummed message: %d bytes\n", i);
krb5_free_data_contents(context, &packet);
if ((retval = krb5_mk_priv(context, auth_context, &inbuf,
&packet, NULL))) {
com_err(progname, retval, "while making KRB_PRIV message");
exit(1);
}
if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
flags)) < 0)
com_err(progname, errno, "while sending PRIV message");
printf("Sent encrypted message: %d bytes\n", i);
krb5_free_data_contents(context, &packet);
krb5_auth_con_free(context, auth_context);
krb5_free_context(context);
exit(0);
}