1 /* $OpenBSD: ldapd.c,v 1.26 2020/03/05 07:39:25 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/stat.h> 21 #include <sys/un.h> 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 25 #include <assert.h> 26 #include <bsd_auth.h> 27 #include <ctype.h> 28 #include <err.h> 29 #include <errno.h> 30 #include <event.h> 31 #include <fcntl.h> 32 #include <login_cap.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <time.h> 38 #include <unistd.h> 39 #include <syslog.h> 40 41 #include "ldapd.h" 42 #include "log.h" 43 44 void usage(void); 45 void ldapd_sig_handler(int fd, short why, void *data); 46 void ldapd_sigchld_handler(int sig, short why, void *data); 47 static void ldapd_imsgev(struct imsgev *iev, int code, struct imsg *imsg); 48 static void ldapd_needfd(struct imsgev *iev); 49 static void ldapd_auth_request(struct imsgev *iev, struct imsg *imsg); 50 static void ldapd_open_request(struct imsgev *iev, struct imsg *imsg); 51 static void ldapd_log_verbose(struct imsg *imsg); 52 static void ldapd_cleanup(char *); 53 static pid_t start_child(enum ldapd_process, char *, int, int, int, 54 char *, char *); 55 56 struct ldapd_stats stats; 57 pid_t ldape_pid; 58 char *datadir = DATADIR; 59 60 void 61 usage(void) 62 { 63 extern char *__progname; 64 65 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] " 66 "[-f file] [-r directory] [-s file]\n", __progname); 67 exit(1); 68 } 69 70 void 71 ldapd_sig_handler(int sig, short why, void *data) 72 { 73 log_info("ldapd: got signal %d", sig); 74 if (sig == SIGINT || sig == SIGTERM) 75 event_loopexit(NULL); 76 } 77 78 void 79 ldapd_sigchld_handler(int sig, short why, void *data) 80 { 81 pid_t pid; 82 int status; 83 84 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) { 85 if (pid == -1) { 86 if (errno == EINTR) 87 continue; 88 if (errno != ECHILD) 89 log_warn("waitpid"); 90 break; 91 } 92 93 if (WIFEXITED(status)) 94 log_debug("child %d exited with status %d", 95 pid, WEXITSTATUS(status)); 96 else if (WIFSIGNALED(status)) 97 log_debug("child %d exited due to signal %d", 98 pid, WTERMSIG(status)); 99 else 100 log_debug("child %d terminated abnormally", pid); 101 102 if (pid == ldape_pid) { 103 log_info("ldapd: lost ldap server"); 104 event_loopexit(NULL); 105 break; 106 } 107 } 108 } 109 110 int 111 main(int argc, char *argv[]) 112 { 113 int c; 114 int debug = 0, verbose = 0, eflag = 0; 115 int configtest = 0; 116 int pipe_parent2ldap[2]; 117 char *conffile = CONFFILE; 118 char *csockpath = LDAPD_SOCKET; 119 char *saved_argv0; 120 struct imsgev *iev_ldape; 121 struct event ev_sigint; 122 struct event ev_sigterm; 123 struct event ev_sigchld; 124 struct event ev_sighup; 125 struct stat sb; 126 127 log_init(1, LOG_DAEMON); /* log to stderr until daemonized */ 128 129 saved_argv0 = argv[0]; 130 if (saved_argv0 == NULL) 131 saved_argv0 = "ldapd"; 132 133 while ((c = getopt(argc, argv, "dhvD:f:nr:s:E")) != -1) { 134 135 switch (c) { 136 case 'd': 137 debug = 1; 138 break; 139 case 'D': 140 if (cmdline_symset(optarg) < 0) { 141 warnx("could not parse macro definition %s", 142 optarg); 143 } 144 break; 145 case 'f': 146 conffile = optarg; 147 break; 148 case 'h': 149 usage(); 150 /* NOTREACHED */ 151 case 'n': 152 configtest = 1; 153 break; 154 case 'r': 155 datadir = optarg; 156 break; 157 case 's': 158 csockpath = optarg; 159 break; 160 case 'v': 161 verbose++; 162 break; 163 case 'E': 164 eflag = 1; 165 break; 166 default: 167 usage(); 168 /* NOTREACHED */ 169 } 170 } 171 172 argc -= optind; 173 if (argc > 0) 174 usage(); 175 176 /* check for root privileges */ 177 if (geteuid()) 178 errx(1, "need root privileges"); 179 180 /* check for ldapd user */ 181 if (getpwnam(LDAPD_USER) == NULL) 182 errx(1, "unknown user %s", LDAPD_USER); 183 184 log_setverbose(verbose); 185 stats.started_at = time(0); 186 tls_init(); 187 188 if (parse_config(conffile) != 0) 189 exit(2); 190 191 if (configtest) { 192 fprintf(stderr, "configuration ok\n"); 193 exit(0); 194 } 195 196 log_init(debug, LOG_DAEMON); 197 198 if (eflag) 199 ldape(debug, verbose, csockpath); 200 201 if (stat(datadir, &sb) == -1) 202 err(1, "%s", datadir); 203 if (!S_ISDIR(sb.st_mode)) 204 errx(1, "%s is not a directory", datadir); 205 206 if (!debug) { 207 if (daemon(1, 0) == -1) 208 err(1, "failed to daemonize"); 209 } 210 211 log_info("startup"); 212 213 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 214 PF_UNSPEC, pipe_parent2ldap) != 0) 215 fatal("socketpair"); 216 217 ldape_pid = start_child(PROC_LDAP_SERVER, saved_argv0, 218 pipe_parent2ldap[1], debug, verbose, csockpath, conffile); 219 220 ldap_loginit("auth", debug, verbose); 221 setproctitle("auth"); 222 event_init(); 223 224 signal_set(&ev_sigint, SIGINT, ldapd_sig_handler, NULL); 225 signal_set(&ev_sigterm, SIGTERM, ldapd_sig_handler, NULL); 226 signal_set(&ev_sigchld, SIGCHLD, ldapd_sigchld_handler, NULL); 227 signal_set(&ev_sighup, SIGHUP, ldapd_sig_handler, NULL); 228 signal_add(&ev_sigint, NULL); 229 signal_add(&ev_sigterm, NULL); 230 signal_add(&ev_sigchld, NULL); 231 signal_add(&ev_sighup, NULL); 232 signal(SIGPIPE, SIG_IGN); 233 234 if ((iev_ldape = calloc(1, sizeof(struct imsgev))) == NULL) 235 fatal("calloc"); 236 imsgev_init(iev_ldape, pipe_parent2ldap[0], NULL, ldapd_imsgev, 237 ldapd_needfd); 238 239 if (pledge("stdio rpath wpath cpath getpw sendfd proc exec", 240 NULL) == -1) 241 err(1, "pledge"); 242 243 event_dispatch(); 244 245 ldapd_cleanup(csockpath); 246 log_debug("ldapd: exiting"); 247 248 return 0; 249 } 250 251 static void 252 ldapd_cleanup(char * csockpath) 253 { 254 struct listener *l; 255 struct sockaddr_un *sun = NULL; 256 257 /* Remove control socket. */ 258 (void)unlink(csockpath); 259 260 /* Remove unix listening sockets. */ 261 TAILQ_FOREACH(l, &conf->listeners, entry) { 262 if (l->ss.ss_family == AF_UNIX) { 263 sun = (struct sockaddr_un *)&l->ss; 264 log_info("ldapd: removing unix socket %s", sun->sun_path); 265 (void)unlink(sun->sun_path); 266 } 267 } 268 } 269 270 static void 271 ldapd_imsgev(struct imsgev *iev, int code, struct imsg *imsg) 272 { 273 switch (code) { 274 case IMSGEV_IMSG: 275 log_debug("%s: got imsg %d on fd %d", 276 __func__, imsg->hdr.type, iev->ibuf.fd); 277 switch (imsg->hdr.type) { 278 case IMSG_LDAPD_AUTH: 279 ldapd_auth_request(iev, imsg); 280 break; 281 case IMSG_CTL_LOG_VERBOSE: 282 ldapd_log_verbose(imsg); 283 break; 284 case IMSG_LDAPD_OPEN: 285 ldapd_open_request(iev, imsg); 286 break; 287 default: 288 log_debug("%s: unexpected imsg %d", 289 __func__, imsg->hdr.type); 290 break; 291 } 292 break; 293 case IMSGEV_EREAD: 294 case IMSGEV_EWRITE: 295 case IMSGEV_EIMSG: 296 fatal("imsgev read/write error"); 297 break; 298 case IMSGEV_DONE: 299 event_loopexit(NULL); 300 break; 301 } 302 } 303 304 static void 305 ldapd_needfd(struct imsgev *iev) 306 { 307 fatal("should never need an fd for parent messages"); 308 } 309 310 static int 311 ldapd_auth_classful(char *name, char *password) 312 { 313 login_cap_t *lc = NULL; 314 char *class = NULL, *style = NULL; 315 auth_session_t *as; 316 317 if ((class = strchr(name, '#')) == NULL) { 318 log_debug("regular auth"); 319 return auth_userokay(name, NULL, "auth-ldap", password); 320 } 321 *class++ = '\0'; 322 323 if ((lc = login_getclass(class)) == NULL) { 324 log_debug("login_getclass(%s) for [%s] failed", class, name); 325 return 0; 326 } 327 if ((style = login_getstyle(lc, style, "auth-ldap")) == NULL) { 328 log_debug("login_getstyle() for [%s] failed", name); 329 login_close(lc); 330 return 0; 331 } 332 if (password) { 333 if ((as = auth_open()) == NULL) { 334 login_close(lc); 335 return 0; 336 } 337 auth_setitem(as, AUTHV_SERVICE, "response"); 338 auth_setdata(as, "", 1); 339 auth_setdata(as, password, strlen(password) + 1); 340 explicit_bzero(password, strlen(password)); 341 } else 342 as = NULL; 343 344 as = auth_verify(as, style, name, lc->lc_class, (char *)NULL); 345 login_close(lc); 346 return (as != NULL ? auth_close(as) : 0); 347 } 348 349 static void 350 ldapd_auth_request(struct imsgev *iev, struct imsg *imsg) 351 { 352 struct auth_req *areq = imsg->data; 353 struct auth_res ares; 354 355 if (imsg->hdr.len != sizeof(*areq) + IMSG_HEADER_SIZE) 356 fatal("invalid size of auth request"); 357 358 /* make sure name and password are null-terminated */ 359 areq->name[sizeof(areq->name) - 1] = '\0'; 360 areq->password[sizeof(areq->password) - 1] = '\0'; 361 362 log_debug("authenticating [%s]", areq->name); 363 ares.ok = ldapd_auth_classful(areq->name, areq->password); 364 ares.fd = areq->fd; 365 ares.msgid = areq->msgid; 366 memset(areq, 0, sizeof(*areq)); 367 imsgev_compose(iev, IMSG_LDAPD_AUTH_RESULT, 0, 0, -1, &ares, 368 sizeof(ares)); 369 } 370 371 static void 372 ldapd_log_verbose(struct imsg *imsg) 373 { 374 int verbose; 375 376 if (imsg->hdr.len != sizeof(verbose) + IMSG_HEADER_SIZE) 377 fatal("invalid size of log verbose request"); 378 379 bcopy(imsg->data, &verbose, sizeof(verbose)); 380 log_setverbose(verbose); 381 } 382 383 static void 384 ldapd_open_request(struct imsgev *iev, struct imsg *imsg) 385 { 386 struct open_req *oreq = imsg->data; 387 int oflags, fd; 388 389 if (imsg->hdr.len != sizeof(*oreq) + IMSG_HEADER_SIZE) 390 fatal("invalid size of open request"); 391 392 /* make sure path is null-terminated */ 393 oreq->path[PATH_MAX] = '\0'; 394 395 if (strncmp(oreq->path, datadir, strlen(datadir)) != 0) { 396 log_warnx("refusing to open file %s", oreq->path); 397 fatal("ldape sent invalid open request"); 398 } 399 400 if (oreq->rdonly) 401 oflags = O_RDONLY; 402 else 403 oflags = O_RDWR | O_CREAT | O_APPEND; 404 405 log_debug("opening [%s]", oreq->path); 406 fd = open(oreq->path, oflags | O_NOFOLLOW, 0600); 407 if (fd == -1) 408 log_warn("%s", oreq->path); 409 410 imsgev_compose(iev, IMSG_LDAPD_OPEN_RESULT, 0, 0, fd, oreq, 411 sizeof(*oreq)); 412 } 413 414 static pid_t 415 start_child(enum ldapd_process p, char *argv0, int fd, int debug, 416 int verbose, char *csockpath, char *conffile) 417 { 418 char *argv[11]; 419 int argc = 0; 420 pid_t pid; 421 422 switch (pid = fork()) { 423 case -1: 424 fatal("cannot fork"); 425 case 0: 426 break; 427 default: 428 close(fd); 429 return (pid); 430 } 431 432 if (fd != PROC_PARENT_SOCK_FILENO) { 433 if (dup2(fd, PROC_PARENT_SOCK_FILENO) == -1) 434 fatal("cannot setup imsg fd"); 435 } else if (fcntl(fd, F_SETFD, 0) == -1) 436 fatal("cannot setup imsg fd"); 437 438 argv[argc++] = argv0; 439 switch (p) { 440 case PROC_MAIN_AUTH: 441 fatalx("Can not start main process"); 442 case PROC_LDAP_SERVER: 443 argv[argc++] = "-E"; 444 break; 445 } 446 if (debug) 447 argv[argc++] = "-d"; 448 if (verbose >= 3) 449 argv[argc++] = "-vvv"; 450 else if (verbose == 2) 451 argv[argc++] = "-vv"; 452 else if (verbose == 1) 453 argv[argc++] = "-v"; 454 if (csockpath) { 455 argv[argc++] = "-s"; 456 argv[argc++] = csockpath; 457 } 458 if (conffile) { 459 argv[argc++] = "-f"; 460 argv[argc++] = conffile; 461 } 462 if (datadir) { 463 argv[argc++] = "-r"; 464 argv[argc++] = datadir; 465 } 466 467 argv[argc++] = NULL; 468 469 execvp(argv0, argv); 470 fatal("execvp"); 471 } 472