freebsd-dev/eBones/lib/librkinit/rk_rpc.c
Justin T. Gibbs f4390542d7 Kerberos can now deal with multi-homed clients.
Kerberos obtains a network address for the local host from the routing
tables and uses it consistently for all Kerberos transactions.  This ensures
that packets only leave the *authenticated* interface.  Clients who open
and use their own sockets for encrypted or authenticated correspondance
to kerberos services should bind their sockets to the same address as that
used by kerberos.  krb_get_local_addr() and krb_bind_local_addr() allow
clients to obtain the local address or bind a socket to the local address
used by Kerberos respectively.

Reviewed by: Mark Murray <markm>, Garrett Wollman <wollman>
Obtained from: concept by Dieter Dworkin Muller <dworkin@village.org>
1995-10-05 21:30:21 +00:00

393 lines
9.2 KiB
C

/*
* $Id: rk_rpc.c,v 1.1.1.1 1995/09/15 06:09:30 gibbs Exp $
* $Source: /home/ncvs/src/eBones/lib/librkinit/rk_rpc.c,v $
* $Author: gibbs $
*
* This file contains functions that are used for network communication.
* See the comment at the top of rk_lib.c for a description of the naming
* conventions used within the rkinit library.
*/
#if !defined(lint) && !defined(SABER) && !defined(LOCORE) && defined(RCS_HDRS)
static char *rcsid = "$Id: rk_rpc.c,v 1.1.1.1 1995/09/15 06:09:30 gibbs Exp $";
#endif /* lint || SABER || LOCORE || RCS_HDRS */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <rkinit.h>
#include <rkinit_err.h>
#include <rkinit_private.h>
extern int errno;
static int sock;
struct sockaddr_in saddr;
static char errbuf[BUFSIZ];
char *calloc();
#ifdef __STDC__
int rki_send_packet(int sock, char type, u_int32_t length, const char *data)
#else
int rki_send_packet(sock, type, length, data)
int sock;
char type;
u_int32_t length;
const char *data;
#endif /* __STDC__ */
{
int len;
u_char *packet;
u_int32_t pkt_len;
u_int32_t net_pkt_len;
pkt_len = length + PKT_DATA;
if ((packet = (u_char *)calloc(pkt_len, sizeof(u_char))) == NULL) {
sprintf(errbuf, "rki_send_packet: failure allocating %d bytes",
pkt_len * sizeof(u_char));
rkinit_errmsg(errbuf);
return(RKINIT_MEMORY);
}
net_pkt_len = htonl(pkt_len);
packet[PKT_TYPE] = type;
bcopy((char *)&net_pkt_len, packet + PKT_LEN, sizeof(u_int32_t));
bcopy(data, packet + PKT_DATA, length);
if ((len = write(sock, packet, pkt_len)) != pkt_len) {
if (len == -1)
sprintf(errbuf, "write: %s", sys_errlist[errno]);
else
sprintf(errbuf, "write: %d bytes written; %d bytes actually sent",
pkt_len, len);
rkinit_errmsg(errbuf);
free(packet);
return(RKINIT_WRITE);
}
free(packet);
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
int rki_get_packet(int sock, u_char type, u_int32_t *length, char *data)
#else
int rki_get_packet(sock, type, length, data)
int sock;
u_char type;
u_int32_t *length;
char *data;
#endif /* __STDC__ */
{
int len;
int len_sofar = 0;
u_int32_t expected_length = 0;
int got_full_packet = FALSE;
int tries = 0;
u_char *packet;
u_int32_t max_pkt_len;
max_pkt_len = *length + PKT_DATA;
if ((packet = (u_char *)calloc(max_pkt_len, sizeof(u_char))) == NULL) {
sprintf(errbuf, "rki_get_packet: failure allocating %d bytes",
max_pkt_len * sizeof(u_char));
rkinit_errmsg(errbuf);
return(RKINIT_MEMORY);
}
/* Read the packet type and length */
while ((len_sofar < PKT_DATA) && (tries < RETRIES)) {
if ((len = read(sock, packet + len_sofar, PKT_DATA - len_sofar)) < 0) {
sprintf(errbuf, "read: %s", sys_errlist[errno]);
rkinit_errmsg(errbuf);
return(RKINIT_READ);
}
len_sofar += len;
tries++;
}
if (len_sofar < PKT_DATA) {
sprintf(errbuf,
"read: expected to receive at least %d bytes; received %d",
PKT_DATA, len_sofar);
rkinit_errmsg(errbuf);
return(RKINIT_PACKET);
}
bcopy(packet + PKT_LEN, (char *)&expected_length, sizeof(u_int32_t));
expected_length = ntohl(expected_length);
if (expected_length > max_pkt_len) {
sprintf(errbuf, "%s %d %s %d",
"rki_get_packet: incoming message of size",
expected_length,
"is larger than message buffer of size",
max_pkt_len);
rkinit_errmsg(errbuf);
return(RKINIT_PACKET);
}
tries = 0;
while (!got_full_packet && (tries < RETRIES)) {
if ((len = read(sock, packet + len_sofar,
expected_length - len_sofar)) < 0) {
sprintf(errbuf, "read: %s", sys_errlist[errno]);
rkinit_errmsg(errbuf);
return(RKINIT_READ);
}
len_sofar += len;
if (expected_length == len_sofar)
got_full_packet = TRUE;
}
if (len_sofar < expected_length) {
sprintf(errbuf,
"read: expected to receive at least %d bytes; received %d",
expected_length, len_sofar);
rkinit_errmsg(errbuf);
return(RKINIT_PACKET);
}
if (packet[PKT_TYPE] == MT_DROP) {
BCLEAR(errbuf);
rkinit_errmsg(errbuf);
return(RKINIT_DROPPED);
}
if (packet[PKT_TYPE] != type) {
sprintf(errbuf, "Expected packet type of %s; got %s",
rki_mt_to_string(type),
rki_mt_to_string(packet[PKT_TYPE]));
rkinit_errmsg(errbuf);
return(RKINIT_PACKET);
}
*length = len_sofar - PKT_DATA;
bcopy(packet + PKT_DATA, data, *length);
free(packet);
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
int rki_setup_rpc(char *host)
#else
int rki_setup_rpc(host)
char *host;
#endif /* __STDC__ */
{
struct hostent *hp;
struct servent *sp;
int port, retval;
SBCLEAR(saddr);
SBCLEAR(hp);
SBCLEAR(sp);
if ((hp = gethostbyname(host)) == NULL) {
sprintf(errbuf, "%s: unknown host.", host);
rkinit_errmsg(errbuf);
return(RKINIT_HOST);
}
if ((sp = getservbyname(SERVENT, "tcp")))
port = sp->s_port;
else
/* Fall back on known port number */
port = htons(PORT);
saddr.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (char *)&saddr.sin_addr, hp->h_length);
saddr.sin_port = port;
if ((sock = socket(hp->h_addrtype, SOCK_STREAM, IPPROTO_IP)) < 0) {
sprintf(errbuf, "socket: %s", sys_errlist[errno]);
rkinit_errmsg(errbuf);
return(RKINIT_SOCKET);
}
if ((retval = krb_bind_local_addr(sock)) != KSUCCESS) {
sprintf(errbuf, "krb_bind_local_addr: %s", krb_err_txt[retval]);
rkinit_errmsg(errbuf);
close(sock);
return(RKINIT_SOCKET);
}
if (connect(sock, (struct sockaddr *)&saddr, sizeof (saddr)) < 0) {
sprintf(errbuf, "connect: %s", sys_errlist[errno]);
rkinit_errmsg(errbuf);
close(sock);
return(RKINIT_CONNECT);
}
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
int rki_rpc_exchange_version_info(int c_lversion, int c_hversion,
int *s_lversion, int *s_hversion)
#else
int rki_rpc_exchange_version_info(c_lversion, c_hversion,
s_lversion, s_hversion)
int c_lversion;
int c_hversion;
int *s_lversion;
int *s_hversion;
#endif /* __STDC__ */
{
int status = RKINIT_SUCCESS;
u_char version_info[VERSION_INFO_SIZE];
u_int32_t length = sizeof(version_info);
version_info[0] = (u_char) c_lversion;
version_info[1] = (u_char) c_hversion;
if ((status = rki_send_packet(sock, MT_CVERSION, length,
(char *)version_info)) != RKINIT_SUCCESS)
return(status);
if ((status = rki_get_packet(sock, MT_SVERSION, &length,
(char *)version_info)) != RKINIT_SUCCESS)
return(status);
*s_lversion = (int) version_info[0];
*s_hversion = (int) version_info[1];
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
int rki_rpc_send_rkinit_info(rkinit_info *info)
#else
int rki_rpc_send_rkinit_info(info)
rkinit_info *info;
#endif /* __STDC__ */
{
rkinit_info info_copy;
bcopy(info, &info_copy, sizeof(rkinit_info));
info_copy.lifetime = htonl(info_copy.lifetime);
return(rki_send_packet(sock, MT_RKINIT_INFO, sizeof(rkinit_info),
(char *)&info_copy));
}
#ifdef __STDC__
int rki_rpc_get_status(void)
#else
int rki_rpc_get_status()
#endif /* __STDC__ */
{
char msg[BUFSIZ];
int status = RKINIT_SUCCESS;
u_int32_t length = sizeof(msg);
if ((status = rki_get_packet(sock, MT_STATUS, &length, msg)))
return(status);
if (length == 0)
return(RKINIT_SUCCESS);
else {
rkinit_errmsg(msg);
return(RKINIT_DAEMON);
}
}
#ifdef __STDC__
int rki_rpc_get_ktext(int sock, KTEXT auth, u_char type)
#else
int rki_rpc_get_ktext(sock, auth, type)
int sock;
KTEXT auth;
u_char type;
#endif /* __STDC__ */
{
int status = RKINIT_SUCCESS;
u_int32_t length = MAX_KTXT_LEN;
if ((status = rki_get_packet(sock, type, &length, (char *)auth->dat)))
return(status);
auth->length = length;
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
int rki_rpc_sendauth(KTEXT auth)
#else
int rki_rpc_sendauth(auth)
KTEXT auth;
#endif /* __STDC__ */
{
return(rki_send_packet(sock, MT_AUTH, auth->length, (char *)auth->dat));
}
#ifdef __STDC__
int rki_rpc_get_skdc(KTEXT scip)
#else
int rki_rpc_get_skdc(scip)
KTEXT scip;
#endif /* __STDC__ */
{
return(rki_rpc_get_ktext(sock, scip, MT_SKDC));
}
#ifdef __STDC__
int rki_rpc_send_ckdc(MSG_DAT *scip)
#else
int rki_rpc_send_ckdc(scip)
MSG_DAT *scip;
#endif /* __STDC__ */
{
return(rki_send_packet(sock, MT_CKDC, scip->app_length,
(char *)scip->app_data));
}
#ifdef __STDC__
int rki_get_csaddr(struct sockaddr_in *caddrp, struct sockaddr_in *saddrp)
#else
int rki_get_csaddr(caddrp, saddrp)
struct sockaddr_in *caddrp;
struct sockaddr_in *saddrp;
#endif /* __STDC__ */
{
int addrlen = sizeof(struct sockaddr_in);
bcopy((char *)&saddr, (char *)saddrp, addrlen);
if (getsockname(sock, (struct sockaddr *)caddrp, &addrlen) < 0) {
sprintf(errbuf, "getsockname: %s", sys_errlist[errno]);
rkinit_errmsg(errbuf);
return(RKINIT_GETSOCK);
}
return(RKINIT_SUCCESS);
}
#ifdef __STDC__
void rki_drop_server(void)
#else
void rki_drop_server()
#endif /* __STDC__ */
{
(void) rki_send_packet(sock, MT_DROP, 0, "");
}
#ifdef __STDC__
void rki_cleanup_rpc(void)
#else
void rki_cleanup_rpc()
#endif /* __STDC__ */
{
rki_drop_server();
(void) close(sock);
}