summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2010-06-26 03:32:55 +0000
committerGreg Hudson <ghudson@mit.edu>2010-06-26 03:32:55 +0000
commit0080380b3b3e945c5eb84504771d9d01ee76a611 (patch)
tree39234f0c55f0a9304b935e0f38c7c9b14aa0c7cf
parent5191e163a9a39ae11e1e62f4a2e191f2d26fbb7a (diff)
downloadkrb5-0080380b3b3e945c5eb84504771d9d01ee76a611.tar.gz
krb5-0080380b3b3e945c5eb84504771d9d01ee76a611.tar.xz
krb5-0080380b3b3e945c5eb84504771d9d01ee76a611.zip
Make kadmin work over IPv6
Make gssrpc work over IPv6 TCP sockets provided that the client creates and connects/binds the sockets and doesn't query their addresses or use bindresvport(). Make kadmin work within those constraints and handle IPv6. Specific changes: * Make svctcp_create() able to extract the port from an IPv6 socket, using a new helper function getport(). * Make clnttcp_create() handle a null raddr value if *sockp is set. * Make kadm5_get_service_name() use getaddrinfo() to canonicalize the admin server name. * Make libkadm5clnt's init_any() responsible for connecting its socket using a new helper function connect_to_server(), which uses getaddrinfo instead of gethostbyname. Pass a null address to clnttcp_create(). * Make libapputil's net-server.c set up IPv6 as well as IPv4 listener ports for RPC connections. * Adjust the error code expected in a libkadm5 unit test. ticket: 6746 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24147 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/kadmin/testing/util/tcl_kadm5.c2
-rw-r--r--src/lib/apputils/net-server.c59
-rw-r--r--src/lib/kadm5/alt_prof.c16
-rw-r--r--src/lib/kadm5/clnt/client_init.c74
-rw-r--r--src/lib/kadm5/unit-test/api.current/init-v2.exp2
-rw-r--r--src/lib/rpc/clnt_tcp.c7
-rw-r--r--src/lib/rpc/svc_tcp.c32
7 files changed, 147 insertions, 45 deletions
diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
index 3a679996ed..b33cf0a0fa 100644
--- a/src/kadmin/testing/util/tcl_kadm5.c
+++ b/src/kadmin/testing/util/tcl_kadm5.c
@@ -351,6 +351,8 @@ static Tcl_DString *unparse_err(kadm5_ret_t code)
code_string = "KADM5_BAD_SERVER_NAME"; break;
case KADM5_MISSING_KRB5_CONF_PARAMS:
code_string = "KADM5_MISSING_KRB5_CONF_PARAMS"; break;
+ case KADM5_XDR_FAILURE: code_string = "KADM5_XDR_FAILURE"; break;
+ case KADM5_CANT_RESOLVE: code_string = "KADM5_CANT_RESOLVE"; break;
case OSA_ADB_DUP: code_string = "OSA_ADB_DUP"; break;
diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c
index 18582e2722..dfae9d1f5d 100644
--- a/src/lib/apputils/net-server.c
+++ b/src/lib/apputils/net-server.c
@@ -575,6 +575,20 @@ setup_a_rpc_listener(struct socksetup *data, struct sockaddr *addr)
if (setreuseaddr(sock, 1) < 0)
com_err(data->prog, errno,
"Cannot enable SO_REUSEADDR on fd %d", sock);
+#ifdef KRB5_USE_INET6
+ if (addr->sa_family == AF_INET6) {
+#ifdef IPV6_V6ONLY
+ if (setv6only(sock, 1))
+ com_err(data->prog, errno,
+ "setsockopt(%d,IPV6_V6ONLY,1) failed", sock);
+ else
+ com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked",
+ sock);
+#else
+ krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support");
+#endif /* IPV6_V6ONLY */
+ }
+#endif /* KRB5_USE_INET6 */
if (bind(sock, addr, socklen(addr)) == -1) {
com_err(data->prog, errno,
"Cannot bind RPC server socket on %s", paddr(addr));
@@ -671,6 +685,9 @@ static int
setup_rpc_listener_ports(struct socksetup *data)
{
struct sockaddr_in sin4;
+#ifdef KRB5_USE_INET6
+ struct sockaddr_in6 sin6;
+#endif
int i;
struct rpc_svc_data svc;
@@ -681,24 +698,54 @@ setup_rpc_listener_ports(struct socksetup *data)
#endif
sin4.sin_addr.s_addr = INADDR_ANY;
+#ifdef KRB5_USE_INET6
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif
+ sin6.sin6_addr = in6addr_any;
+#endif
+
FOREACH_ELT (rpc_svc_data, i, svc) {
int s4;
+#ifdef KRB5_USE_INET6
+ int s6;
+#endif
set_sa_port((struct sockaddr *)&sin4, htons(svc.port));
s4 = setup_a_rpc_listener(data, (struct sockaddr *)&sin4);
if (s4 < 0)
return -1;
+
+ if (add_rpc_listener_fd(data, &svc, s4) == NULL)
+ close(s4);
else {
- if (add_rpc_listener_fd(data, &svc, s4) == NULL)
- close(s4);
+ FD_SET(s4, &sstate.rfds);
+ if (s4 >= sstate.max)
+ sstate.max = s4 + 1;
+ krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s",
+ s4, paddr((struct sockaddr *)&sin4));
+ }
+
+#ifdef KRB5_USE_INET6
+ if (ipv6_enabled()) {
+ set_sa_port((struct sockaddr *)&sin6, htons(svc.port));
+ s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
+ if (s6 < 0)
+ return -1;
+
+ if (add_rpc_listener_fd(data, &svc, s6) == NULL)
+ close(s6);
else {
- FD_SET(s4, &sstate.rfds);
- if (s4 >= sstate.max)
- sstate.max = s4 + 1;
+ FD_SET(s6, &sstate.rfds);
+ if (s6 >= sstate.max)
+ sstate.max = s6 + 1;
krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s",
- s4, paddr((struct sockaddr *)&sin4));
+ s6, paddr((struct sockaddr *)&sin6));
}
}
+#endif
}
FD_ZERO(&rpc_listenfds);
rpc_listenfds = svc_fdset;
diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c
index bc5eb2314e..6a79655126 100644
--- a/src/lib/kadm5/alt_prof.c
+++ b/src/lib/kadm5/alt_prof.c
@@ -33,6 +33,7 @@
/*
* alt_prof.c - Implement alternate profile file handling.
*/
+#include "fake-addrinfo.h"
#include "k5-int.h"
#include <kadm5/admin.h>
#include "adm_proto.h"
@@ -882,7 +883,8 @@ kadm5_get_admin_service_name(krb5_context ctx,
{
krb5_error_code ret;
kadm5_config_params params_in, params_out;
- struct hostent *hp;
+ struct addrinfo hint, *ai = NULL;
+ int err;
memset(&params_in, 0, sizeof(params_in));
memset(&params_out, 0, sizeof(params_out));
@@ -898,8 +900,10 @@ kadm5_get_admin_service_name(krb5_context ctx,
goto err_params;
}
- hp = gethostbyname(params_out.admin_server);
- if (hp == NULL) {
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_flags = AI_CANONNAME;
+ err = getaddrinfo(params_out.admin_server, NULL, &hint, &ai);
+ if (err != 0) {
ret = KADM5_CANT_RESOLVE;
krb5_set_error_message(ctx, ret,
"Cannot resolve address of admin server \"%s\" "
@@ -907,13 +911,15 @@ kadm5_get_admin_service_name(krb5_context ctx,
realm_in);
goto err_params;
}
- if (strlen(hp->h_name) + sizeof("kadmin/") > maxlen) {
+ if (strlen(ai->ai_canonname) + sizeof("kadmin/") > maxlen) {
ret = ENOMEM;
goto err_params;
}
- snprintf(admin_name, maxlen, "kadmin/%s", hp->h_name);
+ snprintf(admin_name, maxlen, "kadmin/%s", ai->ai_canonname);
err_params:
+ if (ai != NULL)
+ freeaddrinfo(ai);
kadm5_free_config_params(ctx, &params_out);
return ret;
}
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index 9301b4bfc7..cc9664f4d4 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -40,6 +40,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <fake-addrinfo.h>
#include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
#include <krb5.h>
#ifdef __STDC__
@@ -80,6 +81,9 @@ gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
unsigned int full_svcname_len);
static kadm5_ret_t
+connect_to_server(const char *hostname, int port, int *fd);
+
+static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
char *client_name, char *full_svcname);
@@ -151,8 +155,6 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
kadm5_config_params *params_in, krb5_ui_4 struct_version,
krb5_ui_4 api_version, char **db_args, void **server_handle)
{
- struct sockaddr_in addr;
- struct hostent *hp;
int fd;
krb5_boolean iprop_enable;
@@ -271,20 +273,9 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
sizeof(full_svcname));
if (code)
goto error;
- /*
- * We have ticket; open the RPC connection.
- */
-
- hp = gethostbyname(handle->params.admin_server);
- if (hp == (struct hostent *) NULL) {
- code = KADM5_BAD_SERVER_NAME;
- goto cleanup;
- }
- /*
- * If the service_name and client_name are iprop-centric,
- * we need to clnttcp_create to the appropriate RPC prog.
- */
+ /* If the service_name and client_name are iprop-centric, use the iprop
+ * port and RPC identifiers. */
iprop_enable = (service_name != NULL &&
strstr(service_name, KIPROP_SVC_NAME) != NULL &&
strstr(client_name, KIPROP_SVC_NAME) != NULL);
@@ -298,13 +289,11 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
rpc_vers = KADMVERS;
}
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = hp->h_addrtype;
- (void) memcpy(&addr.sin_addr, hp->h_addr, sizeof(addr.sin_addr));
- addr.sin_port = htons((u_short) port);
+ code = connect_to_server(handle->params.admin_server, port, &fd);
+ if (code)
+ goto error;
- fd = RPC_ANYSOCK;
- handle->clnt = clnttcp_create(&addr, rpc_prog, rpc_vers, &fd, 0, 0);
+ handle->clnt = clnttcp_create(NULL, rpc_prog, rpc_vers, &fd, 0, 0);
if (handle->clnt == NULL) {
code = KADM5_RPC_ERROR;
#ifdef DEBUG
@@ -562,6 +551,49 @@ error:
return code;
}
+/* Set *fd to a socket connected to hostname and port. */
+static kadm5_ret_t
+connect_to_server(const char *hostname, int port, int *fd)
+{
+ struct addrinfo hint, *addrs, *a;
+ char portbuf[32];
+ int err, s;
+ kadm5_ret_t code;
+
+ /* Look up the server's addresses. */
+ (void) snprintf(portbuf, sizeof(portbuf), "%d", port);
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_socktype = SOCK_STREAM;
+#ifdef AI_NUMERICSERV
+ hint.ai_flags = AI_NUMERICSERV;
+#endif
+ err = getaddrinfo(hostname, portbuf, &hint, &addrs);
+ if (err != 0)
+ return KADM5_CANT_RESOLVE;
+
+ /* Try to connect to each address until we succeed. */
+ for (a = addrs; a != NULL; a = a->ai_next) {
+ s = socket(a->ai_family, a->ai_socktype, 0);
+ if (s == -1) {
+ code = KADM5_FAILURE;
+ goto cleanup;
+ }
+ err = connect(s, a->ai_addr, a->ai_addrlen);
+ if (err == 0) {
+ *fd = s;
+ code = 0;
+ goto cleanup;
+ }
+ close(s);
+ }
+
+ /* We didn't succeed on any address. */
+ code = KADM5_RPC_ERROR;
+cleanup:
+ freeaddrinfo(addrs);
+ return code;
+}
+
/* Acquire GSSAPI credentials and set up RPC auth flavor. */
static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/unit-test/api.current/init-v2.exp
index a364b9c140..7a353d4e9c 100644
--- a/src/lib/kadm5/unit-test/api.current/init-v2.exp
+++ b/src/lib/kadm5/unit-test/api.current/init-v2.exp
@@ -70,7 +70,7 @@ proc test102 {} {
[config_params {KADM5_CONFIG_ADMIN_SERVER} does.not.exist] \
$KADM5_STRUCT_VERSION $KADM5_API_VERSION_3 \
server_handle
- } "BAD_SERVER_NAME"
+ } "CANT_RESOLVE"
}
if {$RPC} test102
diff --git a/src/lib/rpc/clnt_tcp.c b/src/lib/rpc/clnt_tcp.c
index 0eb8f45dd0..cfa44c0e2c 100644
--- a/src/lib/rpc/clnt_tcp.c
+++ b/src/lib/rpc/clnt_tcp.c
@@ -150,7 +150,7 @@ clnttcp_create(
/*
* If no port number given ask the pmap for one
*/
- if (raddr->sin_port == 0) {
+ if (raddr != NULL && raddr->sin_port == 0) {
u_short port;
if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
mem_free((caddr_t)ct, sizeof(struct ct_data));
@@ -185,7 +185,10 @@ clnttcp_create(
ct->ct_sock = *sockp;
ct->ct_wait.tv_usec = 0;
ct->ct_waitset = FALSE;
- ct->ct_addr = *raddr;
+ if (raddr == NULL)
+ memset(&ct->ct_addr, 0, sizeof(ct->ct_addr));
+ else
+ ct->ct_addr = *raddr;
/*
* Initialize call message
diff --git a/src/lib/rpc/svc_tcp.c b/src/lib/rpc/svc_tcp.c
index 796627f2fb..b9aee070f9 100644
--- a/src/lib/rpc/svc_tcp.c
+++ b/src/lib/rpc/svc_tcp.c
@@ -116,6 +116,17 @@ struct tcp_conn { /* kept in xprt->xp_p1 */
char verf_body[MAX_AUTH_BYTES];
};
+static u_short
+getport(struct sockaddr *addr)
+{
+ if (addr->sa_family == AF_INET)
+ return ntohs(((struct sockaddr_in *) addr)->sin_port);
+ else if (addr->sa_family == AF_INET6)
+ return ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
+ else
+ return 0;
+}
+
/*
* Usage:
* xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
@@ -145,8 +156,9 @@ svctcp_create(
bool_t madesock = FALSE;
register SVCXPRT *xprt;
register struct tcp_rendezvous *r;
- struct sockaddr_in addr;
- int len = sizeof(struct sockaddr_in);
+ struct sockaddr_in sin;
+ struct sockaddr_storage addr;
+ socklen_t len = sizeof(addr);
if (sock == RPC_ANYSOCK) {
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
@@ -156,14 +168,14 @@ svctcp_create(
set_cloexec_fd(sock);
madesock = TRUE;
}
- memset(&addr, 0, sizeof (addr));
+ memset(&sin, 0, sizeof(sin));
#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- addr.sin_len = sizeof(addr);
+ sin.sin_len = sizeof(sin);
#endif
- addr.sin_family = AF_INET;
- if (bindresvport(sock, &addr)) {
- addr.sin_port = 0;
- (void)bind(sock, (struct sockaddr *)&addr, len);
+ sin.sin_family = AF_INET;
+ if (bindresvport(sock, &sin)) {
+ sin.sin_port = 0;
+ (void)bind(sock, (struct sockaddr *)&sin, len);
}
if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
perror("svc_tcp.c - cannot getsockname");
@@ -194,7 +206,7 @@ svctcp_create(
xprt->xp_auth = NULL;
xprt->xp_verf = gssrpc__null_auth;
xprt->xp_ops = &svctcp_rendezvous_op;
- xprt->xp_port = ntohs(addr.sin_port);
+ xprt->xp_port = getport((struct sockaddr *) &addr);
xprt->xp_sock = sock;
xprt->xp_laddrlen = 0;
xprt_register(xprt);
@@ -274,7 +286,7 @@ rendezvous_request(
SOCKET sock;
struct tcp_rendezvous *r;
struct sockaddr_in addr, laddr;
- int len, llen;
+ socklen_t len, llen;
r = (struct tcp_rendezvous *)xprt->xp_p1;
again: