2002-06-04 Ken Raeburn <raeburn@mit.edu>
+ * k5-int.h (krb5int_sendto_udp): Declare.
+ (krb5_sendto_kdc): Update declaration.
+ (KRB5INT_ACCESS_STRUCT_VERSION): Bump.
+ (struct _krb5int_access): Update locate_kdc interface; add
+ sendto_udp.
+
* fake-addrinfo.h [COPY_FIRST_CANONNAME]: Include string.h.
* k5-int.h (struct addrlist): Field "addrs" now points to
#include <stdio.h>
+struct addrlist;
+
/* libos.spec */
krb5_error_code krb5_lock_file (krb5_context, int, int);
krb5_error_code krb5_unlock_file (krb5_context, int);
krb5_error_code krb5_sendto_kdc (krb5_context, const krb5_data *,
const krb5_data *, krb5_data *, int);
+krb5_error_code krb5int_sendto_udp (krb5_context, const krb5_data *,
+ const struct addrlist *, krb5_data *);
krb5_error_code krb5_get_krbhst (krb5_context, const krb5_data *, char *** );
krb5_error_code krb5_free_krbhst (krb5_context, char * const * );
krb5_error_code krb5_create_secure_file (krb5_context, const char * pathname);
/* To keep happy libraries which are (for now) accessing internal stuff */
/* Make sure to increment by one when changing the struct */
-#define KRB5INT_ACCESS_STRUCT_VERSION 4
+#define KRB5INT_ACCESS_STRUCT_VERSION 5
typedef struct _krb5int_access {
krb5_error_code (*krb5_locate_kdc) (krb5_context, const krb5_data *,
- struct addrlist *, int);
+ struct addrlist *, int, int);
krb5_error_code (*krb5_locate_server) (krb5_context, const krb5_data *,
struct addrlist *, int,
const char *, const char *,
unsigned int krb5_skdc_timeout_shift;
unsigned int krb5_skdc_timeout_1;
unsigned int krb5_max_dgram_size;
- const struct krb5_hash_provider *md5_hash_provider;
- const struct krb5_enc_provider *arcfour_enc_provider;
- krb5_error_code (* krb5_hmac)
- (const struct krb5_hash_provider *hash,
- const krb5_keyblock *key, unsigned int icount,
- const krb5_data *input, krb5_data *output);
- } krb5int_access;
+ const struct krb5_hash_provider *md5_hash_provider;
+ const struct krb5_enc_provider *arcfour_enc_provider;
+ krb5_error_code (* krb5_hmac) (const struct krb5_hash_provider *hash,
+ const krb5_keyblock *key,
+ unsigned int icount, const krb5_data *input,
+ krb5_data *output);
+ krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg,
+ const struct addrlist *, krb5_data *reply);
+} krb5int_access;
#define KRB5INT_ACCESS_VERSION \
(((krb5_int32)((sizeof(krb5int_access) & 0xFFFF) | \
2002-06-04 Ken Raeburn <raeburn@mit.edu>
- * sendmsg.c: Include fake-addrinfo.h.
- (krb524_sendto_kdc): Update for addrlist changes.
+ * sendmsg.c: Include fake-addrinfo.h. Don't include
+ sys/select.h.
+ (krb524_sendto_kdc): Update for addrlist, locate_server,
+ locate_kdc changes. Rip out network code and call
+ internals.sendto_udp instead.
2002-04-10 Danilo Almeida <dalmeida@mit.edu>
#include <stdlib.h>
#include <string.h>
-#ifdef _AIX
-#include <sys/select.h>
-#endif
-
#include <krb.h>
#include "krb524.h"
const krb5_data * realm;
krb5_data * reply;
{
- register int timeout, host, i;
+ int i;
struct addrlist al = ADDRLIST_INIT;
struct servent *serv;
- int sent, nready;
krb5_error_code retval;
- SOCKET *socklist;
- fd_set readable;
- struct timeval waitlen;
- int cc;
krb5int_access internals;
int port;
retval = internals.krb5_locate_server(context, realm, &al, 0,
"krb524_server", "_krb524",
- 0, port, 0);
+ SOCK_DGRAM, port, 0);
if (retval == KRB5_REALM_CANT_RESOLVE || retval == KRB5_REALM_UNKNOWN) {
/* Fallback heuristic: Assume krb524 port on every KDC might
work. */
- retval = internals.krb5_locate_kdc(context, realm, &al, 0);
+ retval = internals.krb5_locate_kdc(context, realm, &al, 0, SOCK_DGRAM);
/*
* Bash the ports numbers.
*/
if (retval == 0)
for (i = 0; i < al.naddrs; i++) {
+ al.addrs[i]->ai_socktype = SOCK_DGRAM;
if (al.addrs[i]->ai_family == AF_INET)
sa2sin (al.addrs[i]->ai_addr)->sin_port = port;
}
if (al.naddrs == 0)
return KRB5_REALM_UNKNOWN;
- socklist = (SOCKET *)malloc(al.naddrs * sizeof(SOCKET));
- if (socklist == NULL) {
- internals.free_addrlist (&al);
- return ENOMEM;
- }
- for (i = 0; i < al.naddrs; i++)
- socklist[i] = INVALID_SOCKET;
-
- if (!(reply->data = malloc(internals.krb5_max_dgram_size))) {
- internals.free_addrlist (&al);
- free(socklist);
- return ENOMEM;
- }
- reply->length = internals.krb5_max_dgram_size;
-
-#if 0
- /*
- * Not needed for Windows, since it's done by the DLL
- * initialization. XXX What about for the Macintosh?
- *
- * See below for commented out SOCKET_CLEANUP()
- */
- if (SOCKET_INITIALIZE()) { /* PC needs this for some tcp/ip stacks */
- free(addr);
- free(socklist);
- free(reply->data);
- return SOCKET_ERRNO;
- }
-#endif
-
- /*
- * do exponential backoff.
- */
-
- for (timeout = internals.krb5_skdc_timeout_1;
- timeout < internals.krb5_max_skdc_timeout;
- timeout <<= internals.krb5_skdc_timeout_shift) {
- sent = 0;
- for (host = 0; host < al.naddrs; host++) {
- /* send to the host, wait timeout seconds for a response,
- then move on. */
- /* cache some sockets for each host */
- if (socklist[host] == INVALID_SOCKET) {
- /* XXX 4.2/4.3BSD has PF_xxx = AF_xxx, so the socket
- creation here will work properly... */
- /*
- * From socket(2):
- *
- * The protocol specifies a particular protocol to be
- * used with the socket. Normally only a single
- * protocol exists to support a particular socket type
- * within a given protocol family.
- */
- socklist[host] = socket(al.addrs[host]->ai_family, SOCK_DGRAM,
- 0);
- if (socklist[host] == INVALID_SOCKET)
- continue; /* try other hosts */
- /* have a socket to send/recv from */
- /* On BSD systems, a connected UDP socket will get connection
- refused and net unreachable errors while an unconnected
- socket will time out, so use connect, send, recv instead of
- sendto, recvfrom. The connect here may return an error if
- the destination host is known to be unreachable. */
- if (connect(socklist[host], al.addrs[host]->ai_addr,
- al.addrs[host]->ai_addrlen) == SOCKET_ERROR)
- continue;
- }
- if (send(socklist[host], message->data, (int) message->length, 0)
- != message->length)
- continue;
- retry:
- waitlen.tv_usec = 0;
- waitlen.tv_sec = timeout;
- FD_ZERO(&readable);
- FD_SET(socklist[host], &readable);
- nready = select(SOCKET_NFDS(socklist[host]),
- &readable, 0, 0, &waitlen);
- if (nready) {
- if (nready == SOCKET_ERROR) {
- if (SOCKET_ERRNO == SOCKET_EINTR)
- goto retry;
- retval = SOCKET_ERRNO;
- goto out;
- }
- if ((cc = recv(socklist[host],
- reply->data, (int) reply->length, 0)) == SOCKET_ERROR)
- {
- /* man page says error could be:
- EBADF: won't happen
- ENOTSOCK: it's a socket.
- EWOULDBLOCK: not marked non-blocking, and we selected.
- EINTR: could happen
- EFAULT: we allocated the reply packet.
-
- In addition, net related errors like ECONNREFUSED
- are possble (but undocumented). Assume anything
- other than EINTR is a permanent error for the
- server (i.e. don't set sent = 1).
- */
-
- if (SOCKET_ERRNO == SOCKET_EINTR)
- sent = 1;
- continue;
- }
-
- /* We might consider here verifying that the reply
- came from one of the KDC's listed for that address type,
- but that check can be fouled by some implementations of
- some network types which might show a loopback return
- address, for example, if the KDC is on the same host
- as the client. */
-
- reply->length = cc;
- retval = 0;
- goto out;
- } else if (nready == 0) {
- /* timeout */
- sent = 1;
- }
- /* not ready, go on to next server */
- }
- if (!sent) {
- /* never were able to send to any servers; give up */
- retval = KRB5_KDC_UNREACH;
- break;
- }
- }
- retval = KRB5_KDC_UNREACH;
- out:
- for (i = 0; i < al.naddrs; i++)
- if (socklist[i] != INVALID_SOCKET)
- (void) closesocket (socklist[i]);
-#if 0
- SOCKET_CLEANUP(); /* Done with sockets for now */
-#endif
+ retval = internals.sendto_udp (context, message, &al, reply);
internals.free_addrlist (&al);
- free(socklist);
- if (retval) {
- free(reply->data);
- reply->data = 0;
- reply->length = 0;
- }
return retval;
}
2002-06-04 Ken Raeburn <raeburn@mit.edu>
+ * locate_kdc.c (krb5_locate_srv_conf_1): New argument socktype
+ indicates what type of addrinfo entries to add.
+ (krb5int_locate_server): Change argument is_stream to socktype.
+ Pass the value to krb5_locate_srv_conf_1.
+ (krb5_locate_kdc): New argument socktype.
+ * sendto_kdc.c (krb5int_sendto_udp): New function, containing most
+ of the network code from krb5_sendto_kdc.
+ (krb5_sendto_kdc): Call it.
+ * accessor.c (krb5int_accessor): Set new sendto_udp field.
+ * os-proto.h (krb5_locate_kdc): Update prototype. Add forward
+ declaration for struct addrlist.
+ * t_locate_kdc.c (main): Update call to krb5_locate_kdc.
+
* locate_kdc.c: Include fake-addrinfo.h before k5-int.h.
(grow_list, krb5int_free_addrlist)
(add_addrinfo_to_list): Incorporate list-updating code from
internals_temp.krb5_hmac = krb5_hmac;
internals_temp.md5_hash_provider = &krb5int_hash_md5;
internals_temp.arcfour_enc_provider = &krb5int_enc_arcfour;
+ internals_temp.sendto_udp = &krb5int_sendto_udp;
*internals = internals_temp;
return 0;
}
static krb5_error_code
krb5_locate_srv_conf_1(krb5_context context, const krb5_data *realm,
const char * name, struct addrlist *addrlist,
- int get_masters, int udpport, int sec_udpport)
+ int get_masters, int socktype,
+ int udpport, int sec_udpport)
{
const char *realm_srv_names[4];
char **masterlist, **hostlist, *host, *port, *cp;
p2 = sec_udpport;
}
- code = add_host_to_list (addrlist, hostlist[i], p1, p2, SOCK_DGRAM);
+ if (socktype != 0)
+ code = add_host_to_list (addrlist, hostlist[i], p1, p2, socktype);
+ else {
+ code = add_host_to_list (addrlist, hostlist[i], p1, p2,
+ SOCK_DGRAM);
+ if (code == 0)
+ code = add_host_to_list (addrlist, hostlist[i], p1, p2,
+ SOCK_STREAM);
+ }
if (code) {
#ifdef TEST
fprintf (stderr, "error %d returned from add_host_to_list\n", code);
krb5_error_code ret;
ret = krb5_locate_srv_conf_1 (context, realm, name, al,
- get_masters, udpport, sec_udpport);
+ get_masters, 0, udpport, sec_udpport);
if (ret)
return ret;
if (al->naddrs == 0) /* Couldn't resolve any KDC names */
struct addrlist *addrlist,
int get_masters,
const char *profname, const char *dnsname,
- int is_stream,
+ int socktype,
/* network order port numbers! */
int dflport1, int dflport2)
{
*/
code = krb5_locate_srv_conf_1(context, realm, profname, &al, get_masters,
- dflport1, dflport2);
+ socktype, dflport1, dflport2);
#ifdef KRB5_DNS_LOOKUP
if (code && dnsname != 0) {
int use_dns = _krb5_use_dns_kdc(context);
if (use_dns) {
- /* Values of is_stream:
- 0: udp only
- 1: tcp only
- 2: udp or tcp
- No other values currently allowed. */
code = 0;
-#ifdef TEST
- fprintf(stderr, "is_stream = %d\n", is_stream);
-#endif
- if (is_stream != 1) {
+ if (socktype == SOCK_DGRAM || socktype == 0) {
code = krb5_locate_srv_dns_1(realm, dnsname, "_udp", &al);
#ifdef TEST
if (code)
- fprintf(stderr, "dns lookup returned error %d\n", code);
+ fprintf(stderr, "dns udp lookup returned error %d\n",
+ code);
#endif
}
- if (is_stream != 0 && code == 0) {
+ if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp", &al);
#ifdef TEST
if (code)
- fprintf(stderr, "dns lookup returned error %d\n", code);
+ fprintf(stderr, "dns tcp lookup returned error %d\n",
+ code);
#endif
}
}
krb5_error_code
krb5_locate_kdc(krb5_context context, const krb5_data *realm,
struct addrlist *addrlist,
- int get_masters)
+ int get_masters, int socktype)
{
int udpport, sec_udpport;
(get_masters
? "_kerberos-master"
: "_kerberos"),
- 0, udpport, sec_udpport);
+ socktype, udpport, sec_udpport);
}
#ifndef KRB5_LIBOS_INT_PROTO__
#define KRB5_LIBOS_INT_PROTO__
-#ifdef SOCK_DGRAM /* XXX hack... */
+struct addrlist;
krb5_error_code krb5_locate_kdc
- (krb5_context, const krb5_data *, struct addrlist *, int);
-#endif
+ (krb5_context, const krb5_data *, struct addrlist *, int, int);
#ifdef HAVE_NETINET_IN_H
krb5_error_code krb5_unpack_full_ipaddr
krb5_data * reply;
int use_master;
{
- int timeout, host, i;
- int sent, nready;
krb5_error_code retval;
- SOCKET *socklist;
- fd_set readable;
- struct timeval waitlen;
- int cc;
struct addrlist addrs;
/*
* find KDC location(s) for realm
*/
- if ((retval = krb5_locate_kdc(context, realm, &addrs, use_master)))
+ if ((retval = krb5_locate_kdc(context, realm, &addrs, use_master, SOCK_DGRAM)))
return retval;
if (addrs.naddrs == 0)
return (use_master ? KRB5_KDC_UNREACH : KRB5_REALM_UNKNOWN);
+ retval = krb5int_sendto_udp (context, message, &addrs, reply);
+ krb5int_free_addrlist (&addrs);
+ return retval;
+}
+
+krb5_error_code
+krb5int_sendto_udp (krb5_context context, const krb5_data *message,
+ const struct addrlist *addrs, krb5_data *reply)
+{
+ int timeout, host, i;
+ int sent, nready;
+ krb5_error_code retval;
+ SOCKET *socklist;
+ fd_set readable;
+ struct timeval waitlen;
+ int cc;
- socklist = (SOCKET *)malloc(addrs.naddrs * sizeof(SOCKET));
+ socklist = (SOCKET *)malloc(addrs->naddrs * sizeof(SOCKET));
if (socklist == NULL) {
- krb5int_free_addrlist (&addrs);
return ENOMEM;
}
- for (i = 0; i < addrs.naddrs; i++)
+ for (i = 0; i < addrs->naddrs; i++)
socklist[i] = INVALID_SOCKET;
if (!(reply->data = malloc(krb5_max_dgram_size))) {
- for (i = 0; i < addrs.naddrs; i++)
- krb5_xfree (addrs.addrs[i]);
- krb5int_free_addrlist (&addrs);
krb5_xfree(socklist);
return ENOMEM;
}
* See below for commented out SOCKET_CLEANUP()
*/
if (SOCKET_INITIALIZE()) { /* PC needs this for some tcp/ip stacks */
- krb5int_free_addrlist (&addrs);
krb5_xfree(socklist);
free(reply->data);
return SOCKET_ERRNO;
for (timeout = krb5_skdc_timeout_1; timeout < krb5_max_skdc_timeout;
timeout <<= krb5_skdc_timeout_shift) {
sent = 0;
- for (host = 0; host < addrs.naddrs; host++) {
- if (addrs.addrs[host]->ai_socktype != SOCK_DGRAM)
+ for (host = 0; host < addrs->naddrs; host++) {
+ if (addrs->addrs[host]->ai_socktype != SOCK_DGRAM)
continue;
/* Send to the host, wait timeout seconds for a response,
then move on. */
*/
#ifdef DEBUG
fprintf (stderr, "getting dgram socket in family %d...",
- addrs.addrs[host]->ai_family);
+ addrs->addrs[host]->ai_family);
#endif
- socklist[host] = socket(addrs.addrs[host]->ai_family,
+ socklist[host] = socket(addrs->addrs[host]->ai_family,
SOCK_DGRAM, 0);
if (socklist[host] == INVALID_SOCKET) {
#ifdef DEBUG
perror ("socket");
- fprintf (stderr, "af was %d\n", addrs.addrs[host]->ai_family);
+ fprintf (stderr, "af was %d\n", addrs->addrs[host]->ai_family);
#endif
continue; /* try other hosts */
}
#ifdef DEBUG
{
char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
- if (0 != getnameinfo (addrs.addrs[host]->ai_addr,
- addrs.addrs[host]->ai_addrlen,
+ if (0 != getnameinfo (addrs->addrs[host]->ai_addr,
+ addrs->addrs[host]->ai_addrlen,
addrbuf, sizeof (addrbuf),
portbuf, sizeof (portbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
socket will time out, so use connect, send, recv instead of
sendto, recvfrom. The connect here may return an error if
the destination host is known to be unreachable. */
- if (connect(socklist[host], addrs.addrs[host]->ai_addr,
- addrs.addrs[host]->ai_addrlen) == SOCKET_ERROR) {
+ if (connect(socklist[host], addrs->addrs[host]->ai_addr,
+ addrs->addrs[host]->ai_addrlen) == SOCKET_ERROR) {
#ifdef DEBUG
perror ("connect");
#endif
}
retval = KRB5_KDC_UNREACH;
out:
- for (i = 0; i < addrs.naddrs; i++)
+ for (i = 0; i < addrs->naddrs; i++)
if (socklist[i] != INVALID_SOCKET)
(void) closesocket (socklist[i]);
#if 0
SOCKET_CLEANUP(); /* Done with sockets for now */
#endif
- krb5int_free_addrlist (&addrs);
krb5_xfree(socklist);
if (retval) {
free(reply->data);
break;
case LOOKUP_WHATEVER:
- err = krb5_locate_kdc (ctx, &realm, &al, 0);
+ err = krb5_locate_kdc (ctx, &realm, &al, 0, 0);
break;
}
if (err) kfatal (err);