summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile2
-rw-r--r--src/plugin.c318
-rw-r--r--src/plugin.ldif2
-rw-r--r--src/portmap.c211
-rw-r--r--src/portmap.h10
-rw-r--r--src/schema.c43
-rw-r--r--src/schema.h10
7 files changed, 433 insertions, 163 deletions
diff --git a/src/Makefile b/src/Makefile
index 0454c12..53efd4d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
CFLAGS = -g3 -Wall -Wimplicit -Wextra -Wno-unused -fPIC -D_REENTRANT $(shell pkg-config --cflags nspr nss)
LDFLAGS = -lnsl -lpthread
-plugin.so: plugin.c
+plugin.so: plugin.c portmap.c schema.c
$(CC) $(CFLAGS) -shared -o $@ $^ $(LDFLAGS)
diff --git a/src/plugin.c b/src/plugin.c
index 885ccde..333dbee 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -22,155 +22,37 @@
#include <plarenas.h>
#include <dirsrv/slapi-plugin.h>
+#include "portmap.h"
+#include "schema.h"
+
#define PACKAGE_VERSION "0.0"
#define PORT 388
/* the module initialization function */
static Slapi_PluginDesc
plugin_description = {
- .spd_id = "my-plugin",
+ .spd_id = "nis-plugin",
.spd_vendor = "hamdingers.org",
.spd_version = PACKAGE_VERSION,
- .spd_description = "sample plugin",
-};
-struct domain {
- char *domain;
- struct map {
- char *name;
- char *key;
- char *format;
- } *maps;
- int n_maps;
+ .spd_description = "NIS Service Plugin",
};
-struct state {
+
+struct plugin_state {
+ PLArenaPool *arena;
pthread_t tid;
Slapi_ComponentId *plugin_identity;
- PLArenaPool *arena;
- int listeners;
+ int resvport;
+ int n_listeners;
int listenfd[4];
int sock_pf[4];
int sock_type[4];
};
+
struct search_stream_data {
- struct state *state;
+ struct plugin_state *state;
int client;
};
-struct map default_maps[] = {
- {"passwd.byname", "uid", "uid"},
- {"passwd.bynumber", "uidNumber", "uid"},
-};
-struct domain local_domains = {
- ".local",
- default_maps,
- sizeof(default_maps) / sizeof(default_maps[0]),
-};
-
-static int
-setup_listeners(struct state **lstate)
-{
- int sockfd = -1, err, i;
- struct sockaddr_in addr4;
- struct sockaddr_in6 addr6;
- struct state *state;
- PLArenaPool *arena = NULL;
-
- arena = PORT_NewArena(sizeof(double));
- if (arena == NULL) {
- goto failed;
- }
- state = PORT_ArenaZAlloc(arena, sizeof(*state));
- if (state == NULL) {
- goto failed;
- }
- state->arena = arena;
-
- for (i = 0; i < 4; i++) {
- int sock_pf, sock_type, one = 1;
- struct sockaddr *addr;
- socklen_t addrlen;
- switch (i) {
- case 0:
- sock_pf = PF_INET;
- sock_type = SOCK_DGRAM;
- addr = (struct sockaddr *) &addr4;
- addrlen = sizeof(addr4);
- break;
- case 1:
- sock_pf = PF_INET;
- sock_type = SOCK_STREAM;
- addr = (struct sockaddr *) &addr4;
- addrlen = sizeof(addr4);
- break;
- case 2:
- sock_pf = PF_INET6;
- sock_type = SOCK_DGRAM;
- addr = (struct sockaddr *) &addr6;
- addrlen = sizeof(addr6);
- break;
- case 3:
- sock_pf = PF_INET6;
- sock_type = SOCK_STREAM;
- addr = (struct sockaddr *) &addr6;
- addrlen = sizeof(addr6);
- break;
- }
- memset(&addr4, 0, sizeof(addr4));
- addr4.sin_port = htons(PORT);
- memset(&addr6, 0, sizeof(addr6));
- addr6.sin6_port = htons(PORT);
- sockfd = socket(sock_pf, sock_type, 0);
- if (sockfd == -1) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "error creating a listening socket\n");
- continue;
- }
- if (setsockopt(sockfd, IPPROTO_IP, SO_REUSEADDR,
- &one, sizeof(one)) != 0) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "error marking socket for reuse\n");
- }
- if (bind(sockfd, addr, addrlen) != 0) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "error binding to listening port\n");
- close(sockfd);
- continue;
- }
- if ((sock_type == SOCK_STREAM) && (listen(sockfd, 128) == -1)) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "error marking socket for listening\n");
- close(sockfd);
- continue;
- }
- state->listenfd[state->listeners] = sockfd;
- state->sock_pf[state->listeners] = sock_pf;
- state->sock_type[state->listeners] = sock_type;
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "listening on port %d for %s%s clients\n",
- PORT,
- sock_type == SOCK_STREAM ? "tcp" : "udp",
- sock_pf == PF_INET6 ? "6" : "");
- state->listeners++;
- }
- slapi_log_error(SLAPI_LOG_PLUGIN,
- plugin_description.spd_id,
- "set up %d listening sockets\n", state->listeners);
- *lstate = state;
- return 0;
-failed:
- err = errno;
- if (arena != NULL) {
- PORT_FreeArena(arena, PR_TRUE);
- }
- errno = err;
- return -1;
-}
-
static void
cb_stream_result(int rc, void *callback_data)
{
@@ -231,7 +113,7 @@ cb_stream_referral(char *referral, void *callback_data)
}
static void
-handle_stream_client(struct state *state, int client)
+handle_stream_client(struct plugin_state *state, int client)
{
Slapi_PBlock *pblock;
int i;
@@ -262,7 +144,7 @@ handle_stream_client(struct state *state, int client)
}
static void
-handle_dgram_client(struct state *state, int sockfd,
+handle_dgram_client(struct plugin_state *state, int sockfd,
char *dgram, int dgram_size,
struct sockaddr *client_addr, socklen_t client_addrlen)
{
@@ -375,7 +257,7 @@ handle_dgram_client(struct state *state, int sockfd,
"domain(%s)? ", p);
reply.rm_reply.rp_stat = MSG_ACCEPTED;
reply.rm_reply.rp_acpt.ar_stat = SUCCESS;
- bool_ret = strcmp(p, ".local") == 0;
+ bool_ret = schema_supports_domain(p);
reply.rm_reply.rp_acpt.ar_results.where = &bool_ret;
reply.rm_reply.rp_acpt.ar_results.proc = xdr_bool;
if ((request.rm_call.cb_proc == YPPROC_DOMAIN_NONACK) &&
@@ -580,7 +462,7 @@ handle_dgram_client(struct state *state, int sockfd,
}
static void
-handle_stream_client_new(struct state *state, int client)
+handle_stream_client_new(struct plugin_state *state, int client)
{
int i, last, ret;
int32_t len;
@@ -623,7 +505,7 @@ handle_stream_client_new(struct state *state, int client)
static void *
process_requests(void *p)
{
- struct state *state = p;
+ struct plugin_state *state = p;
struct pollfd fds[4];
int client, i;
char dgram[65536];
@@ -631,18 +513,18 @@ process_requests(void *p)
socklen_t client_addrlen;
for (;;) {
memset(&fds, 0, sizeof(fds));
- for (i = 0; i < state->listeners; i++) {
+ for (i = 0; i < state->n_listeners; i++) {
fds[i].fd = state->listenfd[i];
fds[i].events = POLLIN;
}
- switch (poll(fds, state->listeners, -1) != -1) {
+ switch (poll(fds, state->n_listeners, -1) != -1) {
case -1:
return NULL;
break;
case 0:
continue;
default:
- for (i = 0; i < state->listeners; i++) {
+ for (i = 0; i < state->n_listeners; i++) {
if ((fds[i].revents & POLLIN) == 0) {
continue;
}
@@ -683,14 +565,24 @@ process_requests(void *p)
return state;
}
-/* Set up the plugin. */
+/* Start the plugin's work thread. */
static int
plugin_start(Slapi_PBlock *pb)
{
- struct state *state;
+ struct plugin_state *state;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
"plugin starting\n");
+ if (portmap_register(state->resvport, YPPROG, YPVERS,
+ IPPROTO_TCP, PORT)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
+ "error registering with portmap\n");
+ }
+ if (portmap_register(state->resvport, YPPROG, YPVERS,
+ IPPROTO_UDP, PORT)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
+ "error registering with portmap\n");
+ }
if (pthread_create(&state->tid, NULL, &process_requests, state) != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
"error starting listener thread\n");
@@ -700,23 +592,139 @@ plugin_start(Slapi_PBlock *pb)
"plugin started\n");
return 0;
}
-/* Prepare for shutdown. */
+
+/* Stop the plugin's work thread. */
static int
plugin_close(Slapi_PBlock *pb)
{
- if (pmap_unset(YPPROG, YPVERS) != 1) {
- slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
- "error unregistering ports, continuing\n");
+ struct plugin_state *state;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+ portmap_unregister(state->resvport, YPPROG, YPVERS);
+ return 0;
+}
+
+static int
+setup_listeners(struct plugin_state **lstate)
+{
+ int sockfd = -1, err, i;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ struct plugin_state *state;
+ PLArenaPool *arena = NULL;
+
+ arena = PORT_NewArena(sizeof(double));
+ if (arena == NULL) {
+ goto failed;
}
- slapi_log_error(SLAPI_LOG_PLUGIN, "my_init_function",
- "plugin closing\n");
+ state = PORT_ArenaZAlloc(arena, sizeof(*state));
+ if (state == NULL) {
+ goto failed;
+ }
+ state->arena = arena;
+ state->resvport = -1;
+
+ for (i = 0; i < 4; i++) {
+ int sock_pf, sock_type, one = 1;
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ const char *sock_desc;
+ switch (i) {
+ case 0:
+ sock_pf = PF_INET;
+ sock_type = SOCK_DGRAM;
+ addr = (struct sockaddr *) &addr4;
+ addrlen = sizeof(addr4);
+ sock_desc = "udp";
+ break;
+ case 1:
+ sock_pf = PF_INET;
+ sock_type = SOCK_STREAM;
+ addr = (struct sockaddr *) &addr4;
+ addrlen = sizeof(addr4);
+ sock_desc = "tcp";
+ break;
+ case 2:
+ sock_pf = PF_INET6;
+ sock_type = SOCK_DGRAM;
+ addr = (struct sockaddr *) &addr6;
+ addrlen = sizeof(addr6);
+ sock_desc = "udp6";
+ break;
+ case 3:
+ sock_pf = PF_INET6;
+ sock_type = SOCK_STREAM;
+ addr = (struct sockaddr *) &addr6;
+ addrlen = sizeof(addr6);
+ sock_desc = "tcp6";
+ break;
+ }
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_port = htons(PORT);
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_port = htons(PORT);
+ sockfd = socket(sock_pf, sock_type, 0);
+ if (sockfd == -1) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "error creating a %s socket\n",
+ sock_desc);
+ continue;
+ }
+ if (setsockopt(sockfd, IPPROTO_IP, SO_REUSEADDR,
+ &one, sizeof(one)) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "error marking %s socket for reuse\n",
+ sock_desc);
+ }
+ if (bind(sockfd, addr, addrlen) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "error binding %s socket to port\n",
+ sock_desc);
+ 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\n", sock_desc);
+ close(sockfd);
+ continue;
+ }
+ if (i == 0) {
+ state->resvport = sockfd;
+ }
+ state->listenfd[state->n_listeners] = sockfd;
+ state->sock_pf[state->n_listeners] = sock_pf;
+ state->sock_type[state->n_listeners] = sock_type;
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "listening on port %d for %s%s clients\n",
+ PORT,
+ sock_type == SOCK_STREAM ? "tcp" : "udp",
+ sock_pf == PF_INET6 ? "6" : "");
+ state->n_listeners++;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ plugin_description.spd_id,
+ "set up %d listening sockets\n", state->n_listeners);
+ *lstate = state;
return 0;
+failed:
+ err = errno;
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_TRUE);
+ }
+ errno = err;
+ return -1;
}
int
-my_init_function(Slapi_PBlock *pb)
+nis_plugin_init(Slapi_PBlock *pb)
{
- struct state *state;
+ struct plugin_state *state = NULL;
if (setup_listeners(&state) == -1) {
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
"error setting up listening sockets\n");
@@ -728,19 +736,7 @@ my_init_function(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, &plugin_close);
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &state->plugin_identity);
slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, state);
- if (pmap_unset(YPPROG, YPVERS) != 1) {
- slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
- "error clearing registrations, continuing\n");
- }
- if (pmap_set(YPPROG, YPVERS, IPPROTO_TCP, PORT) != 1) {
- slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
- "error registering TCP port, continuing\n");
- }
- if (pmap_set(YPPROG, YPVERS, IPPROTO_UDP, PORT) != 1) {
- slapi_log_error(SLAPI_LOG_PLUGIN, "plugin_start",
- "error registering UDP port, continuing\n");
- }
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
- "registering plugin hooks\n");
+ "registered plugin hooks\n");
return 0;
}
diff --git a/src/plugin.ldif b/src/plugin.ldif
index 082ed11..09931dd 100644
--- a/src/plugin.ldif
+++ b/src/plugin.ldif
@@ -4,7 +4,7 @@ objectclass: nsSlapdPlugin
objectclass: extensibleObject
cn: My Plugin
nsslapd-pluginpath: /usr/src/local/sn/src/plugin.so
-nsslapd-plugininitfunc: my_init_function
+nsslapd-plugininitfunc: nis_plugin_init
nsslapd-plugintype: object
nsslapd-pluginenabled: on
nsslapd-pluginid: my-plugin
diff --git a/src/portmap.c b/src/portmap.c
new file mode 100644
index 0000000..ff0aa62
--- /dev/null
+++ b/src/portmap.c
@@ -0,0 +1,211 @@
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_msg.h>
+#include <rpc/pmap_prot.h>
+#include <errno.h>
+#include <poll.h>
+#include <time.h>
+
+#include <dirsrv/slapi-plugin.h>
+
+static bool_t
+portmap_register_work(int resv_sock,
+ int program, int version, int protocol, int port,
+ int proc)
+{
+ char portmap_buf[4000], auth_buf[4000], reply_buf[8000];
+ uint32_t length;
+ int portmap_length, reply_length;
+ AUTH *auth;
+ XDR portmap_xdrs, auth_xdrs;
+ struct rpc_msg msg;
+ struct pmap map;
+ bool_t ret;
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ union {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } client_addr;
+ socklen_t client_addrlen;
+ struct pollfd pollfd;
+ int i;
+ u_long xid;
+ gid_t gid = 0;
+
+ memset(&addr, 0, sizeof(addr));
+ memset(&addr4, 0, sizeof(addr4));
+ memset(&addr6, 0, sizeof(addr6));
+ addr.sa_family = AF_UNSPEC;
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = ntohs(PMAPPORT);
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = ntohs(PMAPPORT);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.rm_xid = xid = time(NULL);
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = 2;
+ msg.rm_call.cb_prog = PMAPPROG;
+ msg.rm_call.cb_vers = PMAPVERS;
+ msg.rm_call.cb_proc = proc;
+
+ xdrmem_create(&auth_xdrs, auth_buf, sizeof(auth_buf), XDR_ENCODE);
+ auth = authunix_create("localhost", 0, 0, 1, &gid);
+ auth_marshall(auth, &auth_xdrs);
+ msg.rm_call.cb_cred.oa_flavor = AUTH_SYS;
+ msg.rm_call.cb_cred.oa_base = auth_buf;
+ msg.rm_call.cb_cred.oa_length = xdr_getpos(&auth_xdrs);
+ auth_destroy(auth);
+ xdr_destroy(&auth_xdrs);
+
+ map.pm_prog = program;
+ map.pm_vers = version;
+ map.pm_prot = protocol;
+ map.pm_port = port;
+
+ xdrmem_create(&portmap_xdrs, portmap_buf, sizeof(portmap_buf),
+ XDR_ENCODE);
+ xdr_callmsg(&portmap_xdrs, &msg);
+ xdr_pmap(&portmap_xdrs, &map);
+ portmap_length = xdr_getpos(&portmap_xdrs);
+ xdr_destroy(&portmap_xdrs);
+
+ client_addrlen = 0;
+ connect(resv_sock, (struct sockaddr*) &addr4, sizeof(addr4));
+ for (i = 1; i < 32; i *= 2) {
+ if (send(resv_sock, &portmap_buf, portmap_length,
+ 0) != portmap_length) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "error sending request to portmap\n");
+ continue;
+ }
+ pollfd.fd = resv_sock;
+ pollfd.events = POLLIN | POLLERR;
+ if ((poll(&pollfd, 1, i * 1000) > 0) &&
+ (pollfd.revents & POLLIN)) {
+ client_addrlen = sizeof(client_addr);
+ reply_length = recvfrom(resv_sock,
+ reply_buf, sizeof(reply_buf), 0,
+ (struct sockaddr *)&client_addr,
+ &client_addrlen);
+ if (reply_length > 0) {
+ xdrmem_create(&portmap_xdrs,
+ reply_buf, reply_length,
+ XDR_DECODE);
+ if (xdr_replymsg(&portmap_xdrs, &msg)) {
+ if ((msg.rm_direction == REPLY) &&
+ (msg.rm_xid == xid)) {
+ break;
+ }
+ }
+ xdr_destroy(&portmap_xdrs);
+ }
+ }
+ }
+ connect(resv_sock, &addr, sizeof(addr));
+ if (i == 32) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "timeout registering with portmap service\n");
+ return FALSE;
+ }
+
+ if (msg.rm_reply.rp_stat != MSG_ACCEPTED) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap request not accepted\n");
+ switch (msg.rm_reply.rp_rjct.rj_stat) {
+ const char *auth_status;
+ case AUTH_ERROR:
+ switch (msg.rm_reply.rp_rjct.rj_why) {
+ case AUTH_OK:
+ auth_status = "ok";
+ break;
+ case AUTH_BADCRED:
+ auth_status = "bad credentials";
+ break;
+ case AUTH_REJECTEDCRED:
+ auth_status = "rejected credentials";
+ break;
+ case AUTH_BADVERF:
+ auth_status = "bad verifier";
+ break;
+ case AUTH_REJECTEDVERF:
+ auth_status = "rejected verifier";
+ break;
+ case AUTH_TOOWEAK:
+ auth_status = "too weak";
+ break;
+ case AUTH_INVALIDRESP:
+ auth_status = "invalid response";
+ break;
+ case AUTH_FAILED:
+ default:
+ auth_status = "unknown error";
+ break;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap request rejected: "
+ "authentication failed: %s\n",
+ auth_status);
+ break;
+ case RPC_MISMATCH:
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap request rejected: "
+ "RPC mismatch\n");
+ break;
+ }
+ xdr_destroy(&portmap_xdrs);
+ return FALSE;
+ }
+
+ auth = authunix_create_default();
+ if (auth_validate(auth, &msg.rm_reply.rp_acpt.ar_verf)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap reply authenticated\n");
+ } else {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap reply failed authentication\n");
+ }
+ auth_destroy(auth);
+
+ if (msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap request not processed\n");
+ xdr_destroy(&portmap_xdrs);
+ return FALSE;
+ }
+
+ if (xdr_bool(&portmap_xdrs, &ret)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap request succeeded\n");
+ } else {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "XXX",
+ "portmap response did not include a reply\n");
+ ret = FALSE;
+ }
+
+ xdr_destroy(&portmap_xdrs);
+
+ return ret;
+}
+
+bool_t
+portmap_register(int resv_sock,
+ int program, int version, int protocol, int port)
+{
+ return portmap_register_work(resv_sock, program, version,
+ protocol, port, PMAPPROC_UNSET);
+}
+
+bool_t
+portmap_unregister(int resv_sock, int program, int version)
+{
+ return portmap_register_work(resv_sock, program, version,
+ 0, 0, PMAPPROC_UNSET);
+}
diff --git a/src/portmap.h b/src/portmap.h
new file mode 100644
index 0000000..9161095
--- /dev/null
+++ b/src/portmap.h
@@ -0,0 +1,10 @@
+#ifndef portmap_h
+#define portmap_h
+
+#include <rpc/xdr.h>
+
+bool_t portmap_register(int resv_sock,
+ int program, int version, int protocol, int port);
+bool_t portmap_unregister(int resv_sock, int program, int version);
+
+#endif
diff --git a/src/schema.c b/src/schema.c
new file mode 100644
index 0000000..cee39f9
--- /dev/null
+++ b/src/schema.c
@@ -0,0 +1,43 @@
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <dirsrv/slapi-plugin.h>
+#include "schema.h"
+
+/* Replace this with a cache of dynamically-read data that gets refreshed if
+ * it's more than X seconds old. */
+PRBool
+schema_supports_domain(const char *domain)
+{
+ if (strcmp(domain, ".local") == 0) {
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+void
+schema_get(const char *domain, const char *map,
+ char **base, int *scope, char **key, char **format)
+{
+ *base = NULL;
+ *scope = 0;
+ *key = NULL;
+ *format = NULL;
+ if (strcmp(domain, ".local") != 0) {
+ return;
+ }
+ if (strcmp(map, "passwd.byname") == 0) {
+ *base = strdup("dc=boston,dc=redhat,dc=com");
+ *scope = LDAP_SCOPE_SUBTREE;
+ *key = strdup("uid");
+ *format = strdup("${uid}:${gecos}");
+ }
+ if (strcmp(map, "passwd.bynumber") == 0) {
+ *base = strdup("dc=boston,dc=redhat,dc=com");
+ *scope = LDAP_SCOPE_SUBTREE;
+ *key = strdup("uidNumber");
+ *format = strdup("${uid}:${gecos}");
+ }
+ return;
+}
diff --git a/src/schema.h b/src/schema.h
new file mode 100644
index 0000000..e90e137
--- /dev/null
+++ b/src/schema.h
@@ -0,0 +1,10 @@
+
+
+#ifndef schema_h
+#define schema_h
+
+PRBool schema_supports_domain(const char *domain);
+void schema_get(const char *domain, const char *map,
+ char **base, int *scope, char **key, char **format);
+
+#endif