#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "k5-int.h"
#include "com_err.h"
int main (argc, argv)
int argc;
char *argv[];
{
int s;
register int retval, i;
char *hname;
char **srealms;
char *princ;
struct servent *serv;
struct hostent *host;
struct sockaddr_in serv_net_addr, cli_net_addr;
krb5_ccache cc;
krb5_creds creds, *new_creds;
krb5_data reply, msg, princ_data;
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
krb5_context context;
unsigned short port;
if (argc < 2 || argc > 4) {
fputs ("usage: uu-client <hostname> [message [port]]\n", stderr);
return 1;
}
retval = krb5_init_context(&context);
if (retval) {
com_err(argv[0], retval, "while initializing krb5");
exit(1);
}
if (argc == 4) {
port = htons(atoi(argv[3]));
}
else if ((serv = getservbyname ("uu-sample", "tcp")) == NULL)
{
fputs ("uu-client: unknown service \"uu-sample/tcp\"\n", stderr);
return 2;
} else {
port = serv->s_port;
}
if ((host = gethostbyname (argv[1])) == NULL) {
fprintf (stderr, "uu-client: can't get address of host \"%s\".\n",
argv[1]);
return 3;
}
if (host->h_addrtype != AF_INET) {
fprintf (stderr, "uu-client: bad address type %d for \"%s\".\n",
host->h_addrtype, argv[1]);
return 3;
}
hname = strdup (host->h_name);
#ifndef USE_STDOUT
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
com_err ("uu-client", errno, "creating socket");
return 4;
} else {
cli_net_addr.sin_family = AF_INET;
cli_net_addr.sin_port = 0;
cli_net_addr.sin_addr.s_addr = 0;
if (bind (s, (struct sockaddr *)&cli_net_addr,
sizeof (cli_net_addr)) < 0) {
com_err ("uu-client", errno, "binding socket");
return 4;
}
}
serv_net_addr.sin_family = AF_INET;
serv_net_addr.sin_port = port;
i = 0;
while (1) {
if (host->h_addr_list[i] == 0) {
fprintf (stderr, "uu-client: unable to connect to \"%s\"\n", hname);
return 5;
}
memcpy ((char *)&serv_net_addr.sin_addr, host->h_addr_list[i++],
sizeof(serv_net_addr.sin_addr));
if (connect(s, (struct sockaddr *)&serv_net_addr,
sizeof (serv_net_addr)) == 0)
break;
com_err ("uu-client", errno, "connecting to \"%s\" (%s).",
hname, inet_ntoa(serv_net_addr.sin_addr));
}
#else
s = 1;
#endif
retval = krb5_cc_default(context, &cc);
if (retval) {
com_err("uu-client", retval, "getting credentials cache");
return 6;
}
memset ((char*)&creds, 0, sizeof(creds));
retval = krb5_cc_get_principal(context, cc, &creds.client);
if (retval) {
com_err("uu-client", retval, "getting principal name");
return 6;
}
retval = krb5_unparse_name(context, creds.client, &princ);
if (retval) {
com_err("uu-client", retval, "printing principal name");
return 7;
}
else
fprintf(stderr, "uu-client: client principal is \"%s\".\n", princ);
retval = krb5_get_host_realm(context, hname, &srealms);
if (retval) {
com_err("uu-client", retval, "getting realms for \"%s\"", hname);
return 7;
}
retval =
krb5_build_principal_ext(context, &creds.server,
krb5_princ_realm(context, creds.client)->length,
krb5_princ_realm(context, creds.client)->data,
6, "krbtgt",
krb5_princ_realm(context, creds.client)->length,
krb5_princ_realm(context, creds.client)->data,
0);
if (retval) {
com_err("uu-client", retval, "setting up tgt server name");
return 7;
}
retval = krb5_get_credentials(context, KRB5_GC_CACHED, cc,
&creds, &new_creds);
if (retval) {
com_err("uu-client", retval, "getting TGT");
return 6;
}
i = strlen(princ) + 1;
fprintf(stderr, "uu-client: sending %d bytes\n",new_creds->ticket.length + i);
princ_data.data = princ;
princ_data.length = i;
retval = krb5_write_message(context, (krb5_pointer) &s, &princ_data);
if (retval) {
com_err("uu-client", retval, "sending principal name to server");
return 8;
}
free(princ);
retval = krb5_write_message(context, (krb5_pointer) &s, &new_creds->ticket);
if (retval) {
com_err("uu-client", retval, "sending ticket to server");
return 8;
}
retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
if (retval) {
com_err("uu-client", retval, "reading reply from server");
return 9;
}
retval = krb5_auth_con_init(context, &auth_context);
if (retval) {
com_err("uu-client", retval, "initializing the auth_context");
return 9;
}
retval =
krb5_auth_con_genaddrs(context, auth_context, s,
KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
if (retval) {
com_err("uu-client", retval, "generating addrs for auth_context");
return 9;
}
retval = krb5_auth_con_setflags(context, auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE);
if (retval) {
com_err("uu-client", retval, "initializing the auth_context flags");
return 9;
}
retval = krb5_auth_con_setuseruserkey(context, auth_context,
&new_creds->keyblock);
if (retval) {
com_err("uu-client", retval, "setting useruserkey for authcontext");
return 9;
}
#if 1
retval = krb5_rd_req(context, &auth_context, &reply,
NULL, NULL, NULL, &ticket);
free(reply.data);
#else
retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&s, "???",
0, , 0, NULL, &ticket);
#endif
if (retval) {
com_err("uu-client", retval, "reading AP_REQ from server");
return 9;
}
retval = krb5_unparse_name(context, ticket->enc_part2->client, &princ);
if (retval)
com_err("uu-client", retval, "while unparsing client name");
else {
printf("server is named \"%s\"\n", princ);
free(princ);
}
retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
if (retval) {
com_err("uu-client", retval, "reading reply from server");
return 9;
}
retval = krb5_rd_safe(context, auth_context, &reply, &msg, NULL);
if (retval) {
com_err("uu-client", retval, "decoding reply from server");
return 10;
}
printf ("uu-client: server says \"%s\".\n", msg.data);
return 0;
}