1 /* $OpenBSD: ldape.c,v 1.38 2024/01/17 08:28:15 claudio 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
ldape_sig_handler(int sig,short why,void * data)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
send_ldap_extended_response(struct conn * conn,int msgid,unsigned int type,long long result_code,const char * extended_oid)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
ldap_refer(struct request * req,const char * basedn,struct search * search,struct referrals * refs)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
send_ldap_result(struct conn * conn,int msgid,unsigned int type,long long result_code)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
ldap_respond(struct request * req,int code)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
ldap_abandon(struct request * req)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
ldap_unbind(struct request * req)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
ldap_compare(struct request * req)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
ldap_starttls(struct request * req)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
ldap_extended(struct request * req)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
ldape(int debug,int verbose,char * csockpath)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
377 /* Initialize LDAP listeners.
378 */
379 TAILQ_FOREACH(l, &conf->listeners, entry) {
380 l->fd = socket(l->ss.ss_family, SOCK_STREAM | SOCK_NONBLOCK,
381 0);
382 if (l->fd == -1)
383 fatal("ldape: socket");
384
385 setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
386
387 if (l->ss.ss_family == AF_UNIX) {
388 sun = (struct sockaddr_un *)&l->ss;
389 log_info("listening on %s", sun->sun_path);
390 if (unlink(sun->sun_path) == -1 && errno != ENOENT)
391 fatal("ldape: unlink");
392 } else {
393 print_host(&l->ss, host, sizeof(host));
394 log_info("listening on %s:%d", host, ntohs(l->port));
395 }
396
397 if (l->ss.ss_family == AF_UNIX) {
398 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
399 }
400
401 if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) != 0)
402 fatal("ldape: bind");
403
404 if (l->ss.ss_family == AF_UNIX) {
405 mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
406
407 (void)umask(old_umask);
408 if (chmod(sun->sun_path, mode) == -1) {
409 unlink(sun->sun_path);
410 fatal("ldape: chmod");
411 }
412 }
413
414 if (listen(l->fd, 20) != 0)
415 fatal("ldape: listen");
416
417 event_set(&l->ev, l->fd, EV_READ, conn_accept, l);
418 event_add(&l->ev, NULL);
419 evtimer_set(&l->evt, conn_accept, l);
420
421 if (l->flags & F_SSL) {
422 if (strlcpy(key.ssl_name, l->ssl_cert_name,
423 sizeof(key.ssl_name)) >= sizeof(key.ssl_name))
424 fatal("ldape: certificate name truncated");
425
426 l->ssl = SPLAY_FIND(ssltree, conf->sc_ssl, &key);
427 if (l->ssl == NULL)
428 fatal("ldape: certificate tree corrupted");
429
430 l->tls = tls_server();
431 if (l->tls == NULL)
432 fatal("ldape: couldn't allocate tls context");
433
434 if (tls_configure(l->tls, l->ssl->config)) {
435 log_warnx("ldape: %s", tls_error(l->tls));
436 fatalx("ldape: couldn't configure tls");
437 }
438 }
439 }
440
441 TAILQ_FOREACH(ns, &conf->namespaces, next) {
442 if (!namespace_has_referrals(ns) && namespace_open(ns) != 0)
443 fatal("%s", ns->suffix);
444 }
445
446 if ((pw = getpwnam(LDAPD_USER)) == NULL)
447 fatal("getpwnam");
448
449 if (pw != NULL) {
450 if (chroot(pw->pw_dir) == -1)
451 fatal("chroot");
452 if (chdir("/") == -1)
453 fatal("chdir(\"/\")");
454
455 if (setgroups(1, &pw->pw_gid) ||
456 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
457 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
458 fatal("cannot drop privileges");
459 }
460
461 if (pledge("stdio flock inet unix recvfd", NULL) == -1)
462 fatal("pledge");
463
464 log_debug("ldape: entering event loop");
465 event_dispatch();
466
467 while ((ns = TAILQ_FIRST(&conf->namespaces)) != NULL)
468 namespace_remove(ns);
469
470 control_cleanup(&csock);
471
472 log_info("ldape: exiting");
473 exit(0);
474 }
475
476 static void
ldape_imsgev(struct imsgev * iev,int code,struct imsg * imsg)477 ldape_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
478 {
479 switch (code) {
480 case IMSGEV_IMSG:
481 log_debug("%s: got imsg %d on fd %d",
482 __func__, imsg->hdr.type, iev->ibuf.fd);
483 switch (imsg->hdr.type) {
484 case IMSG_LDAPD_AUTH_RESULT:
485 ldape_auth_result(imsg);
486 break;
487 case IMSG_LDAPD_OPEN_RESULT:
488 ldape_open_result(imsg);
489 break;
490 default:
491 log_debug("%s: unexpected imsg %d",
492 __func__, imsg->hdr.type);
493 break;
494 }
495 break;
496 case IMSGEV_EREAD:
497 case IMSGEV_EWRITE:
498 case IMSGEV_EIMSG:
499 fatal("imsgev read/write error");
500 break;
501 case IMSGEV_DONE:
502 event_loopexit(NULL);
503 break;
504 }
505 }
506
507 static void
ldape_needfd(struct imsgev * iev)508 ldape_needfd(struct imsgev *iev)
509 {
510 /* Try to close a control connection first */
511 if (control_close_any(&csock) == 0) {
512 log_warn("closed a control connection");
513 return;
514 }
515
516 if (conn_close_any() == 0) {
517 log_warn("closed a client connection");
518 return;
519 }
520
521 fatal("unable to free an fd");
522 }
523
524 static void
ldape_auth_result(struct imsg * imsg)525 ldape_auth_result(struct imsg *imsg)
526 {
527 struct conn *conn;
528 struct auth_res *ares = imsg->data;
529
530 log_debug("authentication on conn %d/%lld = %d", ares->fd, ares->msgid,
531 ares->ok);
532 conn = conn_by_fd(ares->fd);
533 if (conn->bind_req != NULL && conn->bind_req->msgid == ares->msgid)
534 ldap_bind_continue(conn, ares->ok);
535 else
536 log_warnx("spurious auth result");
537 }
538
539 static void
ldape_open_result(struct imsg * imsg)540 ldape_open_result(struct imsg *imsg)
541 {
542 struct namespace *ns;
543 struct open_req *oreq = imsg->data;
544 int fd;
545
546 if (imsg->hdr.len != sizeof(*oreq) + IMSG_HEADER_SIZE)
547 fatal("invalid size of open result");
548
549 if (oreq->path[PATH_MAX-1] != '\0')
550 fatal("bogus path");
551
552 fd = imsg_get_fd(imsg);
553 log_debug("open(%s) returned fd %d", oreq->path, fd);
554
555 TAILQ_FOREACH(ns, &conf->namespaces, next) {
556 if (namespace_has_referrals(ns))
557 continue;
558 if (strcmp(oreq->path, ns->data_path) == 0) {
559 namespace_set_data_fd(ns, fd);
560 break;
561 }
562 if (strcmp(oreq->path, ns->indx_path) == 0) {
563 namespace_set_indx_fd(ns, fd);
564 break;
565 }
566 }
567
568 if (ns == NULL) {
569 log_warnx("spurious open result");
570 close(fd);
571 } else
572 namespace_queue_schedule(ns, 0);
573 }
574
575