1 /* $OpenBSD: privsep.c,v 1.27 2019/06/28 13:32:47 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 1995, 1999 Theo de Raadt 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/ioctl.h> 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/time.h> 24 25 #include <net/if.h> 26 #include <net/if_media.h> 27 #include <net/if_arp.h> 28 #include <net/if_llc.h> 29 #include <net/bpf.h> 30 31 #include <netinet/in.h> 32 #include <netinet/if_ether.h> 33 #include <arpa/inet.h> 34 35 #include <net80211/ieee80211.h> 36 #include <net80211/ieee80211_ioctl.h> 37 38 #include <errno.h> 39 #include <event.h> 40 #include <fcntl.h> 41 #include <netdb.h> 42 #include <pwd.h> 43 #include <signal.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <limits.h> 50 51 #include "hostapd.h" 52 #include "iapp.h" 53 54 enum hostapd_cmd_types { 55 PRIV_APME_BSSID, /* Get the Host AP's BSSID */ 56 PRIV_APME_GETNODE, /* Get a node from the Host AP */ 57 PRIV_APME_ADDNODE, /* Delete a node from the Host AP */ 58 PRIV_APME_DELNODE, /* Delete a node from the Host AP */ 59 PRIV_APME_ADDROAMING, /* Add a route to the kernel */ 60 PRIV_APME_DELROAMING, /* Delete a route from the kernel */ 61 PRIV_LLC_SEND_XID /* Send IEEE 802.3 LLC XID frame */ 62 }; 63 64 void hostapd_priv(int, short, void *); 65 struct hostapd_apme *hostapd_priv_getapme(int, struct hostapd_config *); 66 void hostapd_sig_relay(int, short, void *); 67 void hostapd_sig_chld(int, short, void *); 68 int hostapd_may_read(int, void *, size_t); 69 void hostapd_must_read(int, void *, size_t); 70 void hostapd_must_write(int, void *, size_t); 71 72 static int priv_fd = -1; 73 static volatile pid_t child_pid = -1; 74 75 /* 76 * Main privsep functions 77 */ 78 79 void 80 hostapd_priv_init(struct hostapd_config *cfg) 81 { 82 struct event ev_sigalrm; 83 struct event ev_sigterm; 84 struct event ev_sigint; 85 struct event ev_sighup; 86 struct event ev_sigchld; 87 struct hostapd_iapp *iapp = &cfg->c_iapp; 88 struct hostapd_apme *apme; 89 int i, socks[2]; 90 struct passwd *pw; 91 struct servent *se; 92 93 for (i = 1; i < _NSIG; i++) 94 signal(i, SIG_DFL); 95 96 if ((se = getservbyname("iapp", "udp")) == NULL) { 97 iapp->i_udp_port = IAPP_PORT; 98 } else 99 iapp->i_udp_port = se->s_port; 100 101 if ((pw = getpwnam(HOSTAPD_USER)) == NULL) 102 hostapd_fatal("failed to get user \"%s\"\n", HOSTAPD_USER); 103 104 endservent(); 105 106 /* Create sockets */ 107 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) 108 hostapd_fatal("failed to get socket pair\n"); 109 110 if ((child_pid = fork()) == -1) 111 hostapd_fatal("failed to fork child process\n"); 112 113 /* 114 * Unprivileged child process 115 */ 116 if (child_pid == 0) { 117 cfg->c_flags &= ~HOSTAPD_CFG_F_PRIV; 118 119 /* 120 * Change the child's root directory to the unprivileged 121 * user's home directory 122 */ 123 if (chroot(pw->pw_dir) == -1) 124 hostapd_fatal("failed to change root directory\n"); 125 if (chdir("/") == -1) 126 hostapd_fatal("failed to change directory\n"); 127 128 /* 129 * Drop privileges and clear the group access list 130 */ 131 if (setgroups(1, &pw->pw_gid) == -1 || 132 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || 133 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) 134 hostapd_fatal("can't drop privileges\n"); 135 136 (void)close(socks[0]); 137 priv_fd = socks[1]; 138 return; 139 } 140 141 /* 142 * Privileged mother process 143 */ 144 cfg->c_flags |= HOSTAPD_CFG_F_PRIV; 145 146 (void)event_init(); 147 148 /* Pass ALRM/TERM/INT/HUP through to child, and accept CHLD */ 149 signal_set(&ev_sigalrm, SIGALRM, hostapd_sig_relay, NULL); 150 signal_set(&ev_sigterm, SIGTERM, hostapd_sig_relay, NULL); 151 signal_set(&ev_sigint, SIGINT, hostapd_sig_relay, NULL); 152 signal_set(&ev_sighup, SIGHUP, hostapd_sig_relay, NULL); 153 signal_set(&ev_sigchld, SIGCHLD, hostapd_sig_chld, NULL); 154 signal_add(&ev_sigalrm, NULL); 155 signal_add(&ev_sigterm, NULL); 156 signal_add(&ev_sigint, NULL); 157 signal_add(&ev_sighup, NULL); 158 signal_add(&ev_sigchld, NULL); 159 160 (void)close(socks[1]); 161 162 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 163 if ((cfg->c_apme_ctl = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 164 hostapd_fatal("unable to open ioctl socket\n"); 165 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) 166 if (apme->a_chanavail != NULL) 167 hostapd_apme_sethopper(apme, 0); 168 } 169 170 hostapd_roaming_init(cfg); 171 172 /* Start a new event listener */ 173 event_set(&cfg->c_priv_ev, socks[0], EV_READ, hostapd_priv, cfg); 174 if (event_add(&cfg->c_priv_ev, NULL) == -1) 175 hostapd_fatal("failed to add priv event"); 176 177 /* Run privileged event loop */ 178 if (event_dispatch() == -1) 179 hostapd_fatal("failed to dispatch priv hostapd"); 180 181 /* Executed after the event loop has been terminated */ 182 hostapd_cleanup(cfg); 183 _exit(EXIT_SUCCESS); 184 } 185 186 struct hostapd_apme * 187 hostapd_priv_getapme(int fd, struct hostapd_config *cfg) 188 { 189 struct hostapd_apme *apme; 190 char name[IFNAMSIZ]; 191 int n; 192 193 hostapd_must_read(fd, name, IFNAMSIZ); 194 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0 || 195 (apme = hostapd_apme_lookup(cfg, name)) == NULL) { 196 n = ENXIO; 197 hostapd_must_write(fd, &n, sizeof(int)); 198 return (NULL); 199 } 200 return (apme); 201 } 202 203 void 204 hostapd_priv(int fd, short sig, void *arg) 205 { 206 struct hostapd_config *cfg = (struct hostapd_config *)arg; 207 struct hostapd_apme *apme; 208 struct hostapd_node node; 209 struct ieee80211_bssid bssid; 210 struct ieee80211_nodereq nr; 211 struct ifreq ifr; 212 unsigned long request; 213 int ret = 0, cmd; 214 215 /* Terminate the event if we got an invalid signal */ 216 if (sig != EV_READ) 217 return; 218 219 bzero(&node, sizeof(struct hostapd_node)); 220 bzero(&nr, sizeof(struct ieee80211_nodereq)); 221 222 /* Get privsep command */ 223 if (hostapd_may_read(fd, &cmd, sizeof(int))) 224 return; 225 226 switch (cmd) { 227 case PRIV_APME_BSSID: 228 hostapd_log(HOSTAPD_LOG_DEBUG, 229 "[priv]: msg PRIV_APME_BSSID received"); 230 231 if ((apme = hostapd_priv_getapme(fd, cfg)) == NULL) 232 break; 233 (void)strlcpy(bssid.i_name, apme->a_iface, sizeof(bssid.i_name)); 234 235 /* Try to get the APME's BSSID */ 236 if ((ret = ioctl(cfg->c_apme_ctl, 237 SIOCG80211BSSID, &bssid)) != 0) 238 ret = errno; 239 240 hostapd_must_write(fd, &ret, sizeof(int)); 241 if (ret == 0) 242 hostapd_must_write(fd, &bssid.i_bssid, 243 IEEE80211_ADDR_LEN); 244 break; 245 246 case PRIV_APME_GETNODE: 247 hostapd_log(HOSTAPD_LOG_DEBUG, 248 "[priv]: msg PRIV_APME_GETNODE received"); 249 250 hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); 251 bcopy(node.ni_macaddr, nr.nr_macaddr, IEEE80211_ADDR_LEN); 252 253 if ((apme = hostapd_priv_getapme(fd, cfg)) == NULL) 254 break; 255 (void)strlcpy(nr.nr_ifname, apme->a_iface, sizeof(ifr.ifr_name)); 256 257 /* Try to get a station from the APME */ 258 if ((ret = ioctl(cfg->c_apme_ctl, 259 SIOCG80211NODE, &nr)) != 0) 260 ret = errno; 261 262 hostapd_must_write(fd, &ret, sizeof(int)); 263 if (ret == 0) { 264 node.ni_associd = nr.nr_associd; 265 node.ni_flags = IEEE80211_NODEREQ_STATE(nr.nr_state); 266 node.ni_rssi = nr.nr_rssi; 267 node.ni_capinfo = nr.nr_capinfo; 268 269 hostapd_must_write(fd, &node, 270 sizeof(struct hostapd_node)); 271 } 272 break; 273 274 case PRIV_APME_ADDNODE: 275 case PRIV_APME_DELNODE: 276 hostapd_log(HOSTAPD_LOG_DEBUG, 277 "[priv]: msg PRIV_APME_[ADD|DEL]NODE received"); 278 279 hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); 280 bcopy(node.ni_macaddr, nr.nr_macaddr, IEEE80211_ADDR_LEN); 281 282 if ((apme = hostapd_priv_getapme(fd, cfg)) == NULL) 283 break; 284 (void)strlcpy(nr.nr_ifname, apme->a_iface, sizeof(ifr.ifr_name)); 285 286 request = cmd == PRIV_APME_ADDNODE ? 287 SIOCS80211NODE : SIOCS80211DELNODE; 288 289 /* Try to add/delete a station from the APME */ 290 if ((ret = ioctl(cfg->c_apme_ctl, request, &nr)) == -1) 291 ret = errno; 292 293 hostapd_must_write(fd, &ret, sizeof(int)); 294 break; 295 296 case PRIV_LLC_SEND_XID: 297 hostapd_log(HOSTAPD_LOG_DEBUG, 298 "[priv]: msg PRIV_LLC_SEND_XID received"); 299 300 hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); 301 302 /* Send a LLC XID frame to reset possible switch ports */ 303 ret = hostapd_llc_send_xid(cfg, &node); 304 hostapd_must_write(fd, &ret, sizeof(int)); 305 break; 306 307 case PRIV_APME_ADDROAMING: 308 case PRIV_APME_DELROAMING: 309 hostapd_log(HOSTAPD_LOG_DEBUG, 310 "[priv]: msg PRIV_APME_[ADD|DEL]ROAMING received"); 311 312 hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); 313 314 if ((apme = hostapd_priv_getapme(fd, cfg)) == NULL) 315 break; 316 ret = hostapd_roaming(apme, &node, cmd == PRIV_APME_ADDROAMING); 317 hostapd_must_write(fd, &ret, sizeof(int)); 318 break; 319 320 default: 321 hostapd_fatal("[priv]: unknown command %d\n", cmd); 322 } 323 if (event_add(&cfg->c_priv_ev, NULL) == -1) 324 hostapd_fatal("failed to schedult priv event"); 325 326 return; 327 } 328 329 /* 330 * Unprivileged callers 331 */ 332 int 333 hostapd_priv_apme_getnode(struct hostapd_apme *apme, struct hostapd_node *node) 334 { 335 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 336 int ret, cmd; 337 338 if (priv_fd < 0) 339 hostapd_fatal("%s: called from privileged portion\n", __func__); 340 341 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 342 hostapd_fatal("%s: Host AP is not available\n", __func__); 343 344 cmd = PRIV_APME_GETNODE; 345 hostapd_must_write(priv_fd, &cmd, sizeof(int)); 346 hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); 347 hostapd_must_write(priv_fd, &apme->a_iface, IFNAMSIZ); 348 hostapd_must_read(priv_fd, &ret, sizeof(int)); 349 if (ret != 0) 350 return (ret); 351 352 hostapd_must_read(priv_fd, node, sizeof(struct hostapd_node)); 353 return (ret); 354 } 355 356 int 357 hostapd_priv_apme_setnode(struct hostapd_apme *apme, struct hostapd_node *node, 358 int add) 359 { 360 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 361 struct hostapd_iapp *iapp = &cfg->c_iapp; 362 int ret, cmd; 363 364 if (priv_fd < 0) 365 hostapd_fatal("%s: called from privileged portion\n", __func__); 366 367 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 368 hostapd_fatal("%s: Host AP is not available\n", __func__); 369 370 if (add) 371 cmd = PRIV_APME_ADDNODE; 372 else 373 cmd = PRIV_APME_DELNODE; 374 hostapd_must_write(priv_fd, &cmd, sizeof(int)); 375 hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); 376 hostapd_must_write(priv_fd, &apme->a_iface, IFNAMSIZ); 377 378 hostapd_must_read(priv_fd, &ret, sizeof(int)); 379 if (ret == 0) 380 hostapd_log(HOSTAPD_LOG_VERBOSE, "%s/%s: %s node %s", 381 apme->a_iface, iapp->i_iface, 382 add ? "added" : "removed", 383 etheraddr_string(node->ni_macaddr)); 384 385 return (ret); 386 } 387 388 void 389 hostapd_priv_apme_bssid(struct hostapd_apme *apme) 390 { 391 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 392 int ret, cmd; 393 394 if (priv_fd < 0) 395 hostapd_fatal("%s: called from privileged portion\n", __func__); 396 397 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 398 hostapd_fatal("%s: Host AP is not available\n", __func__); 399 400 cmd = PRIV_APME_BSSID; 401 hostapd_must_write(priv_fd, &cmd, sizeof(int)); 402 hostapd_must_write(priv_fd, &apme->a_iface, IFNAMSIZ); 403 hostapd_must_read(priv_fd, &ret, sizeof(int)); 404 if (ret != 0) 405 hostapd_fatal("failed to get Host AP's BSSID on" 406 " \"%s\": %s\n", apme->a_iface, strerror(errno)); 407 408 hostapd_must_read(priv_fd, &apme->a_bssid, IEEE80211_ADDR_LEN); 409 cfg->c_stats.cn_tx_apme++; 410 } 411 412 int 413 hostapd_priv_llc_xid(struct hostapd_config *cfg, struct hostapd_node *node) 414 { 415 int ret, cmd; 416 417 if (priv_fd < 0) 418 hostapd_fatal("%s: called from privileged portion\n", __func__); 419 420 cmd = PRIV_LLC_SEND_XID; 421 hostapd_must_write(priv_fd, &cmd, sizeof(int)); 422 hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); 423 hostapd_must_read(priv_fd, &ret, sizeof(int)); 424 425 if (ret == 0) 426 cfg->c_stats.cn_tx_llc++; 427 return (ret); 428 } 429 430 int 431 hostapd_priv_roaming(struct hostapd_apme *apme, struct hostapd_node *node, 432 int add) 433 { 434 struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; 435 int ret, cmd; 436 437 if (priv_fd < 0) 438 hostapd_fatal("%s: called from privileged portion\n", __func__); 439 440 if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) 441 hostapd_fatal("%s: Host AP is not available\n", __func__); 442 443 if (add) 444 cmd = PRIV_APME_ADDROAMING; 445 else 446 cmd = PRIV_APME_DELROAMING; 447 hostapd_must_write(priv_fd, &cmd, sizeof(int)); 448 hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); 449 hostapd_must_write(priv_fd, &apme->a_iface, IFNAMSIZ); 450 451 hostapd_must_read(priv_fd, &ret, sizeof(int)); 452 453 return (ret); 454 } 455 456 /* 457 * If priv parent gets a TERM or HUP, pass it through to child instead. 458 */ 459 /* ARGSUSED */ 460 void 461 hostapd_sig_relay(int sig, short event, void *arg) 462 { 463 int oerrno = errno; 464 465 if (child_pid != -1) 466 if (kill(child_pid, sig) == -1) 467 hostapd_fatal("hostapd_sig_relay: kill(%d, %d)", 468 child_pid, sig); 469 errno = oerrno; 470 } 471 472 /* ARGSUSED */ 473 void 474 hostapd_sig_chld(int sig, short event, void *arg) 475 { 476 /* 477 * If parent gets a SIGCHLD, it will exit. 478 */ 479 480 if (sig == SIGCHLD) 481 (void)event_loopexit(NULL); 482 } 483 484 /* 485 * privsep I/O functions 486 */ 487 488 /* Read all data or return 1 for error. */ 489 int 490 hostapd_may_read(int fd, void *buf, size_t n) 491 { 492 char *s = buf; 493 ssize_t res, pos = 0; 494 495 while ((ssize_t)n > pos) { 496 res = read(fd, s + pos, n - pos); 497 switch (res) { 498 case -1: 499 if (errno == EINTR || errno == EAGAIN) 500 continue; 501 /* FALLTHROUGH */ 502 case 0: 503 return (1); 504 default: 505 pos += res; 506 } 507 } 508 return (0); 509 } 510 511 /* 512 * Read data with the assertion that it all must come through, or 513 * else abort the process. Based on atomicio() from openssh. 514 */ 515 void 516 hostapd_must_read(int fd, void *buf, size_t n) 517 { 518 char *s = buf; 519 ssize_t res, pos = 0; 520 521 while ((ssize_t)n > pos) { 522 res = read(fd, s + pos, n - pos); 523 switch (res) { 524 case -1: 525 if (errno == EINTR || errno == EAGAIN) 526 continue; 527 /* FALLTHROUGH */ 528 case 0: 529 _exit(0); 530 break; 531 default: 532 pos += res; 533 } 534 } 535 } 536 537 /* 538 * Write data with the assertion that it all has to be written, or 539 * else abort the process. Based on atomicio() from openssh. 540 */ 541 void 542 hostapd_must_write(int fd, void *buf, size_t n) 543 { 544 char *s = buf; 545 ssize_t res, pos = 0; 546 547 while ((ssize_t)n > pos) { 548 res = write(fd, s + pos, n - pos); 549 switch (res) { 550 case -1: 551 if (errno == EINTR || errno == EAGAIN) 552 continue; 553 /* FALLTHROUGH */ 554 case 0: 555 _exit(0); 556 break; 557 default: 558 pos += res; 559 } 560 } 561 } 562 563