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