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