summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.c593
-rw-r--r--src/lib/krb5/os/os-proto.h2
-rw-r--r--src/lib/krb5/os/sendto_kdc.c8
5 files changed, 434 insertions, 646 deletions
diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c
index d3c842a86e..d0d0dc21dd 100644
--- a/src/lib/krb5/os/accessor.c
+++ b/src/lib/krb5/os/accessor.c
@@ -37,7 +37,6 @@ 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 1eefe6d986..61cfea01ff 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -8,7 +8,7 @@
* 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
@@ -49,21 +49,6 @@
#endif
#endif /* _WIN32 && !__CYGWIN32__ */
-/* There's a lot of confusion between pointers to different sockaddr
- types, and pointers with different degrees of indirection. Use
- this function in this file to ensure we don't do something silly
- like cast a "sockaddr **" to a "sockaddr_in *". */
-static struct sockaddr_in *sa2sin (struct sockaddr *sa)
-{
- return (struct sockaddr_in *) sa;
-}
-#ifdef KRB5_USE_INET6xxNotUsed
-static struct sockaddr_in6 *sa2sin6 (struct sockaddr *sa)
-{
- return (struct sockaddr_in6 *) sa;
-}
-#endif
-
/*
* Wrapper function for the two backends
*/
@@ -72,30 +57,54 @@ 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;
- code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
- "kpasswd_server", "_kpasswd", 0,
- DEFAULT_KPASSWD_PORT, 0);
+ /*
+ * We always try the local file first
+ */
+
+ code = krb5_locate_srv_conf(context, realm, "kpasswd_server",
+ addr_pp, naddrs, 0);
if (code) {
- 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);
- }
- }
+ 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
+ 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);
+ }
+ }
+ }
+ }
+ }
+#endif /* KRB5_DNS_LOOKUP */
return (code);
}
@@ -116,7 +125,7 @@ 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, local_addr, remote_addr, tmp_addr;
int naddr_p;
int cc, local_result_code, tmp_len;
SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET;
@@ -128,18 +137,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;
@@ -147,7 +156,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
@@ -159,207 +168,212 @@ 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) {
- 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;
-
- 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);
-
- if (getsockname(s2, &local_addr, &addrlen) < 0) {
- if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
- continue; /* try the next addr */
-
+ if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+ {
code = SOCKET_ERRNO;
goto cleanup;
- }
-
- /* some brain-dead OS's don't return useful information from
- * the getsockname call. Namely, windows and solaris. */
-
- if (sa2sin(&local_addr)->sin_addr.s_addr != 0) {
- local_kaddr.addrtype = ADDRTYPE_INET;
- local_kaddr.length = sizeof(sa2sin(&local_addr)->sin_addr);
- local_kaddr.contents = (krb5_octet *) &sa2sin(&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 */
+ }
+ if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+ {
code = SOCKET_ERRNO;
goto cleanup;
- }
-
- remote_kaddr.addrtype = ADDRTYPE_INET;
- remote_kaddr.length = sizeof(sa2sin(&remote_addr)->sin_addr);
- remote_kaddr.contents = (krb5_octet *) &sa2sin(&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,
- 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;
+ }
+
+ 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);
- if (result_code_string) {
- if ((code = krb5_chpw_result_code_string(context,
- local_result_code,
- &code_string)))
+ 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;
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;
- goto cleanup;
- }
+ }
code = SOCKET_ERRNO;
-
+
cleanup:
- 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);
-
+ 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);
+
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 808f868fc1..48a0147700 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,2000,2001 by the Massachusetts Institute of Technology.
+ * Copyright 1990 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -50,6 +50,9 @@
#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
@@ -104,286 +107,32 @@ _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;
-
- newaddrs = realloc (lp->addrs, 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", addr->sa_family);
- 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)
- return err;
- }
- copy = malloc (len);
- if (copy == NULL)
- return errno;
- memcpy (copy, addr, len);
- lp->addrs[lp->naddrs++] = copy;
- 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, duh. */
- 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
-
-/* There's also gethostbyname_r, which is IPv4-only but thread-safe;
- it wants the caller to supply scratch space and a hostent
- structure. Let's go for IPv6 support before thread safety, though;
- it's easier to accomplish, and will probably be finished first
- anyways. */
-#if !defined (HAVE_GETADDRINFO) && !defined (HAVE_GETIPNODEBYNAME)
-#undef getipnodebyname
-#define freehostent(X) ((void)(X))
-#ifdef HAVE_GETHOSTBYNAME2
-#define getipnodebyname(NAME,AF,FLAGS,ERRP) (gethostbyname2(NAME,AF))
-#else
-#define getipnodebyname(NAME,AF,FLAGS,ERRP) ((AF)==AF_INET?gethostbyname(NAME):(struct hostent *)0)
-#endif
-#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
- int err;
- struct hostent *hp;
- int i;
-
-#ifdef TEST
- fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname, port, secport);
-#endif
-
- hp = getipnodebyname (hostname, AF_INET, 0, &err);
- 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;
- }
- freehostent (hp);
- }
-#if defined (KRB5_USE_INET6)
- hp = getipnodebyname (hostname, AF_INET6, 0, &err); /* NOT THREAD SAFE */
- if (hp != NULL) {
- for (i = 0; hp->h_addr_list[i] != 0; i++) {
- struct sockaddr_in6 sin6;
-
- memset (&sin6, 0, sizeof (sin6));
- memcpy (&sin6.sin6_addr, hp->h_addr_list[i],
- sizeof (sin6.sin6_addr));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = port;
- err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6,
- sizeof (sin6));
- if (err)
- break;
- if (secport != 0) {
- sin6.sin6_port = secport;
- err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6,
- sizeof (sin6));
- if (err)
- break;
- }
- }
- freehostent (hp);
- }
-#endif
- 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
*/
-static krb5_error_code
-krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
- udpport, sec_udpport)
+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 addrlist *addrlist;
+ struct sockaddr **addr_pp;
+ int *naddrs;
int get_masters;
- int udpport, sec_udpport;
{
const char *realm_srv_names[4];
char **masterlist, **hostlist, *host, *port, *cp;
krb5_error_code code;
- 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));
+ 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;
#endif
if ((host = malloc(realm->length + 1)) == NULL)
@@ -409,6 +158,27 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, 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++;
@@ -416,7 +186,7 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
if (count == 0) {
profile_free_list(hostlist);
krb5_xfree(host);
- addrlist->naddrs = 0;
+ *naddrs = 0;
return 0;
}
@@ -462,9 +232,16 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
count = count * 2;
#endif
- for (i=0; hostlist[i]; i++) {
- int p1, p2;
+ 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, out=0; hostlist[i]; i++) {
host = hostlist[i];
/*
* Strip off excess whitespace
@@ -481,6 +258,10 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
port++;
}
+ if ((hp = gethostbyname(hostlist[i])) == 0) {
+ continue;
+ }
+
ismaster = 0;
if (masterlist) {
for (j=0; masterlist[j]; j++) {
@@ -490,37 +271,44 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
}
}
- if (get_masters && !ismaster)
- continue;
+ if ( !get_masters || ismaster ) {
+ switch (hp->h_addrtype) {
- 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);
+#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;
#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) {
- if (hostlist)
- profile_free_list (hostlist);
- if (masterlist)
- profile_free_list (masterlist);
- return code;
- }
+ default:
+ break;
+ }
+ }
}
if (hostlist)
@@ -528,56 +316,40 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
if (masterlist)
profile_free_list(masterlist);
- return 0;
-}
-
-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 (out == 0) { /* Couldn't resolve any KDC names */
+ free (addr_p);
+ return KRB5_REALM_CANT_RESOLVE;
}
- if (al.naddrs == 0) /* Couldn't resolve any KDC names */
- return KRB5_REALM_CANT_RESOLVE;
- *addr_pp = al.addrs;
- *naddrs = al.naddrs;
+
+ *addr_pp = addr_p;
+ *naddrs = out;
return 0;
}
-
#ifdef KRB5_DNS_LOOKUP
/*
* Lookup a KDC via DNS SRV records
*/
-static krb5_error_code
-krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
+krb5_error_code
+krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
const krb5_data *realm;
const char *service;
const char *protocol;
- struct addrlist *addrlist;
+ struct sockaddr **addr_pp;
+ int *naddrs;
{
+ 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;
@@ -592,7 +364,13 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
struct srv_dns_entry *head = NULL;
struct srv_dns_entry *srv = NULL, *entry = NULL;
- krb5_error_code code = 0;
+
+ out = 0;
+ addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
+ if (addr == NULL)
+ return ENOMEM;
+
+ count = 1;
/*
* First off, build a query of the form:
@@ -612,22 +390,19 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
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)
@@ -771,20 +546,36 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
if (head == NULL)
goto out;
-#ifdef TEST
- fprintf (stderr, "walking answer list:\n");
-#endif
for (entry = head; entry != NULL; entry = entry->next) {
-#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;
+ 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, "[end]\n");
-#endif
for (entry = head; entry != NULL; ) {
free(entry->host);
@@ -799,22 +590,15 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
if (srv)
free(srv);
- return code;
-}
-
-static 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;
-{
- struct addrlist al = ADDRLIST_INIT;
- krb5_error_code code;
+ if (out == 0) { /* No good servers */
+ if (addr)
+ free(addr);
+ return KRB5_REALM_CANT_RESOLVE;
+ }
- code = krb5_locate_srv_dns_1 (realm, service, protocol, &al);
- return code;
+ *addr_pp = addr;
+ *naddrs = out;
+ return 0;
}
#endif /* KRB5_DNS_LOOKUP */
@@ -823,63 +607,56 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
*/
krb5_error_code
-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_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;
{
krb5_error_code code;
- struct addrlist al = ADDRLIST_INIT;
/*
* We always try the local file first
*/
- code = krb5_locate_srv_conf(context, realm, profname, &al, get_masters);
+ code = krb5_locate_srv_conf(context, realm, "kdc", addr_pp, naddrs,
+ get_masters);
#ifdef KRB5_DNS_LOOKUP
if (code) {
- int use_dns = _krb5_use_dns_kdc(context);
- if (use_dns)
- code = krb5_locate_srv_dns(realm, dnsname,
- is_stream ? "_tcp" : "_udp", &al);
+ 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);
+ }
}
#endif /* KRB5_DNS_LOOKUP */
- if (al.naddrs == 0) { /* No good servers */
- return KRB5_REALM_CANT_RESOLVE;
- }
- if (code == 0) {
- *addr_pp = al.addrs;
- *naddrs = al.naddrs;
- }
- return code;
+ return (code);
}
+#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_kdc(context, realm, addr_pp, naddrs, get_masters)
- krb5_context context;
+krb5_locate_server(realm, name, proto, addr_pp, naddrs)
const krb5_data *realm;
- struct sockaddr ***addr_pp;
+ const char *name, *proto;
+ struct sockaddr **addr_pp;
int *naddrs;
- int get_masters;
{
- 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);
+ 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);
}
+#endif
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index ceba9b477f..12e2afb481 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 86665b412b..58c97f837c 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,8 +90,6 @@ 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;
@@ -135,7 +133,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 */
@@ -145,7 +143,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], sizeof(addr[host])) == SOCKET_ERROR)
continue;
}
if (send(socklist[host],