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