summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2001-04-26 11:10:15 +0000
committerKen Raeburn <raeburn@mit.edu>2001-04-26 11:10:15 +0000
commit612d53bf16b53cd484fe941e3c4ec29579c19db0 (patch)
tree3c2d873c419ce4e9caa74eba5130a3bdc3cc546e
parenta895e124d573c6b7db883966cd338f86c467d93a (diff)
downloadkrb5-612d53bf16b53cd484fe941e3c4ec29579c19db0.tar.gz
krb5-612d53bf16b53cd484fe941e3c4ec29579c19db0.tar.xz
krb5-612d53bf16b53cd484fe941e3c4ec29579c19db0.zip
implement and use new internal interface for locating servers
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13204 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/lib/krb5/os/ChangeLog33
-rw-r--r--src/lib/krb5/os/accessor.c1
-rw-r--r--src/lib/krb5/os/changepw.c476
-rw-r--r--src/lib/krb5/os/locate_kdc.c597
-rw-r--r--src/lib/krb5/os/os-proto.h2
-rw-r--r--src/lib/krb5/os/sendto_kdc.c8
6 files changed, 672 insertions, 445 deletions
diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog
index c0dffe749..3c5446091 100644
--- a/src/lib/krb5/os/ChangeLog
+++ b/src/lib/krb5/os/ChangeLog
@@ -1,3 +1,36 @@
+2001-04-26 Ken Raeburn <raeburn@mit.edu>
+
+ * locate_kdc.c (krb5int_locate_server): New function, replaces
+ functionality of krb5_locate_srv_conf and _dns, including checking
+ whether DNS lookup is desired.
+ (krb5_locate_srv_conf, krb5_locate_srv_dns): Define only if macro
+ TEST is defined. Added another level of indirection in the
+ address pointer argument.
+ (krb5_locate_srv_dns_1, krb5_locate_srv_conf_1,
+ translate_ai_error, get_port, struct addrlist, ADDRLIST_INIT,
+ grow_list, free_list, add_sockaddr_to_list, add_addrinfo_to_list,
+ set_port_num, add_host_to_list): New helper functions.
+ (krb5_locate_kdc): Added another level of indirection in the
+ address pointer argument. Call krb5int_locate_server.
+ (KPASSWD_PORTNAME): Deleted.
+
+ * os-proto.h (krb5_locate_kdc): Updated prototype.
+
+ * sendto_kdc.c (krb5_sendto_kdc): Updates for change in
+ krb5_locate_kdc interface.
+
+ * changepw.c (krb5_locate_kpasswd): Call krb5int_locate_server.
+ Add another level of indirection in address pointer. Now gives
+ preference to _kpasswd info from DNS over admin_server info in
+ config file, if kpasswd_server is not set.
+ (krb5_change_password): Use struct sockaddr_storage for all
+ automatic address variables. Ignore any non-IPv4 addresses
+ returned from krb5_locate_kpasswd; return an error if all
+ addresses are non-IPv4. Update for new krb5_locate_kpasswd
+ interface.
+
+ * accessor.c (krb5int_accessor): Set krb5_locate_server field.
+
2001-04-25 Ken Raeburn <raeburn@mit.edu>
* localaddr.c (socklen_t, socklen): Deleted; definitions now in
diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c
index d0d0dc21d..d3c842a86 100644
--- a/src/lib/krb5/os/accessor.c
+++ b/src/lib/krb5/os/accessor.c
@@ -37,6 +37,7 @@ krb5int_accessor(internals, version)
if (version == KRB5INT_ACCESS_VERSION)
{
krb5int_access internals_temp;
+ internals_temp.krb5_locate_server = krb5int_locate_server;
internals_temp.krb5_locate_kdc = krb5_locate_kdc;
internals_temp.krb5_max_skdc_timeout = krb5_max_skdc_timeout;
internals_temp.krb5_skdc_timeout_shift = krb5_skdc_timeout_shift;
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index 61cfea01f..0a6d0e5ee 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -1,14 +1,14 @@
/*
* lib/krb5/os/changepw.c
*
- * Copyright 1990,1999 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1999,2001 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
- *
+ *
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
@@ -22,7 +22,7 @@
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
- *
+ *
*/
#define NEED_SOCKETS
@@ -57,54 +57,29 @@ static krb5_error_code
krb5_locate_kpasswd(context, realm, addr_pp, naddrs)
krb5_context context;
const krb5_data *realm;
- struct sockaddr **addr_pp;
+ struct sockaddr ***addr_pp;
int *naddrs;
{
krb5_error_code code;
- int i;
-
- /*
- * We always try the local file first
- */
-
- code = krb5_locate_srv_conf(context, realm, "kpasswd_server",
- addr_pp, naddrs, 0);
- if (code) {
- code = krb5_locate_srv_conf(context, realm, "admin_server",
- addr_pp, naddrs, 0);
- if ( !code ) {
- /* success with admin_server but now we need to change the port */
- /* number to use DEFAULT_KPASSWD_PORT. */
- for ( i=0;i<*naddrs;i++ ) {
- struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
- sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
- }
- }
- }
-#ifdef KRB5_DNS_LOOKUP
+ code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+ "kpasswd_server", "_kpasswd", 0,
+ DEFAULT_KPASSWD_PORT, 0);
if (code) {
- int use_dns = _krb5_use_dns_kdc(context);
- if ( use_dns ) {
- code = krb5_locate_srv_dns(realm, "_kpasswd", "_udp",
- addr_pp, naddrs);
- if ( code ) {
- code = krb5_locate_srv_dns(realm,
- "_kerberos-adm",
- "_tcp",
- addr_pp, naddrs);
- if ( !code ) {
- /* success with admin_server but now we need to change the port */
- /* number to use DEFAULT_KPASSWD_PORT. */
- for ( i=0;i<*naddrs;i++ ) {
- struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
- sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
- }
- }
- }
- }
+ code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+ "admin_server", "_kerberos-adm", 1,
+ DEFAULT_KPASSWD_PORT, 0);
+ if (!code) {
+ /* Success with admin_server but now we need to change the
+ port number to use DEFAULT_KPASSWD_PORT. */
+ int i;
+ for ( i=0;i<*naddrs;i++ ) {
+ struct sockaddr *a = (*addr_pp)[i];
+ if (a->sa_family == AF_INET)
+ sa2sin (a)->sin_port = htons(DEFAULT_KPASSWD_PORT);
+ }
+ }
}
-#endif /* KRB5_DNS_LOOKUP */
return (code);
}
@@ -125,10 +100,12 @@ krb5_change_password(context, creds, newpw, result_code,
char *code_string;
krb5_error_code code = 0;
int i, addrlen;
- struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr;
+ struct sockaddr **addr_p;
+ struct sockaddr_storage local_addr, remote_addr, tmp_addr;
int naddr_p;
int cc, local_result_code, tmp_len;
SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET;
+ int tried_one = 0;
/* Initialize values so that cleanup call can safely check for NULL */
@@ -137,18 +114,18 @@ krb5_change_password(context, creds, newpw, result_code,
memset(&chpw_req, 0, sizeof(krb5_data));
memset(&chpw_rep, 0, sizeof(krb5_data));
memset(&ap_req, 0, sizeof(krb5_data));
-
+
/* initialize auth_context so that we know we have to free it */
if ((code = krb5_auth_con_init(context, &auth_context)))
goto cleanup;
-
- if ((code = krb5_mk_req_extended(context, &auth_context,
+
+ if ((code = krb5_mk_req_extended(context, &auth_context,
AP_OPTS_USE_SUBKEY,
NULL, creds, &ap_req)))
goto cleanup;
- if ((code = krb5_locate_kpasswd(context,
- krb5_princ_realm(context, creds->client),
+ if ((code = krb5_locate_kpasswd(context,
+ krb5_princ_realm(context, creds->client),
&addr_p, &naddr_p)))
goto cleanup;
@@ -156,7 +133,7 @@ krb5_change_password(context, creds, newpw, result_code,
is left unconnected in case the server is multihomed and routes
are asymmetric. s2 is connected to resolve routes and get
addresses. this is the *only* way to get proper addresses for
- multihomed hosts if routing is asymmetric.
+ multihomed hosts if routing is asymmetric.
A related problem in the server, but not the client, is that
many os's have no way to disconnect a connected udp socket, so
@@ -168,212 +145,215 @@ krb5_change_password(context, creds, newpw, result_code,
hostname resolution to get the local ip addr) will work and
interoperate if the client is single-homed. */
- if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
- {
+ if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ for (i=0; i<naddr_p; i++) {
+ fd_set fdset;
+ struct timeval timeout;
+
+ /* XXX Now the locate_ functions can return IPv6 addresses. */
+ if (addr_p[i]->sa_family != AF_INET)
+ continue;
+
+ tried_one = 1;
+ if (connect(s2, addr_p[i], socklen(addr_p[i])) == SOCKET_ERROR) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
+
code = SOCKET_ERRNO;
goto cleanup;
- }
+ }
+
+ addrlen = sizeof(local_addr);
+
+ if (getsockname(s2, ss2sa(&local_addr), &addrlen) < 0) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
- if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
- {
code = SOCKET_ERRNO;
goto cleanup;
- }
-
- for (i=0; i<naddr_p; i++)
- {
- fd_set fdset;
- struct timeval timeout;
-
- if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- addrlen = sizeof(local_addr);
+ }
+
+ /* some brain-dead OS's don't return useful information from
+ * the getsockname call. Namely, windows and solaris. */
+
+ if (ss2sin(&local_addr)->sin_addr.s_addr != 0) {
+ local_kaddr.addrtype = ADDRTYPE_INET;
+ local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr);
+ local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr;
+ } else {
+ krb5_address **addrs;
+
+ krb5_os_localaddr(context, &addrs);
+
+ local_kaddr.magic = addrs[0]->magic;
+ local_kaddr.addrtype = addrs[0]->addrtype;
+ local_kaddr.length = addrs[0]->length;
+ local_kaddr.contents = malloc(addrs[0]->length);
+ memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+
+ krb5_free_addresses(context, addrs);
+ }
+
+ addrlen = sizeof(remote_addr);
+ if (getpeername(s2, ss2sa(&remote_addr), &addrlen) < 0) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
+
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ remote_kaddr.addrtype = ADDRTYPE_INET;
+ remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
+ remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
+
+ /* mk_priv requires that the local address be set.
+ getsockname is used for this. rd_priv requires that the
+ remote address be set. recvfrom is used for this. If
+ rd_priv is given a local address, and the message has the
+ recipient addr in it, this will be checked. However, there
+ is simply no way to know ahead of time what address the
+ message will be delivered *to*. Therefore, it is important
+ that either no recipient address is in the messages when
+ mk_priv is called, or that no local address is passed to
+ rd_priv. Both is a better idea, and I have done that. In
+ summary, when mk_priv is called, *only* a local address is
+ specified. when rd_priv is called, *only* a remote address
+ is specified. Are we having fun yet? */
+
+ if ((code = krb5_auth_con_setaddrs(context, auth_context,
+ &local_kaddr, NULL))) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
+ newpw, &chpw_req)))
+ {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
- if (getsockname(s2, &local_addr, &addrlen) < 0)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- /* some brain-dead OS's don't return useful information from
- * the getsockname call. Namely, windows and solaris. */
-
- if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
- {
- local_kaddr.addrtype = ADDRTYPE_INET;
- local_kaddr.length = sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
- local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
- }
- else
- {
- krb5_address **addrs;
-
- krb5_os_localaddr(context, &addrs);
-
- local_kaddr.magic = addrs[0]->magic;
- local_kaddr.addrtype = addrs[0]->addrtype;
- local_kaddr.length = addrs[0]->length;
- local_kaddr.contents = malloc(addrs[0]->length);
- memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
-
- krb5_free_addresses(context, addrs);
- }
-
- addrlen = sizeof(remote_addr);
- if (getpeername(s2, &remote_addr, &addrlen) < 0)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- remote_kaddr.addrtype = ADDRTYPE_INET;
- remote_kaddr.length = sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
- remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
-
- /* mk_priv requires that the local address be set.
- getsockname is used for this. rd_priv requires that the
- remote address be set. recvfrom is used for this. If
- rd_priv is given a local address, and the message has the
- recipient addr in it, this will be checked. However, there
- is simply no way to know ahead of time what address the
- message will be delivered *to*. Therefore, it is important
- that either no recipient address is in the messages when
- mk_priv is called, or that no local address is passed to
- rd_priv. Both is a better idea, and I have done that. In
- summary, when mk_priv is called, *only* a local address is
- specified. when rd_priv is called, *only* a remote address
- is specified. Are we having fun yet? */
-
- if ((code = krb5_auth_con_setaddrs(context, auth_context,
- &local_kaddr, NULL)))
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
- newpw, &chpw_req)))
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0,
- (struct sockaddr *) &addr_p[i],
- sizeof(addr_p[i]))) != chpw_req.length)
- {
- if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
- (SOCKET_ERRNO == EHOSTUNREACH)))
- continue; /* try the next addr */
-
- code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
- goto cleanup;
- }
-
- chpw_rep.length = 1500;
- chpw_rep.data = (char *) malloc(chpw_rep.length);
-
- /* XXX need a timeout/retry loop here */
- FD_ZERO (&fdset);
- FD_SET (s1, &fdset);
- timeout.tv_sec = 120;
- timeout.tv_usec = 0;
- switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
- case -1:
- code = SOCKET_ERRNO;
- goto cleanup;
- case 0:
- code = ETIMEDOUT;
- goto cleanup;
- default:
- /* fall through */
- ;
- }
-
- /* "recv" would be good enough here... except that Windows/NT
- commits the atrocity of returning -1 to indicate failure,
- but leaving errno set to 0.
-
- "recvfrom(...,NULL,NULL)" would seem to be a good enough
- alternative, and it works on NT, but it doesn't work on
- SunOS 4.1.4 or Irix 5.3. Thus we must actually accept the
- value and discard it. */
- tmp_len = sizeof(tmp_addr);
- if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length,
- 0, &tmp_addr, &tmp_len)) < 0)
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- closesocket(s1);
- s1 = INVALID_SOCKET;
- closesocket(s2);
- s2 = INVALID_SOCKET;
-
- chpw_rep.length = cc;
-
- if ((code = krb5_auth_con_setaddrs(context, auth_context,
- NULL, &remote_kaddr)))
- goto cleanup;
-
- if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
- &local_result_code,
- result_string)))
- goto cleanup;
-
- if (result_code)
- *result_code = local_result_code;
-
- if (result_code_string)
- {
- if ((code = krb5_chpw_result_code_string(context,
- local_result_code,
- &code_string)))
- goto cleanup;
-
- result_code_string->length = strlen(code_string);
- if ((result_code_string->data =
- (char *) malloc(result_code_string->length)) == NULL)
- return(ENOMEM);
- strncpy(result_code_string->data, code_string, result_code_string->length);
- }
-
- code = 0;
+ if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0,
+ addr_p[i], socklen(addr_p[i]))) != chpw_req.length)
+ {
+ if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
+ (SOCKET_ERRNO == EHOSTUNREACH)))
+ continue; /* try the next addr */
+
+ code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
+ goto cleanup;
+ }
+
+ chpw_rep.length = 1500;
+ chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+ /* XXX need a timeout/retry loop here */
+ FD_ZERO (&fdset);
+ FD_SET (s1, &fdset);
+ timeout.tv_sec = 120;
+ timeout.tv_usec = 0;
+ switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
+ case -1:
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ case 0:
+ code = ETIMEDOUT;
+ goto cleanup;
+ default:
+ /* fall through */
+ ;
+ }
+
+ /* "recv" would be good enough here... except that Windows/NT
+ commits the atrocity of returning -1 to indicate failure,
+ but leaving errno set to 0.
+
+ "recvfrom(...,NULL,NULL)" would seem to be a good enough
+ alternative, and it works on NT, but it doesn't work on
+ SunOS 4.1.4 or Irix 5.3. Thus we must actually accept the
+ value and discard it. */
+ tmp_len = sizeof(tmp_addr);
+ if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length,
+ 0, ss2sa(&tmp_addr), &tmp_len)) < 0)
+ {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ closesocket(s1);
+ s1 = INVALID_SOCKET;
+ closesocket(s2);
+ s2 = INVALID_SOCKET;
+
+ chpw_rep.length = cc;
+
+ if ((code = krb5_auth_con_setaddrs(context, auth_context,
+ NULL, &remote_kaddr)))
+ goto cleanup;
+
+ if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
+ &local_result_code,
+ result_string)))
+ goto cleanup;
+
+ if (result_code)
+ *result_code = local_result_code;
+
+ if (result_code_string) {
+ if ((code = krb5_chpw_result_code_string(context,
+ local_result_code,
+ &code_string)))
goto cleanup;
- }
- code = SOCKET_ERRNO;
-
+ result_code_string->length = strlen(code_string);
+ if ((result_code_string->data =
+ (char *) malloc(result_code_string->length)) == NULL)
+ return(ENOMEM);
+ strncpy(result_code_string->data, code_string, result_code_string->length);
+ }
+
+ code = 0;
+ goto cleanup;
+ }
+
+ if (tried_one)
+ /* Got some non-fatal errors, but didn't get any successes. */
+ code = SOCKET_ERRNO;
+ else
+ /* Had some addresses, but didn't try any because they weren't
+ AF_INET addresses and we don't support AF_INET6 addresses
+ here yet. */
+ code = EHOSTUNREACH;
+
cleanup:
- if(auth_context != NULL)
- krb5_auth_con_free(context, auth_context);
-
- if(addr_p != NULL)
- krb5_xfree(addr_p);
-
- if(s1 != INVALID_SOCKET)
- closesocket(s1);
-
- if(s2 != INVALID_SOCKET)
- closesocket(s2);
-
+ if (auth_context != NULL)
+ krb5_auth_con_free(context, auth_context);
+
+ if (addr_p != NULL) {
+ for (i = 0; i < naddr_p; i++)
+ krb5_xfree (addr_p[i]);
+ krb5_xfree(addr_p);
+ }
+
+ if (s1 != INVALID_SOCKET)
+ closesocket(s1);
+
+ if (s2 != INVALID_SOCKET)
+ closesocket(s2);
+
krb5_free_data_contents(context, &chpw_req);
krb5_free_data_contents(context, &chpw_rep);
- krb5_free_data_contents(context, &ap_req);
-
+ krb5_free_data_contents(context, &ap_req);
+
return(code);
}
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index 48a014770..c68709f30 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -1,7 +1,7 @@
/*
* lib/krb5/os/locate_kdc.c
*
- * Copyright 1990 by the Massachusetts Institute of Technology.
+ * Copyright 1990,2000,2001 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -50,9 +50,6 @@
#endif
#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
-#ifndef KPASSWD_PORTNAME
-#define KPASSWD_PORTNAME "kpasswd"
-#endif
#if KRB5_DNS_LOOKUP_KDC
#define DEFAULT_LOOKUP_KDC 1
@@ -107,32 +104,256 @@ _krb5_use_dns_realm(context)
#endif /* KRB5_DNS_LOOKUP */
+static int get_port (const char *service, int stream, int defalt)
+{
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints = { 0 };
+ struct addrinfo *ai;
+ int err;
+
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM;
+ err = getaddrinfo (NULL, service, &hints, &ai);
+ if (err == 0 && ai != 0) {
+ if (ai->ai_addr->sa_family == AF_INET) {
+ int port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+ freeaddrinfo (ai);
+ return port;
+ }
+ freeaddrinfo (ai);
+ }
+ /* Any error - don't complain, just use default. */
+ return htons (defalt);
+#else
+ struct servent *sp;
+ sp = getservbyname (service, stream ? "tcp" : "udp"); /* NOT THREAD SAFE */
+ if (sp)
+ return sp->s_port;
+ return htons (defalt);
+#endif
+}
+
+struct addrlist {
+ struct sockaddr **addrs;
+ int naddrs;
+ int space;
+};
+#define ADDRLIST_INIT { 0, 0, 0 }
+
+static int
+grow_list (struct addrlist *lp, int nmore)
+{
+ int i;
+ int newspace = lp->space + nmore;
+ size_t newsize = newspace * sizeof (struct addrlist);
+ struct sockaddr **newaddrs;
+
+ if (lp->addrs)
+ newaddrs = realloc (lp->addrs, newsize);
+ else
+ newaddrs = malloc (newsize);
+
+ if (newaddrs == NULL)
+ return errno;
+ for (i = lp->space; i < newspace; i++)
+ newaddrs[i] = NULL;
+ lp->addrs = newaddrs;
+ lp->space = newspace;
+ return 0;
+}
+
+static void
+free_list (struct addrlist *lp)
+{
+ int i;
+ for (i = 0; i < lp->naddrs; i++)
+ free (lp->addrs[i]);
+ free (lp->addrs);
+ lp->addrs = NULL;
+ lp->naddrs = lp->space = 0;
+}
+
+static int
+add_sockaddr_to_list (struct addrlist *lp, const struct sockaddr *addr,
+ size_t len)
+{
+ struct sockaddr *copy;
+
+#ifdef TEST
+ fprintf (stderr, "\tadding sockaddr family %2d, len %d", addr->sa_family,
+ len);
+ if (addr->sa_family == AF_INET)
+ fprintf (stderr, "\t%s",
+ inet_ntoa (((const struct sockaddr_in *)addr)->sin_addr));
+ fprintf (stderr, "\n");
+#endif
+
+ if (lp->naddrs == lp->space) {
+ int err = grow_list (lp, 1);
+ if (err) {
+#ifdef TEST
+ fprintf (stderr, "grow_list failed %d\n", err);
+#endif
+ return err;
+ }
+ }
+ copy = malloc (len);
+ if (copy == NULL) {
+#ifdef TEST
+ perror ("malloc");
+#endif
+ return errno;
+ }
+ memcpy (copy, addr, len);
+ lp->addrs[lp->naddrs++] = copy;
+#ifdef TEST
+ fprintf (stderr, "count is now %d\n", lp->naddrs);
+#endif
+ return 0;
+}
+
+#ifdef HAVE_GETADDRINFO
+static int translate_ai_error (int err)
+{
+ switch (err) {
+ case 0:
+ return 0;
+ case EAI_ADDRFAMILY:
+ case EAI_BADFLAGS:
+ case EAI_FAMILY:
+ case EAI_SOCKTYPE:
+ case EAI_SERVICE:
+ /* All of these indicate bad inputs to getaddrinfo. */
+ return EINVAL;
+ case EAI_AGAIN:
+ /* Translate to standard errno code. */
+ return EAGAIN;
+ case EAI_MEMORY:
+ /* Translate to standard errno code. */
+ return ENOMEM;
+ case EAI_NODATA:
+ case EAI_NONAME:
+ /* Name not known or no address data, but no error. Do
+ nothing more. */
+ return 0;
+ case EAI_SYSTEM:
+ /* System error, obviously. */
+ return errno;
+ default:
+ /* An error code we haven't handled? */
+ return EINVAL;
+ }
+}
+
+static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a)
+{
+ return add_sockaddr_to_list (lp, a->ai_addr, a->ai_addrlen);
+}
+
+static void set_port_num (struct sockaddr *addr, int num)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = num;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = num;
+ break;
+ }
+}
+#endif
+
+static int
+add_host_to_list (struct addrlist *lp, const char *hostname,
+ int port, int secport)
+{
+#ifdef HAVE_GETADDRINFO
+ int err;
+ struct addrinfo *addrs, *a;
+
+#ifdef TEST
+ fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname,
+ ntohs (port), ntohs (secport));
+#endif
+
+ err = getaddrinfo (hostname, NULL, NULL, &addrs);
+ if (err)
+ return translate_ai_error (err);
+ for (a = addrs; a; a = a->ai_next) {
+ set_port_num (a->ai_addr, port);
+ err = add_addrinfo_to_list (lp, a);
+ if (err)
+ break;
+
+ if (secport == 0)
+ continue;
+
+ set_port_num (a->ai_addr, secport);
+ err = add_addrinfo_to_list (lp, a);
+ if (err)
+ break;
+ }
+ freeaddrinfo (addrs);
+ return err;
+#else
+ /* If we don't have getaddrinfo, we're not bothering with IPv6
+ support. */
+ int err;
+ struct hostent *hp;
+ int i;
+
+#ifdef TEST
+ fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname, port, secport);
+#endif
+
+ hp = gethostbyname (hostname);
+ if (hp != NULL) {
+ for (i = 0; hp->h_addr_list[i] != 0; i++) {
+ struct sockaddr_in sin4;
+
+ memset (&sin4, 0, sizeof (sin4));
+ memcpy (&sin4.sin_addr, hp->h_addr_list[i],
+ sizeof (sin4.sin_addr));
+ sin4.sin_family = AF_INET;
+ sin4.sin_port = port;
+ err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4,
+ sizeof (sin4));
+ if (err)
+ break;
+ if (secport != 0) {
+ sin4.sin_port = secport;
+ err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4,
+ sizeof (sin4));
+ }
+
+ if (err)
+ break;
+ }
+ }
+ return 0;
+#endif
+}
+
/*
* returns count of number of addresses found
* if master is non-NULL, it is filled in with the index of
* the master kdc
*/
-krb5_error_code
-krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
- krb5_context context;
- const krb5_data *realm;
- const char * name;
- struct sockaddr **addr_pp;
- int *naddrs;
- int get_masters;
+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)
{
const char *realm_srv_names[4];
char **masterlist, **hostlist, *host, *port, *cp;
krb5_error_code code;
- int i, j, out, count, ismaster;
- struct sockaddr *addr_p;
- struct sockaddr_in *sin_p;
- struct hostent *hp;
- struct servent *sp;
-#ifdef HAVE_NETINET_IN_H
- u_short udpport;
- u_short sec_udpport;
+ int i, j, count, ismaster;
+
+#ifdef TEST
+ fprintf (stderr,
+ "looking in krb5.conf for realm %s entry %s; ports %d,%d\n",
+ realm->data, name, ntohs (udpport), ntohs (sec_udpport));
#endif
if ((host = malloc(realm->length + 1)) == NULL)
@@ -158,27 +379,6 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
return code;
}
-#ifdef HAVE_NETINET_IN_H
- if ( !strcmp(name,"kpasswd_server") ) {
- if ((sp = getservbyname(KPASSWD_PORTNAME, "udp")))
- udpport = sp->s_port;
- else
- udpport = htons(DEFAULT_KPASSWD_PORT);
- sec_udpport = 0;
- } else {
- if ((sp = getservbyname(KDC_PORTNAME, "udp")))
- udpport = sp->s_port;
- else
- udpport = htons(KRB5_DEFAULT_PORT);
- if ((sp = getservbyname(KDC_SECONDARY_PORTNAME, "udp")))
- sec_udpport = sp->s_port;
- else
- sec_udpport = htons(KRB5_DEFAULT_SEC_PORT);
- }
-#endif
- if (sec_udpport == udpport)
- sec_udpport = 0;
-
count = 0;
while (hostlist && hostlist[count])
count++;
@@ -186,7 +386,7 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
if (count == 0) {
profile_free_list(hostlist);
krb5_xfree(host);
- *naddrs = 0;
+ addrlist->naddrs = 0;
return 0;
}
@@ -232,16 +432,9 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
count = count * 2;
#endif
- addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr) * count);
- if (addr_p == NULL) {
- if (hostlist)
- profile_free_list(hostlist);
- if (masterlist)
- profile_free_list(masterlist);
- return ENOMEM;
- }
+ for (i=0; hostlist[i]; i++) {
+ int p1, p2;
- for (i=0, out=0; hostlist[i]; i++) {
host = hostlist[i];
/*
* Strip off excess whitespace
@@ -258,10 +451,6 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
port++;
}
- if ((hp = gethostbyname(hostlist[i])) == 0) {
- continue;
- }
-
ismaster = 0;
if (masterlist) {
for (j=0; masterlist[j]; j++) {
@@ -271,44 +460,40 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
}
}
- if ( !get_masters || ismaster ) {
- switch (hp->h_addrtype) {
+ if (get_masters && !ismaster)
+ continue;
-#ifdef HAVE_NETINET_IN_H
- case AF_INET:
- for (j=0; hp->h_addr_list[j]; j++) {
- sin_p = (struct sockaddr_in *) &addr_p[out++];
- memset ((char *)sin_p, 0, sizeof(struct sockaddr));
- sin_p->sin_family = hp->h_addrtype;
- sin_p->sin_port = port ? htons(atoi(port)) : udpport;
- memcpy((char *)&sin_p->sin_addr,
- (char *)hp->h_addr_list[j],
- sizeof(struct in_addr));
- if (out+1 >= count) {
- count += 5;
- addr_p = (struct sockaddr *)
- realloc ((char *)addr_p,
- sizeof(struct sockaddr) * count);
- if (addr_p == NULL) {
- if ( hostlist )
- profile_free_list(hostlist);
- if ( masterlist )
- profile_free_list(masterlist);
- return ENOMEM;
- }
- }
- if (sec_udpport && !port) {
- addr_p[out] = addr_p[out-1];
- sin_p = (struct sockaddr_in *) &addr_p[out++];
- sin_p->sin_port = sec_udpport;
- }
- }
- break;
+ if (port) {
+ unsigned long l;
+#ifdef HAVE_STROUL
+ char *endptr;
+ l = strtoul (port, &endptr, 10);
+ if (endptr == NULL || *endptr != 0)
+ return EINVAL;
+#else
+ l = atoi (port);
+#endif
+ /* L is unsigned, don't need to check <0. */
+ if (l > 65535)
+ return EINVAL;
+ p1 = htons (l);
+ p2 = 0;
+ } else {
+ p1 = udpport;
+ p2 = sec_udpport;
+ }
+
+ code = add_host_to_list (addrlist, hostlist[i], p1, p2);
+ if (code) {
+#ifdef TEST
+ fprintf (stderr, "error %d returned from add_host_to_list\n", code);
#endif
- default:
- break;
- }
- }
+ if (hostlist)
+ profile_free_list (hostlist);
+ if (masterlist)
+ profile_free_list (masterlist);
+ return code;
+ }
}
if (hostlist)
@@ -316,15 +501,37 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
if (masterlist)
profile_free_list(masterlist);
- if (out == 0) { /* Couldn't resolve any KDC names */
- free (addr_p);
- return KRB5_REALM_CANT_RESOLVE;
- }
+ return 0;
+}
- *addr_pp = addr_p;
- *naddrs = out;
+#ifdef TEST
+static krb5_error_code
+krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters,
+ udpport, sec_udpport)
+ krb5_context context;
+ const krb5_data *realm;
+ const char * name;
+ struct sockaddr ***addr_pp;
+ int *naddrs;
+ int get_masters;
+ int udpport, sec_udpport;
+{
+ krb5_error_code ret;
+ struct addrlist al = ADDRLIST_INIT;
+
+ ret = krb5_locate_srv_conf_1 (context, realm, name, &al,
+ get_masters, udpport, sec_udpport);
+ if (ret) {
+ free_list (&al);
+ return ret;
+ }
+ if (al.naddrs == 0) /* Couldn't resolve any KDC names */
+ return KRB5_REALM_CANT_RESOLVE;
+ *addr_pp = al.addrs;
+ *naddrs = al.naddrs;
return 0;
}
+#endif
#ifdef KRB5_DNS_LOOKUP
@@ -332,24 +539,18 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
* Lookup a KDC via DNS SRV records
*/
-krb5_error_code
-krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
- const krb5_data *realm;
- const char *service;
- const char *protocol;
- struct sockaddr **addr_pp;
- int *naddrs;
+static krb5_error_code
+krb5_locate_srv_dns_1 (const krb5_data *realm,
+ const char *service,
+ const char *protocol,
+ struct addrlist *addrlist)
{
- int out, j, count;
union {
unsigned char bytes[2048];
HEADER hdr;
} answer;
unsigned char *p=NULL;
char host[MAX_DNS_NAMELEN], *h;
- struct sockaddr *addr = NULL;
- struct sockaddr_in *sin_p = NULL;
- struct hostent *hp = NULL;
int type, class;
int priority, weight, size, len, numanswers, numqueries, rdlen;
unsigned short port;
@@ -364,13 +565,7 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
struct srv_dns_entry *head = NULL;
struct srv_dns_entry *srv = NULL, *entry = NULL;
-
- out = 0;
- addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
- if (addr == NULL)
- return ENOMEM;
-
- count = 1;
+ krb5_error_code code = 0;
/*
* First off, build a query of the form:
@@ -390,19 +585,22 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
realm->data);
/* Realm names don't (normally) end with ".", but if the query
- doesn't end with "." and doesn't get an answer as is, the
- resolv code will try appending the local domain. Since the
- realm names are absolutes, let's stop that.
+ doesn't end with "." and doesn't get an answer as is, the
+ resolv code will try appending the local domain. Since the
+ realm names are absolutes, let's stop that.
- But only if a name has been specified. If we are performing
- a search on the prefix alone then the intention is to allow
- the local domain or domain search lists to be expanded.
- */
+ But only if a name has been specified. If we are performing
+ a search on the prefix alone then the intention is to allow
+ the local domain or domain search lists to be expanded. */
h = host + strlen (host);
if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
strcpy (h, ".");
+#ifdef TEST
+ fprintf (stderr, "sending DNS SRV query for %s\n", host);
+#endif
+
size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
if (size < hdrsize)
@@ -546,36 +744,20 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
if (head == NULL)
goto out;
+#ifdef TEST
+ fprintf (stderr, "walking answer list:\n");
+#endif
for (entry = head; entry != NULL; entry = entry->next) {
- hp = gethostbyname(entry->host);
- if (hp != 0) {
- switch (hp->h_addrtype) {
-#ifdef HAVE_NETINET_IN_H
- case AF_INET:
- for (j=0; hp->h_addr_list[j]; j++) {
- sin_p = (struct sockaddr_in *) &addr[out++];
- memset ((char *) sin_p, 0, sizeof (struct sockaddr));
- sin_p->sin_family = hp->h_addrtype;
- sin_p->sin_port = htons(entry->port);
- memcpy((char *) &sin_p->sin_addr,
- (char *) hp->h_addr_list[j],
- sizeof(struct in_addr));
- if (out + 1 >= count) {
- count += 5;
- addr = (struct sockaddr *)
- realloc((char *) addr,
- sizeof(struct sockaddr) * count);
- if (!addr)
- goto out;
- }
- }
- break;
-#endif /* HAVE_NETINET_IN_H */
- default:
- break;
- }
- }
+#ifdef TEST
+ fprintf (stderr, "\tport=%d host=%s\n", entry->port, entry->host);
+#endif
+ code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0);
+ if (code)
+ break;
}
+#ifdef TEST
+ fprintf (stderr, "[end]\n");
+#endif
for (entry = head; entry != NULL; ) {
free(entry->host);
@@ -590,16 +772,24 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
if (srv)
free(srv);
- if (out == 0) { /* No good servers */
- if (addr)
- free(addr);
- return KRB5_REALM_CANT_RESOLVE;
- }
+ return code;
+}
- *addr_pp = addr;
- *naddrs = out;
- return 0;
+#ifdef TEST
+static krb5_error_code
+krb5_locate_srv_dns(const krb5_data *realm,
+ const char *service, const char *protocol,
+ struct sockaddr ***addr_pp, int *naddrs)
+{
+ struct addrlist al = ADDRLIST_INIT;
+ krb5_error_code code;
+
+ code = krb5_locate_srv_dns_1 (realm, service, protocol, &al);
+ *addr_pp = al.addrs;
+ *naddrs = al.naddrs;
+ return code;
}
+#endif
#endif /* KRB5_DNS_LOOKUP */
/*
@@ -607,56 +797,77 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
*/
krb5_error_code
-krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters)
- krb5_context context;
- const krb5_data *realm;
- struct sockaddr **addr_pp;
- int *naddrs;
- int get_masters;
+krb5int_locate_server (krb5_context context, const krb5_data *realm,
+ struct sockaddr ***addr_pp, int *naddrs,
+ int get_masters,
+ const char *profname, const char *dnsname,
+ int is_stream,
+ /* network order port numbers! */
+ int dflport1, int dflport2)
{
krb5_error_code code;
+ struct addrlist al = ADDRLIST_INIT;
/*
* We always try the local file first
*/
- code = krb5_locate_srv_conf(context, realm, "kdc", addr_pp, naddrs,
- get_masters);
+ code = krb5_locate_srv_conf_1(context, realm, profname, &al, get_masters,
+ dflport1, dflport2);
#ifdef KRB5_DNS_LOOKUP
- if (code) {
- int use_dns = _krb5_use_dns_kdc(context);
- if ( use_dns ) {
- code = krb5_locate_srv_dns(realm,
- get_masters ? "_kerberos-master" : "_kerberos",
- "_udp", addr_pp, naddrs);
- }
+ if (code && dnsname != 0) {
+ int use_dns = _krb5_use_dns_kdc(context);
+ if (use_dns)
+ code = krb5_locate_srv_dns_1(realm, dnsname,
+ is_stream ? "_tcp" : "_udp", &al);
}
#endif /* KRB5_DNS_LOOKUP */
- return (code);
+#ifdef TEST
+ if (code == 0)
+ fprintf (stderr, "krb5int_locate_server found %d addresses\n",
+ al.naddrs);
+ else
+ fprintf (stderr, "krb5int_locate_server returning error code %d\n",
+ code);
+#endif
+ if (code != 0) {
+ if (al.space)
+ free_list (&al);
+ return code;
+ }
+ if (al.naddrs == 0) { /* No good servers */
+ if (al.space)
+ free_list (&al);
+ return KRB5_REALM_CANT_RESOLVE;
+ }
+ *addr_pp = al.addrs;
+ *naddrs = al.naddrs;
+ return 0;
}
-#if 0 /* Why is this useful? It's not used now, and it's certainly
- not useful if you don't have the DNS code enabled. -KR */
-
-/*
- * It turns out that it is really useful to be able to use these functions
- * for other things (like admin servers), so create an abstract function
- * for this
- */
-
krb5_error_code
-krb5_locate_server(realm, name, proto, addr_pp, naddrs)
+krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters)
+ krb5_context context;
const krb5_data *realm;
- const char *name, *proto;
- struct sockaddr **addr_pp;
+ struct sockaddr ***addr_pp;
int *naddrs;
+ int get_masters;
{
- krb5_error_code code = KRB5_REALM_UNKNOWN;
-#ifdef KRB5_DNS_LOOKUP
- code = krb5_locate_srv_dns(realm, name, proto,
- (struct sockaddr **) addr_pp, naddrs);
-#endif /* KRB5_DNS_LOOKUP */
- return (code);
+ int udpport, sec_udpport;
+
+ udpport = get_port (KDC_PORTNAME, 0, KRB5_DEFAULT_PORT);
+ sec_udpport = get_port (KDC_SECONDARY_PORTNAME, 0,
+ (udpport == htons (KRB5_DEFAULT_PORT)
+ ? KRB5_DEFAULT_SEC_PORT
+ : KRB5_DEFAULT_PORT));
+ if (sec_udpport == udpport)
+ sec_udpport = 0;
+
+ return krb5int_locate_server (context, realm, addr_pp, naddrs, get_masters,
+ "kdc",
+ (get_masters
+ ? "_kerberos-master"
+ : "_kerberos"),
+ 0, udpport, sec_udpport);
}
-#endif
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index 12e2afb48..ceba9b477 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -34,7 +34,7 @@
krb5_error_code krb5_locate_kdc
PROTOTYPE((krb5_context,
const krb5_data *,
- struct sockaddr **,
+ struct sockaddr ***,
int *,
int));
#endif
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 58c97f837..486066b56 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -63,7 +63,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
int use_master;
{
register int timeout, host, i;
- struct sockaddr *addr;
+ struct sockaddr **addr;
int naddr;
int sent, nready;
krb5_error_code retval;
@@ -90,6 +90,8 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
socklist[i] = INVALID_SOCKET;
if (!(reply->data = malloc(krb5_max_dgram_size))) {
+ for (i = 0; i < naddr; i++)
+ krb5_xfree (addr[i]);
krb5_xfree(addr);
krb5_xfree(socklist);
return ENOMEM;
@@ -133,7 +135,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
* protocol exists to support a particular socket type
* within a given protocol family.
*/
- socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0);
+ socklist[host] = socket(addr[host]->sa_family, SOCK_DGRAM, 0);
if (socklist[host] == INVALID_SOCKET)
continue; /* try other hosts */
/* have a socket to send/recv from */
@@ -143,7 +145,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
sendto, recvfrom. The connect here may return an error if
the destination host is known to be unreachable. */
if (connect(socklist[host],
- &addr[host], sizeof(addr[host])) == SOCKET_ERROR)
+ addr[host], socklen(addr[host])) == SOCKET_ERROR)
continue;
}
if (send(socklist[host],