From 41040f094ce1ea792ab78b5e766d7da69ed72e64 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Wed, 5 Jun 2002 01:49:47 +0000 Subject: [PATCH] Separate send-to-kdc UDP code, export it via accessor interface, and call in to it from krb524_sendto_kdc. Supply a socket type to krb5_locate_server and krb5_locate_kdc. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@14473 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/ChangeLog | 6 ++ src/include/k5-int.h | 24 +++-- src/krb524/ChangeLog | 7 +- src/krb524/sendmsg.c | 158 ++------------------------------- src/lib/krb5/os/ChangeLog | 13 +++ src/lib/krb5/os/accessor.c | 1 + src/lib/krb5/os/locate_kdc.c | 41 +++++---- src/lib/krb5/os/os-proto.h | 5 +- src/lib/krb5/os/sendto_kdc.c | 54 +++++------ src/lib/krb5/os/t_locate_kdc.c | 2 +- 10 files changed, 99 insertions(+), 212 deletions(-) diff --git a/src/include/ChangeLog b/src/include/ChangeLog index ba1fbf6f1..b228e57b6 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,5 +1,11 @@ 2002-06-04 Ken Raeburn + * 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 diff --git a/src/include/k5-int.h b/src/include/k5-int.h index e53585a15..b384315ff 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -464,11 +464,15 @@ extern char *strdup (const char *); #include +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); @@ -1543,11 +1547,11 @@ void krb5int_set_prompt_types /* 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 *, @@ -1557,13 +1561,15 @@ typedef struct _krb5int_access { 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) | \ diff --git a/src/krb524/ChangeLog b/src/krb524/ChangeLog index 6f35970ed..2ad2efa6f 100644 --- a/src/krb524/ChangeLog +++ b/src/krb524/ChangeLog @@ -1,7 +1,10 @@ 2002-06-04 Ken Raeburn - * 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 diff --git a/src/krb524/sendmsg.c b/src/krb524/sendmsg.c index 2335dad31..aac8f915e 100644 --- a/src/krb524/sendmsg.c +++ b/src/krb524/sendmsg.c @@ -39,10 +39,6 @@ #include #include -#ifdef _AIX -#include -#endif - #include #include "krb524.h" @@ -68,15 +64,10 @@ krb524_sendto_kdc (context, message, realm, reply) 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; @@ -92,16 +83,17 @@ krb524_sendto_kdc (context, message, realm, reply) 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; } @@ -111,147 +103,7 @@ krb524_sendto_kdc (context, message, realm, reply) 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; } diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index 9f75d40b9..c1b6802be 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,5 +1,18 @@ 2002-06-04 Ken Raeburn + * 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 diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index 5e77051a6..b410f3d30 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -47,6 +47,7 @@ krb5int_accessor(internals, version) 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; } diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c index d1819939d..bcaf3e8b8 100644 --- a/src/lib/krb5/os/locate_kdc.c +++ b/src/lib/krb5/os/locate_kdc.c @@ -291,7 +291,8 @@ egress: 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; @@ -431,7 +432,15 @@ krb5_locate_srv_conf_1(krb5_context context, const krb5_data *realm, 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); @@ -466,7 +475,7 @@ krb5_locate_srv_conf(context, realm, name, al, get_masters, 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 */ @@ -740,7 +749,7 @@ krb5int_locate_server (krb5_context context, const krb5_data *realm, 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) { @@ -754,33 +763,27 @@ krb5int_locate_server (krb5_context context, const krb5_data *realm, */ 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 } } @@ -811,7 +814,7 @@ krb5int_locate_server (krb5_context context, const krb5_data *realm, 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; @@ -827,5 +830,5 @@ krb5_locate_kdc(krb5_context context, const krb5_data *realm, (get_masters ? "_kerberos-master" : "_kerberos"), - 0, udpport, sec_udpport); + socktype, udpport, sec_udpport); } diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h index 48910b51b..f474fa04e 100644 --- a/src/lib/krb5/os/os-proto.h +++ b/src/lib/krb5/os/os-proto.h @@ -30,10 +30,9 @@ #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 diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index 862b85a4b..bf0574240 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -63,36 +63,42 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) 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; } @@ -106,7 +112,6 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) * 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; @@ -120,8 +125,8 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) 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. */ @@ -139,22 +144,22 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) */ #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)) @@ -169,8 +174,8 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) 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 @@ -253,13 +258,12 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) } 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); diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c index 5bb334b6d..fc2073eb2 100644 --- a/src/lib/krb5/os/t_locate_kdc.c +++ b/src/lib/krb5/os/t_locate_kdc.c @@ -118,7 +118,7 @@ int main (int argc, char *argv[]) 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); -- 2.26.2