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