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