From 4118a0c053531ed45299318a5fcececcab94a314 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Wed, 11 Feb 2009 18:20:18 -0500 Subject: - use our own bind-reserve-port helper, which should work with either ipv4 or ipv6 sockets - make portmap_register()/portmap_unregister() require the address family --- src/plug-nis.c | 124 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 45 deletions(-) (limited to 'src/plug-nis.c') diff --git a/src/plug-nis.c b/src/plug-nis.c index ae01984..19ff1dc 100644 --- a/src/plug-nis.c +++ b/src/plug-nis.c @@ -36,7 +36,6 @@ #include #include -#include #include #ifdef HAVE_TCPD_H @@ -98,9 +97,12 @@ plugin_startup(Slapi_PBlock *pb) /* Kick off any other NIS servers on the local box. */ portmap_unregister(plugin_description.spd_id, state->pmap_client_socket, - YPPROG, YPVERS); + YPPROG, YPVERS, AF_INET); /* Register our listening ports. */ for (i = 0; i < state->n_listeners; i++) { + if (state->listener[i].pf != PF_INET) { + continue; + } switch (state->listener[i].type) { case SOCK_DGRAM: protocol = IPPROTO_UDP; @@ -120,12 +122,18 @@ plugin_startup(Slapi_PBlock *pb) } if (!portmap_register(plugin_description.spd_id, state->pmap_client_socket, - YPPROG, YPVERS, protocol, + YPPROG, YPVERS, + AF_INET, protocol, state->listener[i].port)) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id, "error registering %s service " "with portmap\n", pname); + } else { + slapi_log_error(SLAPI_LOG_PLUGIN, + plugin_description.spd_id, + "registered %s service " + "with portmap\n", pname); } } } @@ -143,12 +151,14 @@ plugin_shutdown(Slapi_PBlock *pb) slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); for (i = 0; i < state->n_listeners; i++) { close(state->listener[i].fd); + state->listener[i].fd = -1; } state->n_listeners = 0; if (state->pmap_client_socket != -1) { /* Clear our registration with the portmapper. */ portmap_unregister(plugin_description.spd_id, - state->pmap_client_socket, YPPROG, YPVERS); + state->pmap_client_socket, + YPPROG, YPVERS, AF_INET); } wrap_stop_thread(state->tid); map_done(state); @@ -186,6 +196,53 @@ plugin_read_config(Slapi_PBlock *plugin_pb, int *port) } } +/* Bind to a privileged port. We don't much care which one at this point. */ +static int +plugin_bind_resvport(int fd, int family, int but_not) +{ + int i, offset, port; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + switch (family) { + case AF_INET: + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + break; + case AF_INET6: + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + break; + default: + return -1; + } + offset = getpid() % 512; + for (i = 512; i < 1024; i++) { + port = ((offset + i) % 512) + 512; + if (port == but_not) { + continue; + } + switch (family) { + case AF_INET: + sin.sin_port = htons(port); + if (bind(fd, (struct sockaddr*) &sin, + sizeof(sin)) == 0) { + return port; + } + break; + case AF_INET6: + sin6.sin6_port = htons(port); + if (bind(fd, (struct sockaddr*) &sin6, + sizeof(sin6)) == 0) { + return port; + } + break; + default: + return -1; + } + } + return 0; +} + /* Handle the part of startup that needs to be done before we drop privileges: * bind to listening ports and one more for talking to the local portmapper. */ static int @@ -238,9 +295,7 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) "error allocating portmap client socket\n"); goto failed; } - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - if (bindresvport(sockfd, &sin) != 0) { + if (plugin_bind_resvport(sockfd, AF_INET, port) <= 0) { if ((getenv(NIS_PLUGIN_CONTINUE_WITHOUT_PORTMAP_ENV) == NULL) || !atol(getenv(NIS_PLUGIN_CONTINUE_WITHOUT_PORTMAP_ENV))) { slapi_log_error(SLAPI_LOG_FATAL, @@ -248,6 +303,7 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) "error binding portmap client socket " "to a privileged port\n"); close(sockfd); + sockfd = -1; goto failed; } else { slapi_log_error(SLAPI_LOG_PLUGIN, @@ -268,10 +324,10 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) const char *sock_desc; /* Figure out what kind of socket we need, and a textual * term to use in log messages. */ - pf = (i & 2) ? PF_INET6 : PF_INET; + pf = (i & 2) ? PF_INET : PF_INET6; type = (i & 1) ? SOCK_STREAM : SOCK_DGRAM; - sock_desc = (i & 2) ? ((i & 1) ? "tcp6" : "udp6") : - ((i & 1) ? "tcp" : "udp"); + sock_desc = (i & 2) ? ((i & 1) ? "tcp" : "udp") : + ((i & 1) ? "tcp6" : "udp6"); /* Allocate the socket. */ sockfd = socket(pf, type, 0); if (sockfd == -1) { @@ -290,19 +346,22 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) "error marking %s socket for reuse, " "continuing\n", sock_desc); close(sockfd); - goto failed; + continue; } - /* Bind to the server port, if one was specified, otherwise let - * libc try to find an unused one for us. */ + /* Bind to the server port, if one was specified, otherwise try + * to find an unused one. */ memset(&sin, 0, sizeof(sin)); memset(&sin6, 0, sizeof(sin6)); sin.sin_family = AF_INET; sin6.sin6_family = AF_INET6; if (port == 0) { - ret = (pf == PF_INET6) ? bindresvport(sockfd, - (struct sockaddr_in*) &sin6) : - bindresvport(sockfd, - &sin); + port = (pf == PF_INET6) ? plugin_bind_resvport(sockfd, + AF_INET6, + 0) : + plugin_bind_resvport(sockfd, + AF_INET, + 0); + ret = (port > 0) ? 0 : -1; } else { sin.sin_port = htons(port); sin6.sin6_port = htons(port); @@ -340,39 +399,12 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) strerror(errno)); continue; } - } else { - /* Try to read back the bound address. */ - socklen_t socklen; - if (getsockname(sockfd, - (pf == PF_INET6) ? - (struct sockaddr*) &sin6 : - (struct sockaddr*) &sin, - &socklen) != 0) { - slapi_log_error(SLAPI_LOG_PLUGIN, - plugin_description.spd_id, - "error retrieving local " - "socket address: %s\n", - strerror(errno)); - } - if (socklen != - (pf == PF_INET6) ? sizeof(sin6) : sizeof(sin)) { - slapi_log_error(SLAPI_LOG_PLUGIN, - plugin_description.spd_id, - "error retrieving local " - "socket address: %s\n", - strerror(errno)); - } - } flags = fcntl(sockfd, F_GETFL); if ((flags & O_NONBLOCK) == 0) { fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); } - /* Read the port number that we ended up using, in case we used - * bindresvport[6]. */ - port = (pf == PF_INET6) ? ntohs(sin6.sin6_port) : - ntohs(sin.sin_port); - /* If it's a listening socket, let the kernel know that we're + /* If it's a stream socket, let the kernel know that we're * ready to accept client connections. */ if (type == SOCK_STREAM) { if (listen(sockfd, 128) == -1) { @@ -406,9 +438,11 @@ plugin_state_init(Slapi_PBlock *pb, struct plugin_state **lstate) failed: for (i = 0; i < state->n_listeners; i++) { close(state->listener[i].fd); + state->listener[i].fd = -1; } if (state->pmap_client_socket != -1) { close(state->pmap_client_socket); + state->pmap_client_socket = -1; } err = errno; free(state); -- cgit