#include "krb5.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "com_err.h"
#include "simple.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#define PROGNAME argv[0]
static void
usage(name)
char *name;
{
fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n", name);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int sock, i;
unsigned int len;
int flags = 0;
int on = 1;
struct servent *serv;
struct hostent *host;
struct sockaddr_in s_sock;
struct sockaddr_in c_sock;
char full_hname[MAXHOSTNAMELEN];
char *cp;
extern int opterr, optind;
extern char * optarg;
int ch;
short port = 0;
krb5_keytab keytab = NULL;
char *service = SIMPLE_SERVICE;
krb5_error_code retval;
krb5_data packet, message;
unsigned char pktbuf[BUFSIZ];
krb5_principal sprinc;
krb5_context context;
krb5_auth_context auth_context = NULL;
krb5_address addr;
krb5_ticket *ticket = NULL;
retval = krb5_init_context(&context);
if (retval) {
com_err(argv[0], retval, "while initializing krb5");
exit(1);
}
opterr = 0;
while ((ch = getopt(argc, argv, "p:s:S:")) != -1)
switch (ch) {
case 'p':
port = atoi(optarg);
break;
case 's':
service = optarg;
break;
case 'S':
if ((retval = krb5_kt_resolve(context, optarg, &keytab))) {
com_err(PROGNAME, retval,
"while resolving keytab file %s", optarg);
exit(2);
}
break;
case '?':
default:
usage(PROGNAME);
exit(1);
break;
}
if ((retval = krb5_sname_to_principal(context, NULL, service,
KRB5_NT_SRV_HST, &sprinc))) {
com_err(PROGNAME, retval, "while generating service name %s", service);
exit(1);
}
memset((char *)&s_sock, 0, sizeof(s_sock));
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 (gethostname(full_hname, sizeof(full_hname)) < 0) {
perror("gethostname");
exit(1);
}
if ((host = gethostbyname(full_hname)) == (struct hostent *)0) {
fprintf(stderr, "%s: host unknown\n", full_hname);
exit(1);
}
memcpy((char *)&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("opening datagram socket");
exit(1);
}
(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
sizeof(on));
if (bind(sock, (struct sockaddr *)&s_sock, sizeof(s_sock))) {
perror("binding datagram socket");
exit(1);
}
#ifdef DEBUG
printf("socket has port # %d\n", ntohs(s_sock.sin_port));
#endif
len = sizeof(struct sockaddr_in);
if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
(struct sockaddr *)&c_sock, &len)) < 0) {
perror("receiving datagram");
exit(1);
}
printf("Received %d bytes\n", i);
packet.length = i;
packet.data = (krb5_pointer) pktbuf;
if ((retval = krb5_rd_req(context, &auth_context, &packet,
sprinc, keytab, NULL, &ticket))) {
com_err(PROGNAME, retval, "while reading request");
exit(1);
}
if ((retval = krb5_unparse_name(context, ticket->enc_part2->client,
&cp))) {
com_err(PROGNAME, retval, "while unparsing client name");
exit(1);
}
printf("Got authentication info from %s\n", cp);
free(cp);
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,
NULL, &addr))) {
com_err(PROGNAME, retval, "while setting foreign addr");
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,
NULL, &addr))) {
com_err(PROGNAME, retval, "while setting foreign port");
exit(1);
}
len = sizeof(struct sockaddr_in);
if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
(struct sockaddr *)&c_sock, &len)) < 0) {
perror("receiving datagram");
exit(1);
}
#ifdef DEBUG
printf("&c_sock.sin_addr is %s\n", inet_ntoa(c_sock.sin_addr));
#endif
printf("Received %d bytes\n", i);
packet.length = i;
packet.data = (krb5_pointer) pktbuf;
if ((retval = krb5_rd_safe(context, auth_context, &packet,
&message, NULL))) {
com_err(PROGNAME, retval, "while verifying SAFE message");
exit(1);
}
printf("Safe message is: '%.*s'\n", (int) message.length, message.data);
krb5_free_data_contents(context, &message);
len = sizeof(struct sockaddr_in);
if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
(struct sockaddr *)&c_sock, &len)) < 0) {
perror("receiving datagram");
exit(1);
}
printf("Received %d bytes\n", i);
packet.length = i;
packet.data = (krb5_pointer) pktbuf;
if ((retval = krb5_rd_priv(context, auth_context, &packet,
&message, NULL))) {
com_err(PROGNAME, retval, "while verifying PRIV message");
exit(1);
}
printf("Decrypted message is: '%.*s'\n", (int) message.length,
message.data);
krb5_auth_con_free(context, auth_context);
krb5_free_context(context);
exit(0);
}