summaryrefslogtreecommitdiffstats
path: root/src/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugin.c')
-rw-r--r--src/plugin.c248
1 files changed, 91 insertions, 157 deletions
diff --git a/src/plugin.c b/src/plugin.c
index b4a662d..7741593 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
+#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
@@ -22,6 +23,7 @@
#include <plarenas.h>
#include <dirsrv/slapi-plugin.h>
+#include "dispatch.h"
#include "nis.h"
#include "plugin.h"
#include "portmap.h"
@@ -34,93 +36,24 @@
static Slapi_PluginDesc
plugin_description = {
.spd_id = "nis-plugin",
- .spd_vendor = "hamdingers.org",
+ .spd_vendor = "badvocacy.net",
.spd_version = PACKAGE_VERSION,
- .spd_description = "NIS Service Plugin",
+ .spd_description = "NIS Server Plugin",
};
-static void *
-listener_thread(void *p)
-{
- struct plugin_state *state = p;
- struct pollfd fds[4];
- int client, reqsize, i;
- char dgram[65536];
- struct sockaddr_storage client_addr;
- socklen_t client_addrlen;
- for (;;) {
- /* Set up for polling. */
- memset(&fds, 0, sizeof(fds));
- for (i = 0; i < state->n_listeners; i++) {
- fds[i].fd = state->listenfd[i];
- fds[i].events = POLLIN;
- }
- switch (poll(fds, state->n_listeners, -1) != -1) {
- case -1:
- return NULL;
- break;
- case 0:
- continue;
- default:
- /* Iterate over listening sockets with work for us. */
- for (i = 0; i < state->n_listeners; i++) {
- if ((fds[i].revents & POLLIN) == 0) {
- continue;
- }
- switch (state->sock_type[i]) {
- case SOCK_DGRAM:
- client_addrlen = sizeof(client_addr);
- reqsize = recvfrom(fds[i].fd,
- dgram,
- sizeof(dgram),
- 0,
- (struct sockaddr *) &client_addr,
- &client_addrlen);
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "datagram request\n");
- nis_process_request(state, fds[i].fd,
- (struct sockaddr *)
- &client_addr,
- client_addrlen,
- dgram, reqsize);
- break;
- case SOCK_STREAM:
- client = accept(fds[i].fd, NULL, NULL);
- if (client != -1) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "new stream request\n");
- stream_client_start(state,
- client);
- }
- break;
- default:
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "unknown request\n");
- break;
- }
- }
- }
- }
- return state;
-}
-
/* Start the plugin's work thread. */
static int
-plugin_start(Slapi_PBlock *pb)
+plugin_startup(Slapi_PBlock *pb)
{
struct plugin_state *state;
const char *pname;
int i, protocol;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
- slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
- "plugin starting\n");
+ slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start", "plugin starting\n");
/* Register the listener sockets with the portmapper. */
- if (state->resvport != -1) {
+ if (state->pmap_client_socket != -1) {
for (i = 0; i < state->n_listeners; i++) {
- switch (state->sock_type[i]) {
+ switch (state->listener[i].type) {
case SOCK_DGRAM:
protocol = IPPROTO_UDP;
pname = "UDP";
@@ -130,16 +63,16 @@ plugin_start(Slapi_PBlock *pb)
pname = "TCP";
break;
default:
- protocol = IPPROTO_IP;
- pname = "IP";
+ /* never reached */
+ assert(0);
break;
}
if (protocol == IPPROTO_IP) {
continue;
}
- if (!portmap_register(state->resvport,
+ if (!portmap_register(state->pmap_client_socket,
YPPROG, YPVERS, protocol,
- state->listenport[i])) {
+ state->listener[i].port)) {
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
"error registering %s service "
@@ -149,7 +82,7 @@ plugin_start(Slapi_PBlock *pb)
}
/* Start a new listening thread to handle incoming traffic. FIXME:
* switch to using NSPR's threading facilities. */
- if (pthread_create(&state->tid, NULL, &listener_thread, state) != 0) {
+ if (pthread_create(&state->tid, NULL, &dispatch_thread, state) != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
"error starting listener thread\n");
@@ -162,24 +95,27 @@ plugin_start(Slapi_PBlock *pb)
/* Stop the plugin's work thread. */
static int
-plugin_close(Slapi_PBlock *pb)
+plugin_shutdown(Slapi_PBlock *pb)
{
struct plugin_state *state;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
- if (state->resvport != -1) {
+ if (state->pmap_client_socket != -1) {
/* Clear our registration with the portmapper. */
- portmap_unregister(state->resvport, YPPROG, YPVERS);
- close(state->resvport);
+ portmap_unregister(state->pmap_client_socket, YPPROG, YPVERS);
}
return 0;
}
+/* Handle the part of startup that needs to be done before we drop privileges:
+ * bind to listening ports. */
static int
-setup_listener_sockets(struct plugin_state **lstate)
+plugin_state_init(struct plugin_state **lstate)
{
- int sockfd = -1, err, i;
- struct plugin_state *state;
+ int sockfd = -1, err, i, j;
+ struct plugin_state *state = NULL;
PLArenaPool *arena = NULL;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
arena = PORT_NewArena(sizeof(double));
if (arena == NULL) {
@@ -191,61 +127,44 @@ setup_listener_sockets(struct plugin_state **lstate)
}
state->arena = arena;
- /* Bind to a privileged port so that the portmapper will let us
- * register after we've dropped to a non-root account. We could reuse
- * the datagram listening socket we'll create later. */
- state->resvport = socket(PF_INET, SOCK_DGRAM, 0);
- if (bindresvport(state->resvport, NULL) != 0) {
+ /* Bind to a privileged port now so that the portmapper will let us
+ * register after the server's dropped privileges. */
+ state->pmap_client_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ memset(&sin, 0, sizeof(sin));
+ if (bindresvport(state->pmap_client_socket, &sin) != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
- "error setting up portmap client socket, %d\n",
- (int)getuid());
- close(state->resvport);
- state->resvport = -1;
+ "error setting up portmap client socket, %ld\n",
+ (long) getuid());
+ close(state->pmap_client_socket);
+ state->pmap_client_socket = -1;
+ goto failed;
}
- /* Privileged port, datagram and stream, IPv4 and IPv6. */
+ /* We need to bind on privileged ports for both datagram and connected
+ * listeners, over both IPv4 and IPv6. */
+ state->n_listeners = 0;
for (i = 0; i < 4; i++) {
- int sock_pf, sock_type, one = 1;
- struct sockaddr *addr;
- socklen_t addrlen;
- struct sockaddr_storage ss;
- struct sockaddr_in *addr4 = (struct sockaddr_in *) &ss;
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &ss;
+ int pf, type, fd, one, port, ret;
const char *sock_desc;
- u_int16_t *port;
- memset(&ss, 0, sizeof(ss));
- switch (i) {
- case 0:
- sock_pf = PF_INET;
- sock_type = SOCK_DGRAM;
- sock_desc = "udp";
- addr4->sin_family = AF_INET;
- port = &addr4->sin_port;
- break;
- case 1:
- sock_pf = PF_INET;
- sock_type = SOCK_STREAM;
- sock_desc = "tcp";
- addr4->sin_family = AF_INET;
- port = &addr4->sin_port;
- break;
- case 2:
- sock_pf = PF_INET6;
- sock_type = SOCK_DGRAM;
- sock_desc = "udp6";
- addr6->sin6_family = AF_INET6;
- port = &addr6->sin6_port;
- break;
- case 3:
- sock_pf = PF_INET6;
- sock_type = SOCK_STREAM;
- sock_desc = "tcp6";
- addr6->sin6_family = AF_INET6;
- port = &addr6->sin6_port;
- break;
+ /* Before we do anything else, on our second trip through, make
+ * sure that the first socket was created, because we'll need
+ * it for communicating with the portmapper. */
+ if ((i > 0) && (state->n_listeners == 0)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "no socket available to use for "
+ "communicating with portmapper\n");
+ continue;
}
- sockfd = socket(sock_pf, sock_type, 0);
+ /* Figure out what kind of socket we need, and a textual
+ * term to use in log messages. */
+ pf = (i & 2) ? PF_INET6 : PF_INET;
+ type = (i & 1) ? SOCK_STREAM : SOCK_DGRAM;
+ sock_desc = (i & 2) ? ((i & 1) ? "tcp6" : "udp6") :
+ ((i & 1) ? "tcp" : "udp");
+ /* Allocate the socket. */
+ sockfd = socket(pf, type, 0);
if (sockfd == -1) {
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
@@ -253,6 +172,7 @@ setup_listener_sockets(struct plugin_state **lstate)
sock_desc);
continue;
}
+ /* Mark the socket as reusable. */
if (setsockopt(sockfd, IPPROTO_IP, SO_REUSEADDR,
&one, sizeof(one)) != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN,
@@ -260,7 +180,10 @@ setup_listener_sockets(struct plugin_state **lstate)
"error marking %s socket for reuse\n",
sock_desc);
}
- if (bindresvport(sockfd, (struct sockaddr_in *) &ss) != 0) {
+ /* Bind to a reserved port. */
+ ret = (pf == PF_INET6) ? bindresvport6(sockfd, &sin6) :
+ bindresvport(sockfd, &sin);
+ if (ret != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
"error binding %s socket to a "
@@ -269,28 +192,37 @@ setup_listener_sockets(struct plugin_state **lstate)
close(sockfd);
continue;
}
- if ((sock_type == SOCK_STREAM) && (listen(sockfd, 128) == -1)) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "error marking %s socket for "
- "listening: %s\n", sock_desc,
- strerror(errno));
- close(sockfd);
- continue;
+ /* Pick out the port number that we got back. */
+ port = (pf == PF_INET6) ? htons(sin6.sin6_port) :
+ htons(sin.sin_port);
+ /* If it's a listening socket, let the kernel know that we're
+ * ready to accept client connections. */
+ if (type == SOCK_STREAM) {
+ if (listen(sockfd, 128) == -1) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "error marking %s socket for "
+ "listening: %s\n", sock_desc,
+ strerror(errno));
+ close(sockfd);
+ continue;
+ }
}
+ /* Save the first socket for reuse as the portmap client
+ * socket. */
if (i == 0) {
- state->resvport = sockfd;
+ state->pmap_client_socket = sockfd;
}
- state->listenfd[state->n_listeners] = sockfd;
- state->listenport[state->n_listeners] = ntohs(*port);
- state->sock_pf[state->n_listeners] = sock_pf;
- state->sock_type[state->n_listeners] = sock_type;
+ /* Save the other info. */
+ state->listener[state->n_listeners].fd = sockfd;
+ state->listener[state->n_listeners].port = port;
+ state->listener[state->n_listeners].pf = pf;
+ state->listener[state->n_listeners].type = type;
slapi_log_error(SLAPI_LOG_PLUGIN,
plugin_description.spd_id,
- "listening on port %d for %s%s clients\n",
- state->listenport[state->n_listeners],
- sock_type == SOCK_STREAM ? "tcp" : "udp",
- sock_pf == PF_INET6 ? "6" : "");
+ "listening on port %d for %s clients\n",
+ state->listener[state->n_listeners].port,
+ sock_desc);
state->n_listeners++;
}
slapi_log_error(SLAPI_LOG_PLUGIN,
@@ -311,15 +243,17 @@ int
nis_plugin_init(Slapi_PBlock *pb)
{
struct plugin_state *state = NULL;
- if (setup_listener_sockets(&state) == -1) {
+ /* Allocate a memory pool and start listening for connections. */
+ if (plugin_state_init(&state) == -1) {
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
- "error setting up listening sockets\n");
+ "error setting up plugin\n");
return -1;
}
+ /* Register the plugin with the server. */
slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
- slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, &plugin_start);
- slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, &plugin_close);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, &plugin_startup);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, &plugin_shutdown);
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &state->plugin_identity);
state->plugin_desc = &plugin_description;
slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, state);