svn rev #24147: trunk/src/ kadmin/testing/util/ lib/apputils/ lib/kadm5/ lib/kadm5/clnt/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Fri Jun 25 23:32:56 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24147
Commit By: ghudson
Log Message:
ticket: 6746
subject: 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.



Changed Files:
U   trunk/src/kadmin/testing/util/tcl_kadm5.c
U   trunk/src/lib/apputils/net-server.c
U   trunk/src/lib/kadm5/alt_prof.c
U   trunk/src/lib/kadm5/clnt/client_init.c
U   trunk/src/lib/kadm5/unit-test/api.current/init-v2.exp
U   trunk/src/lib/rpc/clnt_tcp.c
U   trunk/src/lib/rpc/svc_tcp.c
Modified: trunk/src/kadmin/testing/util/tcl_kadm5.c
===================================================================
--- trunk/src/kadmin/testing/util/tcl_kadm5.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/kadmin/testing/util/tcl_kadm5.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -351,6 +351,8 @@
         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;

Modified: trunk/src/lib/apputils/net-server.c
===================================================================
--- trunk/src/lib/apputils/net-server.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/apputils/net-server.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -575,6 +575,20 @@
     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 @@
 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 @@
 #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;

Modified: trunk/src/lib/kadm5/alt_prof.c
===================================================================
--- trunk/src/lib/kadm5/alt_prof.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/kadm5/alt_prof.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -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 @@
 {
     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 @@
         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 @@
                                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;
 }

Modified: trunk/src/lib/kadm5/clnt/client_init.c
===================================================================
--- trunk/src/lib/kadm5/clnt/client_init.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/kadm5/clnt/client_init.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -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 @@
          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 @@
          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 @@
                           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 @@
         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 @@
     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,

Modified: trunk/src/lib/kadm5/unit-test/api.current/init-v2.exp
===================================================================
--- trunk/src/lib/kadm5/unit-test/api.current/init-v2.exp	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/kadm5/unit-test/api.current/init-v2.exp	2010-06-26 03:32:55 UTC (rev 24147)
@@ -70,7 +70,7 @@
 		[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
 

Modified: trunk/src/lib/rpc/clnt_tcp.c
===================================================================
--- trunk/src/lib/rpc/clnt_tcp.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/rpc/clnt_tcp.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -150,7 +150,7 @@
 	/*
 	 * 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 @@
 	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

Modified: trunk/src/lib/rpc/svc_tcp.c
===================================================================
--- trunk/src/lib/rpc/svc_tcp.c	2010-06-25 22:26:04 UTC (rev 24146)
+++ trunk/src/lib/rpc/svc_tcp.c	2010-06-26 03:32:55 UTC (rev 24147)
@@ -116,6 +116,17 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
         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:




More information about the cvs-krb5 mailing list