summaryrefslogtreecommitdiff
path: root/usr.sbin/ldapd/ldapd.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ldapd/ldapd.c')
-rw-r--r--usr.sbin/ldapd/ldapd.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/usr.sbin/ldapd/ldapd.c b/usr.sbin/ldapd/ldapd.c
new file mode 100644
index 00000000000..2ad516a4988
--- /dev/null
+++ b/usr.sbin/ldapd/ldapd.c
@@ -0,0 +1,331 @@
+/* $OpenBSD: ldapd.c,v 1.1 2010/05/31 17:36:31 martinh Exp $ */
+
+/*
+ * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <bsd_auth.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "ldapd.h"
+
+void usage(void);
+void ldapd_sig_handler(int fd, short why, void *data);
+void ldapd_sigchld_handler(int sig, short why, void *data);
+void ldapd_dispatch_ldape(int fd, short event, void *ptr);
+
+struct ldapd_stats stats;
+pid_t ldape_pid;
+
+void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-dnv] [-D macro=value] "
+ "[-f file] [-s file]\n", __progname);
+ exit(1);
+}
+
+void
+ldapd_sig_handler(int sig, short why, void *data)
+{
+ log_info("ldapd: got signal %d", sig);
+ if (sig == SIGINT || sig == SIGTERM)
+ event_loopexit(NULL);
+}
+
+void
+ldapd_sigchld_handler(int sig, short why, void *data)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
+ if (pid == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno != ECHILD)
+ log_warn("waitpid");
+ break;
+ }
+
+ if (WIFEXITED(status))
+ log_debug("child %d exited with status %d",
+ pid, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ log_debug("child %d exited due to signal %d",
+ pid, WTERMSIG(status));
+ else
+ log_debug("child %d terminated abnormally", pid);
+
+ if (pid == ldape_pid) {
+ log_info("ldapd: lost ldap server");
+ event_loopexit(NULL);
+ break;
+ }
+ }
+}
+
+/* set socket non-blocking */
+void
+fd_nonblock(int fd)
+{
+ int flags = fcntl(fd, F_GETFL, 0);
+ int rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ if (rc == -1) {
+ log_warn("failed to set fd %i non-blocking", fd);
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int debug = 0, verbose = 0;
+ int configtest = 0, skip_chroot = 0;
+ int pipe_parent2ldap[2];
+ char *conffile = CONFFILE;
+ char *csockpath = LDAPD_SOCKET;
+ struct passwd *pw = NULL;
+ struct imsgev *iev_ldape;
+ struct event ev_sigint;
+ struct event ev_sigterm;
+ struct event ev_sigchld;
+ struct event ev_sighup;
+
+ log_init(1); /* log to stderr until daemonized */
+
+ while ((c = getopt(argc, argv, "dhvD:f:ns:")) != -1) {
+ switch (c) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'D':
+ if (cmdline_symset(optarg) < 0) {
+ warnx("could not parse macro definition %s",
+ optarg);
+ }
+ break;
+ case 'f':
+ conffile = optarg;
+ break;
+ case 'h':
+ usage();
+ /* NOTREACHED */
+ case 'n':
+ configtest = 1;
+ break;
+ case 's':
+ csockpath = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc > 0)
+ usage();
+
+ log_verbose(verbose);
+ stats.started_at = time(0);
+ ssl_init();
+
+ if (parse_config(conffile) != 0)
+ exit(2);
+
+ if (configtest) {
+ fprintf(stderr, "configuration ok\n");
+ exit(0);
+ }
+
+ if (geteuid()) {
+ if (!debug)
+ errx(1, "need root privileges");
+ skip_chroot = 1;
+ }
+
+ if (!skip_chroot && (pw = getpwnam(LDAPD_USER)) == NULL)
+ err(1, "%s", LDAPD_USER);
+
+ if (!debug) {
+ if (daemon(1, 0) == -1)
+ err(1, "failed to daemonize");
+ }
+
+ log_init(debug);
+ log_info("startup");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldap) != 0)
+ fatal("socketpair");
+
+ fd_nonblock(pipe_parent2ldap[0]);
+ fd_nonblock(pipe_parent2ldap[1]);
+
+ ldape_pid = ldape(pw, csockpath, pipe_parent2ldap);
+
+ setproctitle("auth");
+ event_init();
+
+ signal_set(&ev_sigint, SIGINT, ldapd_sig_handler, NULL);
+ signal_set(&ev_sigterm, SIGTERM, ldapd_sig_handler, NULL);
+ signal_set(&ev_sigchld, SIGCHLD, ldapd_sigchld_handler, NULL);
+ signal_set(&ev_sighup, SIGHUP, ldapd_sig_handler, NULL);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_add(&ev_sigchld, NULL);
+ signal_add(&ev_sighup, NULL);
+ signal(SIGPIPE, SIG_IGN);
+
+ close(pipe_parent2ldap[1]);
+
+ if ((iev_ldape = calloc(1, sizeof(struct imsgev))) == NULL)
+ fatal("calloc");
+ imsg_init(&iev_ldape->ibuf, pipe_parent2ldap[0]);
+ iev_ldape->handler = ldapd_dispatch_ldape;
+ imsg_event_add(iev_ldape);
+
+ event_dispatch();
+ log_debug("ldapd: exiting");
+
+ return 0;
+}
+
+void
+imsg_event_add(struct imsgev *iev)
+{
+ iev->events = EV_READ;
+ if (iev->ibuf.w.queued)
+ iev->events |= EV_WRITE;
+
+ if (event_initialized(&iev->ev))
+ event_del(&iev->ev);
+ event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
+ event_add(&iev->ev, NULL);
+}
+
+int
+imsg_compose_event(struct imsgev *iev, u_int16_t type,
+ u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
+{
+ int ret;
+
+ if ((ret = imsg_compose(&iev->ibuf, type, peerid,
+ pid, fd, data, datalen)) != -1)
+ imsg_event_add(iev);
+ return (ret);
+}
+
+int
+imsg_event_handle(struct imsgev *iev, short event)
+{
+ ssize_t n;
+
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(&iev->ibuf)) == -1)
+ fatal("imsg_read error");
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ return -1;
+ }
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&iev->ibuf.w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(iev);
+ return 1;
+ default:
+ fatalx("unknown event");
+ }
+
+ return 0;
+}
+
+void
+ldapd_dispatch_ldape(int fd, short event, void *ptr)
+{
+ struct imsgev *iev = ptr;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int verbose;
+
+ if (imsg_event_handle(iev, event) != 0)
+ return;
+
+ ibuf = &iev->ibuf;
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("ldapd_dispatch_ldape: imsg_read error");
+ if (n == 0)
+ break;
+
+ log_debug("ldapd_dispatch_ldape: imsg type %u", imsg.hdr.type);
+
+ switch (imsg.hdr.type) {
+ case IMSG_LDAPD_AUTH: {
+ struct auth_req *areq = imsg.data;
+ struct auth_res ares;
+
+ log_debug("authenticating [%s]", areq->name);
+ ares.ok = auth_userokay(areq->name, NULL, "auth-ldap",
+ areq->password);
+ ares.fd = areq->fd;
+ ares.msgid = areq->msgid;
+ bzero(areq, sizeof(*areq));
+ imsg_compose(ibuf, IMSG_LDAPD_AUTH_RESULT, 0, 0, -1,
+ &ares, sizeof(ares));
+ imsg_event_add(iev);
+ break;
+ }
+ case IMSG_CTL_LOG_VERBOSE:
+ memcpy(&verbose, imsg.data, sizeof(verbose));
+ log_verbose(verbose);
+ break;
+ default:
+ log_debug("ldapd_dispatch_ldape: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(iev);
+}
+