xref: /openbsd/usr.sbin/ldapd/ldape.c (revision 4cfece93)
1 /*	$OpenBSD: ldape.c,v 1.33 2019/10/26 17:52:55 martijn Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/un.h>
24 #include <sys/wait.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include "ldapd.h"
34 #include "log.h"
35 
36 void			 ldape_sig_handler(int fd, short why, void *data);
37 static void		 ldape_auth_result(struct imsg *imsg);
38 static void		 ldape_open_result(struct imsg *imsg);
39 static void		 ldape_imsgev(struct imsgev *iev, int code,
40 			    struct imsg *imsg);
41 static void		 ldape_needfd(struct imsgev *iev);
42 
43 int			 ldap_starttls(struct request *req);
44 void			 send_ldap_extended_response(struct conn *conn,
45 				int msgid, unsigned int type,
46 				long long result_code,
47 				const char *extended_oid);
48 
49 struct imsgev		*iev_ldapd;
50 struct control_sock	 csock;
51 
52 void
53 ldape_sig_handler(int sig, short why, void *data)
54 {
55 	log_debug("ldape: got signal %d", sig);
56 	if (sig == SIGCHLD) {
57 		for (;;) {
58 			pid_t	 pid;
59 			int	 status;
60 
61 			pid = waitpid(WAIT_ANY, &status, WNOHANG);
62 			if (pid <= 0)
63 				break;
64 		}
65 		return;
66 	}
67 
68 	event_loopexit(NULL);
69 }
70 
71 void
72 send_ldap_extended_response(struct conn *conn, int msgid, unsigned int type,
73     long long result_code, const char *extended_oid)
74 {
75 	ssize_t			 rc;
76 	struct ber_element	*root, *elm;
77 	void			*buf;
78 
79 	log_debug("sending response %u with result %lld", type, result_code);
80 
81 	if ((root = ober_add_sequence(NULL)) == NULL)
82 		goto fail;
83 
84 	elm = ober_printf_elements(root, "d{tEss",
85 	    msgid, BER_CLASS_APP, type, result_code, "", "");
86 	if (elm == NULL)
87 		goto fail;
88 
89 	if (extended_oid)
90 		if (ober_add_string(elm, extended_oid) == NULL)
91 			goto fail;
92 
93 	ldap_debug_elements(root, type, "sending response on fd %d", conn->fd);
94 
95 	rc = ober_write_elements(&conn->ber, root);
96 	ober_free_elements(root);
97 
98 	if (rc < 0)
99 		log_warn("failed to create ldap result");
100 	else {
101 		ober_get_writebuf(&conn->ber, &buf);
102 		if (bufferevent_write(conn->bev, buf, rc) != 0)
103 			log_warn("failed to send ldap result");
104 	}
105 
106 	return;
107 fail:
108 	if (root)
109 		ober_free_elements(root);
110 }
111 
112 int
113 ldap_refer(struct request *req, const char *basedn, struct search *search,
114     struct referrals *refs)
115 {
116 	struct ber_element	*root, *elm, *ref_root = NULL;
117 	struct referral		*ref;
118 	long long		 result_code = LDAP_REFERRAL;
119 	unsigned int		 type;
120 	ssize_t			 rc;
121 	void			*buf;
122 	char			*url, *scope_str = NULL;
123 
124 	if (req->type == LDAP_REQ_SEARCH)
125 		type = LDAP_RES_SEARCH_RESULT;
126 	else
127 		type = req->type + 1;
128 
129 	if (search != NULL) {
130 		if (search->scope != LDAP_SCOPE_SUBTREE)
131 			scope_str = "base";
132 		else
133 			scope_str = "sub";
134 	}
135 
136 	log_debug("sending referral in response %u on msgid %lld",
137 	    type, req->msgid);
138 
139 	if ((root = ober_add_sequence(NULL)) == NULL)
140 		goto fail;
141 
142 	if ((elm = ref_root = ober_add_sequence(NULL)) == NULL)
143 		goto fail;
144 	ober_set_header(ref_root, BER_CLASS_CONTEXT, LDAP_REQ_SEARCH);
145 	SLIST_FOREACH(ref, refs, next) {
146 		if (search != NULL)
147 			rc = asprintf(&url, "%s/%s??%s", ref->url, basedn,
148 			    scope_str);
149 		else
150 			rc = asprintf(&url, "%s/%s", ref->url, basedn);
151 		if (rc == -1) {
152 			log_warn("asprintf");
153 			goto fail;
154 		}
155 		log_debug("adding referral '%s'", url);
156 		elm = ober_add_string(elm, url);
157 		free(url);
158 		if (elm == NULL)
159 			goto fail;
160 	}
161 
162 	elm = ober_printf_elements(root, "d{tEsse",
163 	    req->msgid, BER_CLASS_APP, type, result_code, "", "", ref_root);
164 	if (elm == NULL)
165 		goto fail;
166 	ref_root = NULL;
167 
168 	rc = ober_write_elements(&req->conn->ber, root);
169 	ober_free_elements(root);
170 
171 	if (rc < 0)
172 		log_warn("failed to create ldap result");
173 	else {
174 		ober_get_writebuf(&req->conn->ber, &buf);
175 		if (bufferevent_write(req->conn->bev, buf, rc) != 0)
176 			log_warn("failed to send ldap result");
177 	}
178 
179 	request_free(req);
180 	return LDAP_REFERRAL;
181 
182 fail:
183 	if (root != NULL)
184 		ober_free_elements(root);
185 	if (ref_root != NULL)
186 		ober_free_elements(ref_root);
187 	request_free(req);
188 	return LDAP_REFERRAL;
189 }
190 
191 void
192 send_ldap_result(struct conn *conn, int msgid, unsigned int type,
193     long long result_code)
194 {
195 	send_ldap_extended_response(conn, msgid, type, result_code, NULL);
196 }
197 
198 int
199 ldap_respond(struct request *req, int code)
200 {
201 	if (code >= 0)
202 		send_ldap_result(req->conn, req->msgid, req->type + 1, code);
203 	request_free(req);
204 	return code;
205 }
206 
207 int
208 ldap_abandon(struct request *req)
209 {
210 	long long	 msgid;
211 	struct search	*search;
212 
213 	if (ober_scanf_elements(req->op, "i", &msgid) != 0) {
214 		request_free(req);
215 		return -1;	/* protocol error, but don't respond */
216 	}
217 
218 	TAILQ_FOREACH(search, &req->conn->searches, next) {
219 		if (search->req->msgid == msgid) {
220 			/* unlinks the search from conn->searches */
221 			search_close(search);
222 			break;
223 		}
224 	}
225 	request_free(req);
226 	return -1;
227 }
228 
229 int
230 ldap_unbind(struct request *req)
231 {
232 	log_debug("current bind dn = %s",
233 	    req->conn->binddn == NULL ? "" : req->conn->binddn);
234 	conn_disconnect(req->conn);
235 	request_free(req);
236 	return -1;		/* don't send any response */
237 }
238 
239 int
240 ldap_compare(struct request *req)
241 {
242 	struct ber_element	*entry, *elm, *attr;
243 	struct namespace	*ns;
244 	struct referrals	*refs;
245 	struct attr_type	*at;
246 	char			*dn, *aname, *value, *s;
247 
248 	if (ober_scanf_elements(req->op, "{s{ss", &dn, &aname, &value) != 0) {
249 		log_debug("%s: protocol error", __func__);
250 		request_free(req);
251 		return -1;
252 	}
253 
254 	if ((at = lookup_attribute(conf->schema, aname)) == NULL)
255 		return ldap_respond(req, LDAP_UNDEFINED_TYPE);
256 
257 	if ((ns = namespace_for_base(dn)) == NULL) {
258 		refs = namespace_referrals(dn);
259 		if (refs == NULL)
260 			return ldap_respond(req, LDAP_NO_SUCH_OBJECT);
261 		else
262 			return ldap_refer(req, dn, NULL, refs);
263 	}
264 
265 	if ((entry = namespace_get(ns, dn)) == NULL)
266 		return ldap_respond(req, LDAP_NO_SUCH_OBJECT);
267 
268 	if ((attr = ldap_find_attribute(entry, at)) == NULL)
269 		return ldap_respond(req, LDAP_NO_SUCH_ATTRIBUTE);
270 
271 	if ((attr = attr->be_next) == NULL)	/* skip attribute name */
272 		return ldap_respond(req, LDAP_OTHER);
273 
274 	for (elm = attr->be_sub; elm != NULL; elm = elm->be_next) {
275 		if (ober_get_string(elm, &s) != 0)
276 			return ldap_respond(req, LDAP_OTHER);
277 		if (strcasecmp(value, s) == 0)
278 			return ldap_respond(req, LDAP_COMPARE_TRUE);
279 	}
280 
281 	return ldap_respond(req, LDAP_COMPARE_FALSE);
282 }
283 
284 int
285 ldap_starttls(struct request *req)
286 {
287 	if ((req->conn->listener->flags & F_STARTTLS) == 0) {
288 		log_debug("StartTLS not configured for this connection");
289 		return LDAP_OPERATIONS_ERROR;
290 	}
291 
292 	req->conn->s_flags |= F_STARTTLS;
293 	return LDAP_SUCCESS;
294 }
295 
296 int
297 ldap_extended(struct request *req)
298 {
299 	int			 i, rc = LDAP_PROTOCOL_ERROR;
300 	char			*oid = NULL;
301 	struct {
302 		const char	*oid;
303 		int (*fn)(struct request *);
304 	} extended_ops[] = {
305 		{ "1.3.6.1.4.1.1466.20037", ldap_starttls },
306 		{ NULL }
307 	};
308 
309 	if (ober_scanf_elements(req->op, "{s", &oid) != 0)
310 		goto done;
311 
312 	log_debug("got extended operation %s", oid);
313 	req->op = req->op->be_sub->be_next;
314 
315 	for (i = 0; extended_ops[i].oid != NULL; i++) {
316 		if (strcmp(oid, extended_ops[i].oid) == 0) {
317 			rc = extended_ops[i].fn(req);
318 			break;
319 		}
320 	}
321 
322 	if (extended_ops[i].fn == NULL)
323 		log_warnx("unimplemented extended operation %s", oid);
324 
325 done:
326 	send_ldap_extended_response(req->conn, req->msgid, LDAP_RES_EXTENDED,
327 	    rc, oid);
328 
329 	request_free(req);
330 	return 0;
331 }
332 
333 void
334 ldape(int debug, int verbose, char *csockpath)
335 {
336 	int			 on = 1;
337 	struct namespace	*ns;
338 	struct listener		*l;
339 	struct sockaddr_un	*sun = NULL;
340 	struct event		 ev_sigint;
341 	struct event		 ev_sigterm;
342 	struct event		 ev_sigchld;
343 	struct event		 ev_sighup;
344 	struct ssl		 key;
345 	struct passwd		*pw;
346 	char			 host[128];
347 	mode_t			old_umask = 0;
348 
349 	TAILQ_INIT(&conn_list);
350 
351 	ldap_loginit("ldap server", debug, verbose);
352 	setproctitle("ldap server");
353 	event_init();
354 
355 	signal_set(&ev_sigint, SIGINT, ldape_sig_handler, NULL);
356 	signal_set(&ev_sigterm, SIGTERM, ldape_sig_handler, NULL);
357 	signal_set(&ev_sigchld, SIGCHLD, ldape_sig_handler, NULL);
358 	signal_set(&ev_sighup, SIGHUP, ldape_sig_handler, NULL);
359 	signal_add(&ev_sigint, NULL);
360 	signal_add(&ev_sigterm, NULL);
361 	signal_add(&ev_sigchld, NULL);
362 	signal_add(&ev_sighup, NULL);
363 	signal(SIGPIPE, SIG_IGN);
364 
365 	/* Initialize parent imsg events. */
366 	if ((iev_ldapd = calloc(1, sizeof(struct imsgev))) == NULL)
367 		fatal("calloc");
368 	imsgev_init(iev_ldapd, PROC_PARENT_SOCK_FILENO, NULL, ldape_imsgev,
369 	    ldape_needfd);
370 
371 	/* Initialize control socket. */
372 	memset(&csock, 0, sizeof(csock));
373 	csock.cs_name = csockpath;
374 	control_init(&csock);
375 	control_listen(&csock);
376 	TAILQ_INIT(&ctl_conns);
377 
378 	/* Initialize LDAP listeners.
379 	 */
380 	TAILQ_FOREACH(l, &conf->listeners, entry) {
381 		l->fd = socket(l->ss.ss_family, SOCK_STREAM | SOCK_NONBLOCK,
382 		    0);
383 		if (l->fd == -1)
384 			fatal("ldape: socket");
385 
386 		setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
387 
388 		if (l->ss.ss_family == AF_UNIX) {
389 			sun = (struct sockaddr_un *)&l->ss;
390 			log_info("listening on %s", sun->sun_path);
391 			if (unlink(sun->sun_path) == -1 && errno != ENOENT)
392 				fatal("ldape: unlink");
393 		} else {
394 			print_host(&l->ss, host, sizeof(host));
395 			log_info("listening on %s:%d", host, ntohs(l->port));
396 		}
397 
398 		if (l->ss.ss_family == AF_UNIX) {
399 			old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
400 		}
401 
402 		if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) != 0)
403 			fatal("ldape: bind");
404 
405 		if (l->ss.ss_family == AF_UNIX) {
406 			mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
407 
408 			(void)umask(old_umask);
409 			if (chmod(sun->sun_path, mode) == -1) {
410 				unlink(sun->sun_path);
411 				fatal("ldape: chmod");
412 			}
413 		}
414 
415 		if (listen(l->fd, 20) != 0)
416 			fatal("ldape: listen");
417 
418 		event_set(&l->ev, l->fd, EV_READ, conn_accept, l);
419 		event_add(&l->ev, NULL);
420 		evtimer_set(&l->evt, conn_accept, l);
421 
422 		if (l->flags & F_SSL) {
423 			if (strlcpy(key.ssl_name, l->ssl_cert_name,
424 			    sizeof(key.ssl_name)) >= sizeof(key.ssl_name))
425 				fatal("ldape: certificate name truncated");
426 
427 			l->ssl = SPLAY_FIND(ssltree, conf->sc_ssl, &key);
428 			if (l->ssl == NULL)
429 				fatal("ldape: certificate tree corrupted");
430 
431 			l->tls = tls_server();
432 			if (l->tls == NULL)
433 				fatal("ldape: couldn't allocate tls context");
434 
435 			if (tls_configure(l->tls, l->ssl->config)) {
436 				log_warn("ldape: %s", tls_error(l->tls));
437 				fatal("ldape: couldn't configure tls");
438 			}
439 		}
440 	}
441 
442 	TAILQ_FOREACH(ns, &conf->namespaces, next) {
443 		if (!namespace_has_referrals(ns) && namespace_open(ns) != 0)
444 			fatal("%s", ns->suffix);
445 	}
446 
447 	if ((pw = getpwnam(LDAPD_USER)) == NULL)
448 		fatal("getpwnam");
449 
450 	if (pw != NULL) {
451 		if (chroot(pw->pw_dir) == -1)
452 			fatal("chroot");
453 		if (chdir("/") == -1)
454 			fatal("chdir(\"/\")");
455 
456 		if (setgroups(1, &pw->pw_gid) ||
457 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
458 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
459 			fatal("cannot drop privileges");
460 	}
461 
462 	if (pledge("stdio flock inet unix recvfd", NULL) == -1)
463 		fatal("pledge");
464 
465 	log_debug("ldape: entering event loop");
466 	event_dispatch();
467 
468 	while ((ns = TAILQ_FIRST(&conf->namespaces)) != NULL)
469 		namespace_remove(ns);
470 
471 	control_cleanup(&csock);
472 
473 	log_info("ldape: exiting");
474 	exit(0);
475 }
476 
477 static void
478 ldape_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
479 {
480 	switch (code) {
481 	case IMSGEV_IMSG:
482 		log_debug("%s: got imsg %d on fd %d",
483 		    __func__, imsg->hdr.type, iev->ibuf.fd);
484 		switch (imsg->hdr.type) {
485 		case IMSG_LDAPD_AUTH_RESULT:
486 			ldape_auth_result(imsg);
487 			break;
488 		case IMSG_LDAPD_OPEN_RESULT:
489 			ldape_open_result(imsg);
490 			break;
491 		default:
492 			log_debug("%s: unexpected imsg %d",
493 			    __func__, imsg->hdr.type);
494 			break;
495 		}
496 		break;
497 	case IMSGEV_EREAD:
498 	case IMSGEV_EWRITE:
499 	case IMSGEV_EIMSG:
500 		fatal("imsgev read/write error");
501 		break;
502 	case IMSGEV_DONE:
503 		event_loopexit(NULL);
504 		break;
505 	}
506 }
507 
508 static void
509 ldape_needfd(struct imsgev *iev)
510 {
511 	/* Try to close a control connection first */
512 	if (control_close_any(&csock) == 0) {
513 		log_warn("closed a control connection");
514 		return;
515 	}
516 
517 	if (conn_close_any() == 0) {
518 		log_warn("closed a client connection");
519 		return;
520 	}
521 
522 	fatal("unable to free an fd");
523 }
524 
525 static void
526 ldape_auth_result(struct imsg *imsg)
527 {
528 	struct conn		*conn;
529 	struct auth_res		*ares = imsg->data;
530 
531 	log_debug("authentication on conn %d/%lld = %d", ares->fd, ares->msgid,
532 	    ares->ok);
533 	conn = conn_by_fd(ares->fd);
534 	if (conn->bind_req != NULL && conn->bind_req->msgid == ares->msgid)
535 		ldap_bind_continue(conn, ares->ok);
536 	else
537 		log_warnx("spurious auth result");
538 }
539 
540 static void
541 ldape_open_result(struct imsg *imsg)
542 {
543 	struct namespace	*ns;
544 	struct open_req		*oreq = imsg->data;
545 
546 	if (imsg->hdr.len != sizeof(*oreq) + IMSG_HEADER_SIZE)
547 		fatal("invalid size of open result");
548 
549 	/* make sure path is null-terminated */
550 	oreq->path[PATH_MAX] = '\0';
551 
552 	log_debug("open(%s) returned fd %d", oreq->path, imsg->fd);
553 
554 	TAILQ_FOREACH(ns, &conf->namespaces, next) {
555 		if (namespace_has_referrals(ns))
556 			continue;
557 		if (strcmp(oreq->path, ns->data_path) == 0) {
558 			namespace_set_data_fd(ns, imsg->fd);
559 			break;
560 		}
561 		if (strcmp(oreq->path, ns->indx_path) == 0) {
562 			namespace_set_indx_fd(ns, imsg->fd);
563 			break;
564 		}
565 	}
566 
567 	if (ns == NULL) {
568 		log_warnx("spurious open result");
569 		close(imsg->fd);
570 	} else
571 		namespace_queue_schedule(ns, 0);
572 }
573 
574