* $Source: /usr/src/kerberosIV/krb/RCS/send_to_kdc.c,v $
* Copyright 1987, 1988 by the Massachusetts Institute of Technology.
* For copying and distribution information, please see the file
static char rcsid_send_to_kdc_c
[] =
"$Id: send_to_kdc.c,v 4.21 90/06/25 20:57:21 kfall Exp $";
#include <mit-copyright.h>
#include <sys/uio.h> /* struct iovec to make lint happy */
#define S_AD_SZ sizeof(struct sockaddr_in)
extern char *malloc(), *calloc(), *realloc();
/* CLIENT_KRB_TIMEOUT indicates the time to wait before
* retrying a server. It's defined in "krb.h".
static struct timeval timeout
= { CLIENT_KRB_TIMEOUT
, 0};
static char *prog
= "send_to_kdc";
* This file contains two routines, send_to_kdc() and send_recv().
* send_recv() is a static routine used by send_to_kdc().
* send_to_kdc() sends a message to the Kerberos authentication
* server(s) in the given realm and returns the reply message.
* The "pkt" argument points to the message to be sent to Kerberos;
* the "rpkt" argument will be filled in with Kerberos' reply.
* The "realm" argument indicates the realm of the Kerberos server(s)
* to transact with. If the realm is null, the local realm is used.
* If more than one Kerberos server is known for a given realm,
* different servers will be queried until one of them replies.
* Several attempts (retries) are made for each server before
* If an answer was received from a Kerberos host, KSUCCESS is
* returned. The following errors can be returned:
* SKDC_CANT - can't get local realm
* - can't find "kerberos" in /etc/services database
* - couldn't find any Kerberos host
* SKDC_RETRY - couldn't get an answer from any Kerberos server,
send_to_kdc(pkt
,rpkt
,realm
)
int no_host
; /* was a kerberos host found? */
struct hostent
*host
, *hostlist
;
* If "realm" is non-null, use that, otherwise get the
(void) strcpy(lrealm
, realm
);
if (krb_get_lrealm(lrealm
,1)) {
fprintf(stderr
, "%s: can't get local realm\n", prog
);
printf("lrealm is %s\n", lrealm
);
register struct servent
*sp
;
if ((sp
= getservbyname("kerberos","udp")) == 0) {
fprintf(stderr
, "%s: Can't get kerberos/udp service\n",
krb_udp_port
= sp
->s_port
;
printf("krb_udp_port is %d\n", krb_udp_port
);
bzero((char *)&to
, S_AD_SZ
);
hostlist
= (struct hostent
*) malloc(sizeof(struct hostent
));
return (/*errno */SKDC_CANT
);
if ((f
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
fprintf(stderr
,"%s: Can't open socket\n", prog
);
/* from now on, exit through rtn label for cleanup */
/* get an initial allocation */
for (i
= 1; krb_get_krbhst(krbhst
, lrealm
, i
) == KSUCCESS
; ++i
) {
printf("Getting host entry for %s...",krbhst
);
host
= gethostbyname(krbhst
);
host
? "Got it" : "Didn't get it");
no_host
= 0; /* found at least one */
/* preserve host network address to check later
* (would be better to preserve *all* addresses,
* take care of that later)
hostlist
= (struct hostent
*)
realloc((char *)hostlist
,
sizeof(struct hostent
)*(n_hosts
+1));
return /*errno */SKDC_CANT
;
bcopy((char *)host
, (char *)&hostlist
[n_hosts
-1],
host
= &hostlist
[n_hosts
-1];
cp
= malloc((unsigned)host
->h_length
);
retval
= /*errno */SKDC_CANT
;
bcopy((char *)host
->h_addr
, cp
, host
->h_length
);
/* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2
(or worse) only return one name ... */
#if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
host
->h_addr_list
= (char **)malloc(sizeof(char *));
if (!host
->h_addr_list
) {
retval
= /*errno */SKDC_CANT
;
#endif /* ULTRIX022 || SunOS */
bzero((char *)&hostlist
[n_hosts
],
to
.sin_family
= host
->h_addrtype
;
bcopy(host
->h_addr
, (char *)&to
.sin_addr
,
to
.sin_port
= krb_udp_port
;
if (send_recv(pkt
, rpkt
, f
, &to
, hostlist
)) {
printf("Timeout, error, or wrong descriptor\n");
fprintf(stderr
, "%s: can't find any Kerberos host.\n",
/* retry each host in sequence */
for (retry
= 0; retry
< CLIENT_KRB_RETRY
; ++retry
) {
for (host
= hostlist
; host
->h_name
!= (char *)NULL
; host
++) {
to
.sin_family
= host
->h_addrtype
;
bcopy(host
->h_addr
, (char *)&to
.sin_addr
,
if (send_recv(pkt
, rpkt
, f
, &to
, hostlist
)) {
register struct hostent
*hp
;
for (hp
= hostlist
; hp
->h_name
; hp
++)
#if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
#endif /* ULTRIX022 || SunOS */
#if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40))
free((char *)hp
->h_addr_list
);
#endif /* ULTRIX022 || SunOS */
* try to send out and receive message.
* return 1 on success, 0 on failure
static send_recv(pkt
,rpkt
,f
,_to
,addrs
)
register struct hostent
*hp
;
if (_to
->sin_family
== AF_INET
)
printf("Sending message to %s...",
inet_ntoa(_to
->sin_addr
));
printf("Sending message...");
if ((numsent
= sendto(f
,(char *)(pkt
->dat
), pkt
->length
, 0,
S_AD_SZ
)) != pkt
->length
) {
printf("sent only %d/%d\n",numsent
, pkt
->length
);
printf("Sent\nWaiting for reply...");
/* select - either recv is ready, or timeout */
/* see if timeout or error or wrong descriptor */
if (select(f
+ 1, &readfds
, (fd_set
*)0, (fd_set
*)0, &timeout
) < 1
|| !FD_ISSET(f
, &readfds
)) {
fprintf(stderr
, "select failed: readfds=%x",
if (recvfrom(f
, (char *)(rpkt
->dat
), sizeof(rpkt
->dat
), 0,
(struct sockaddr
*)&from
, &sin_size
)
printf("received packet from %s\n", inet_ntoa(from
.sin_addr
));
for (hp
= addrs
; hp
->h_name
!= (char *)NULL
; hp
++) {
if (!bcmp(hp
->h_addr
, (char *)&from
.sin_addr
.s_addr
,
fprintf(stderr
, "%s: received packet from wrong host! (%x)\n",
"send_to_kdc(send_rcv)", from
.sin_addr
.s_addr
);