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