1 /* $OpenBSD: hostapd.c,v 1.41 2019/07/03 03:24:03 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 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/signal.h> 23 #include <sys/socket.h> 24 #include <sys/time.h> 25 #include <sys/queue.h> 26 #include <sys/stat.h> 27 28 #include <net/if.h> 29 #include <net/if_media.h> 30 #include <net/if_arp.h> 31 #include <net/if_llc.h> 32 #include <net/bpf.h> 33 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <arpa/inet.h> 37 38 #include <errno.h> 39 #include <event.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <stdarg.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <limits.h> 47 #include <err.h> 48 49 #include "hostapd.h" 50 #include "iapp.h" 51 52 void hostapd_usage(void); 53 void hostapd_udp_init(struct hostapd_config *); 54 void hostapd_sig_handler(int, short, void *); 55 static __inline int 56 hostapd_entry_cmp(struct hostapd_entry *, struct hostapd_entry *); 57 58 struct hostapd_config hostapd_cfg; 59 60 extern char *__progname; 61 char printbuf[BUFSIZ]; 62 63 void 64 hostapd_usage(void) 65 { 66 fprintf(stderr, "usage: %s [-dv] [-D macro=value] [-f file]\n", 67 __progname); 68 exit(EXIT_FAILURE); 69 } 70 71 void 72 hostapd_log(u_int level, const char *fmt, ...) 73 { 74 char *nfmt = NULL; 75 va_list ap; 76 77 if (level > hostapd_cfg.c_verbose) 78 return; 79 80 va_start(ap, fmt); 81 if (hostapd_cfg.c_debug) { 82 if (asprintf(&nfmt, "%s\n", fmt) != -1) 83 vfprintf(stderr, nfmt, ap); 84 else { 85 vfprintf(stderr, fmt, ap); 86 fprintf(stderr, "\n"); 87 } 88 fflush(stderr); 89 } else 90 vsyslog(LOG_INFO, fmt, ap); 91 va_end(ap); 92 93 free(nfmt); 94 } 95 96 void 97 hostapd_printf(const char *fmt, ...) 98 { 99 char newfmt[BUFSIZ]; 100 va_list ap; 101 size_t n; 102 103 if (fmt == NULL) 104 goto flush; 105 106 va_start(ap, fmt); 107 bzero(newfmt, sizeof(newfmt)); 108 if ((n = strlcpy(newfmt, printbuf, sizeof(newfmt))) >= sizeof(newfmt)) 109 goto va_flush; 110 if (strlcpy(newfmt + n, fmt, sizeof(newfmt) - n) >= sizeof(newfmt) - n) 111 goto va_flush; 112 if (vsnprintf(printbuf, sizeof(printbuf), newfmt, ap) < 0) 113 goto va_flush; 114 va_end(ap); 115 116 return; 117 118 va_flush: 119 va_end(ap); 120 flush: 121 if (strlen(printbuf)) 122 hostapd_log(HOSTAPD_LOG, "%s", printbuf); 123 bzero(printbuf, sizeof(printbuf)); 124 } 125 126 void 127 hostapd_fatal(const char *fmt, ...) 128 { 129 va_list ap; 130 131 va_start(ap, fmt); 132 if (hostapd_cfg.c_debug) { 133 vfprintf(stderr, fmt, ap); 134 fflush(stderr); 135 } else 136 vsyslog(LOG_ERR, fmt, ap); 137 va_end(ap); 138 139 hostapd_cleanup(&hostapd_cfg); 140 exit(EXIT_FAILURE); 141 } 142 143 int 144 hostapd_check_file_secrecy(int fd, const char *fname) 145 { 146 struct stat st; 147 148 if (fstat(fd, &st)) { 149 hostapd_log(HOSTAPD_LOG, 150 "cannot stat %s", fname); 151 return (-1); 152 } 153 154 if (st.st_uid != 0 && st.st_uid != getuid()) { 155 hostapd_log(HOSTAPD_LOG, 156 "%s: owner not root or current user", fname); 157 return (-1); 158 } 159 160 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 161 hostapd_log(HOSTAPD_LOG, 162 "%s: group/world readable/writeable", fname); 163 return (-1); 164 } 165 166 return (0); 167 } 168 169 int 170 hostapd_bpf_open(u_int flags) 171 { 172 int fd = -1; 173 struct bpf_version bpv; 174 175 if ((fd = open("/dev/bpf", flags)) == -1) { 176 hostapd_fatal("unable to open BPF device: %s\n", 177 strerror(errno)); 178 } 179 180 /* 181 * Get and validate the BPF version 182 */ 183 184 if (ioctl(fd, BIOCVERSION, &bpv) == -1) 185 hostapd_fatal("failed to get BPF version: %s\n", 186 strerror(errno)); 187 188 if (bpv.bv_major != BPF_MAJOR_VERSION || 189 bpv.bv_minor < BPF_MINOR_VERSION) 190 hostapd_fatal("invalid BPF version\n"); 191 192 return (fd); 193 } 194 195 void 196 hostapd_udp_init(struct hostapd_config *cfg) 197 { 198 struct hostapd_iapp *iapp = &cfg->c_iapp; 199 struct ifreq ifr; 200 struct sockaddr_in *addr, baddr; 201 struct ip_mreq mreq; 202 int brd = 1; 203 204 bzero(&ifr, sizeof(ifr)); 205 206 /* 207 * Open a listening UDP socket 208 */ 209 210 if ((iapp->i_udp = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 211 hostapd_fatal("unable to open udp socket\n"); 212 213 cfg->c_flags |= HOSTAPD_CFG_F_UDP; 214 215 (void)strlcpy(ifr.ifr_name, iapp->i_iface, sizeof(ifr.ifr_name)); 216 217 if (ioctl(iapp->i_udp, SIOCGIFADDR, &ifr) == -1) 218 hostapd_fatal("UDP ioctl %s on \"%s\" failed: %s\n", 219 "SIOCGIFADDR", ifr.ifr_name, strerror(errno)); 220 221 addr = (struct sockaddr_in *)&ifr.ifr_addr; 222 iapp->i_addr.sin_family = AF_INET; 223 iapp->i_addr.sin_addr.s_addr = addr->sin_addr.s_addr; 224 if (iapp->i_addr.sin_port == 0) 225 iapp->i_addr.sin_port = htons(IAPP_PORT); 226 227 if (ioctl(iapp->i_udp, SIOCGIFBRDADDR, &ifr) == -1) 228 hostapd_fatal("UDP ioctl %s on \"%s\" failed: %s\n", 229 "SIOCGIFBRDADDR", ifr.ifr_name, strerror(errno)); 230 231 addr = (struct sockaddr_in *)&ifr.ifr_addr; 232 iapp->i_broadcast.sin_family = AF_INET; 233 iapp->i_broadcast.sin_addr.s_addr = addr->sin_addr.s_addr; 234 iapp->i_broadcast.sin_port = iapp->i_addr.sin_port; 235 236 baddr.sin_family = AF_INET; 237 baddr.sin_addr.s_addr = htonl(INADDR_ANY); 238 baddr.sin_port = iapp->i_addr.sin_port; 239 240 if (bind(iapp->i_udp, (struct sockaddr *)&baddr, 241 sizeof(baddr)) == -1) 242 hostapd_fatal("failed to bind UDP socket: %s\n", 243 strerror(errno)); 244 245 /* 246 * The revised 802.11F standard requires IAPP messages to be 247 * sent via multicast to the default group 224.0.1.178. 248 * Nevertheless, some implementations still use broadcasts 249 * for IAPP messages. 250 */ 251 if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) { 252 /* 253 * Enable broadcast 254 */ 255 if (setsockopt(iapp->i_udp, SOL_SOCKET, SO_BROADCAST, 256 &brd, sizeof(brd)) == -1) 257 hostapd_fatal("failed to enable broadcast on socket\n"); 258 259 hostapd_log(HOSTAPD_LOG_DEBUG, "%s: using broadcast mode " 260 "(address %s)", iapp->i_iface, inet_ntoa(addr->sin_addr)); 261 } else { 262 /* 263 * Enable multicast 264 */ 265 bzero(&mreq, sizeof(mreq)); 266 267 iapp->i_multicast.sin_family = AF_INET; 268 if (iapp->i_multicast.sin_addr.s_addr == INADDR_ANY) 269 iapp->i_multicast.sin_addr.s_addr = 270 inet_addr(IAPP_MCASTADDR); 271 iapp->i_multicast.sin_port = iapp->i_addr.sin_port; 272 273 mreq.imr_multiaddr.s_addr = 274 iapp->i_multicast.sin_addr.s_addr; 275 mreq.imr_interface.s_addr = 276 iapp->i_addr.sin_addr.s_addr; 277 278 if (setsockopt(iapp->i_udp, IPPROTO_IP, 279 IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) 280 hostapd_fatal("failed to add multicast membership to " 281 "%s: %s\n", IAPP_MCASTADDR, strerror(errno)); 282 283 if (setsockopt(iapp->i_udp, IPPROTO_IP, IP_MULTICAST_TTL, 284 &iapp->i_ttl, sizeof(iapp->i_ttl)) == -1) 285 hostapd_fatal("failed to set multicast ttl to " 286 "%u: %s\n", iapp->i_ttl, strerror(errno)); 287 288 hostapd_log(HOSTAPD_LOG_DEBUG, "%s: using multicast mode " 289 "(ttl %u, group %s)", iapp->i_iface, iapp->i_ttl, 290 inet_ntoa(iapp->i_multicast.sin_addr)); 291 } 292 } 293 294 /* ARGSUSED */ 295 void 296 hostapd_sig_handler(int sig, short event, void *arg) 297 { 298 switch (sig) { 299 case SIGALRM: 300 case SIGTERM: 301 case SIGQUIT: 302 case SIGINT: 303 (void)event_loopexit(NULL); 304 } 305 } 306 307 void 308 hostapd_cleanup(struct hostapd_config *cfg) 309 { 310 struct hostapd_iapp *iapp = &cfg->c_iapp; 311 struct ip_mreq mreq; 312 struct hostapd_apme *apme; 313 struct hostapd_table *table; 314 struct hostapd_entry *entry; 315 316 /* Release all Host APs */ 317 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 318 while ((apme = TAILQ_FIRST(&cfg->c_apmes)) != NULL) 319 hostapd_apme_term(apme); 320 } 321 322 if (cfg->c_flags & HOSTAPD_CFG_F_PRIV && 323 (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) == 0) { 324 /* 325 * Disable multicast and let the kernel unsubscribe 326 * from the multicast group. 327 */ 328 329 bzero(&mreq, sizeof(mreq)); 330 331 mreq.imr_multiaddr.s_addr = 332 inet_addr(IAPP_MCASTADDR); 333 mreq.imr_interface.s_addr = 334 iapp->i_addr.sin_addr.s_addr; 335 336 if (setsockopt(iapp->i_udp, IPPROTO_IP, 337 IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) 338 hostapd_log(HOSTAPD_LOG, "failed to remove multicast" 339 " membership to %s: %s", 340 IAPP_MCASTADDR, strerror(errno)); 341 } 342 343 if ((cfg->c_flags & HOSTAPD_CFG_F_PRIV) == 0 && 344 cfg->c_flags & HOSTAPD_CFG_F_APME) { 345 /* Shutdown the Host AP protocol handler */ 346 hostapd_iapp_term(&hostapd_cfg); 347 } 348 349 /* Cleanup tables */ 350 while ((table = TAILQ_FIRST(&cfg->c_tables)) != NULL) { 351 while ((entry = RB_MIN(hostapd_tree, &table->t_tree)) != NULL) { 352 RB_REMOVE(hostapd_tree, &table->t_tree, entry); 353 free(entry); 354 } 355 while ((entry = TAILQ_FIRST(&table->t_mask_head)) != NULL) { 356 TAILQ_REMOVE(&table->t_mask_head, entry, e_entries); 357 free(entry); 358 } 359 TAILQ_REMOVE(&cfg->c_tables, table, t_entries); 360 free(table); 361 } 362 363 hostapd_log(HOSTAPD_LOG_VERBOSE, "bye!"); 364 } 365 366 int 367 main(int argc, char *argv[]) 368 { 369 struct event ev_sigalrm; 370 struct event ev_sigterm; 371 struct event ev_sigquit; 372 struct event ev_sigint; 373 struct hostapd_config *cfg = &hostapd_cfg; 374 struct hostapd_iapp *iapp; 375 struct hostapd_apme *apme; 376 char *config = NULL; 377 u_int debug = 0, ret; 378 int ch; 379 380 /* Set startup logging */ 381 cfg->c_debug = 1; 382 383 /* 384 * Get and parse command line options 385 */ 386 while ((ch = getopt(argc, argv, "f:D:dv")) != -1) { 387 switch (ch) { 388 case 'f': 389 config = optarg; 390 break; 391 case 'D': 392 if (hostapd_parse_symset(optarg) < 0) 393 hostapd_fatal("could not parse macro " 394 "definition %s\n", optarg); 395 break; 396 case 'd': 397 debug++; 398 break; 399 case 'v': 400 cfg->c_verbose++; 401 break; 402 default: 403 hostapd_usage(); 404 } 405 } 406 407 argc -= optind; 408 argv += optind; 409 if (argc > 0) 410 hostapd_usage(); 411 412 if (config == NULL) 413 ret = strlcpy(cfg->c_config, HOSTAPD_CONFIG, sizeof(cfg->c_config)); 414 else 415 ret = strlcpy(cfg->c_config, config, sizeof(cfg->c_config)); 416 if (ret >= sizeof(cfg->c_config)) 417 hostapd_fatal("invalid configuration file\n"); 418 419 if (geteuid()) 420 hostapd_fatal("need root privileges\n"); 421 422 /* Parse the configuration file */ 423 if (hostapd_parse_file(cfg) != 0) 424 hostapd_fatal("invalid configuration in %s\n", cfg->c_config); 425 426 iapp = &cfg->c_iapp; 427 428 if ((cfg->c_flags & HOSTAPD_CFG_F_IAPP) == 0) 429 hostapd_fatal("IAPP interface not specified\n"); 430 431 if (cfg->c_apme_dlt == 0) 432 cfg->c_apme_dlt = HOSTAPD_DLT; 433 434 /* 435 * Setup the hostapd handlers 436 */ 437 hostapd_udp_init(cfg); 438 hostapd_llc_init(cfg); 439 440 /* 441 * Set runtime logging and detach as daemon 442 */ 443 if ((cfg->c_debug = debug) == 0) { 444 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 445 tzset(); 446 if (daemon(0, 0) == -1) 447 hostapd_fatal("failed to daemonize\n"); 448 } 449 450 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 451 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) 452 hostapd_apme_init(apme); 453 } else 454 hostapd_log(HOSTAPD_LOG, "%s: running without a Host AP", 455 iapp->i_iface); 456 457 /* Drop all privileges in an unprivileged child process */ 458 hostapd_priv_init(cfg); 459 460 if (cfg->c_flags & HOSTAPD_CFG_F_APME) 461 setproctitle("IAPP: %s, Host AP", iapp->i_iface); 462 else 463 setproctitle("IAPP: %s", iapp->i_iface); 464 465 /* 466 * Unprivileged child process 467 */ 468 469 (void)event_init(); 470 471 /* 472 * Set signal handlers 473 */ 474 signal_set(&ev_sigalrm, SIGALRM, hostapd_sig_handler, NULL); 475 signal_set(&ev_sigterm, SIGTERM, hostapd_sig_handler, NULL); 476 signal_set(&ev_sigquit, SIGQUIT, hostapd_sig_handler, NULL); 477 signal_set(&ev_sigint, SIGINT, hostapd_sig_handler, NULL); 478 signal_add(&ev_sigalrm, NULL); 479 signal_add(&ev_sigterm, NULL); 480 signal_add(&ev_sigquit, NULL); 481 signal_add(&ev_sigint, NULL); 482 signal(SIGHUP, SIG_IGN); 483 signal(SIGCHLD, SIG_IGN); 484 485 /* Initialize the IAPP protocol handler */ 486 hostapd_iapp_init(cfg); 487 488 /* 489 * Schedule the Host AP listener 490 */ 491 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 492 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 493 event_set(&apme->a_ev, apme->a_raw, 494 EV_READ | EV_PERSIST, hostapd_apme_input, apme); 495 if (event_add(&apme->a_ev, NULL) == -1) 496 hostapd_fatal("failed to add APME event"); 497 } 498 } 499 500 /* 501 * Schedule the IAPP listener 502 */ 503 event_set(&iapp->i_udp_ev, iapp->i_udp, EV_READ | EV_PERSIST, 504 hostapd_iapp_input, cfg); 505 if (event_add(&iapp->i_udp_ev, NULL) == -1) 506 hostapd_fatal("failed to add IAPP event"); 507 508 hostapd_log(HOSTAPD_LOG, "starting hostapd with pid %u", 509 getpid()); 510 511 /* Run event loop */ 512 if (event_dispatch() == -1) 513 hostapd_fatal("failed to dispatch hostapd"); 514 515 /* Executed after the event loop has been terminated */ 516 hostapd_cleanup(cfg); 517 return (EXIT_SUCCESS); 518 } 519 520 void 521 hostapd_randval(u_int8_t *buf, const u_int len) 522 { 523 u_int32_t data = 0; 524 u_int i; 525 526 for (i = 0; i < len; i++) { 527 if ((i % sizeof(data)) == 0) 528 data = arc4random(); 529 buf[i] = data & 0xff; 530 data >>= 8; 531 } 532 } 533 534 struct hostapd_table * 535 hostapd_table_add(struct hostapd_config *cfg, const char *name) 536 { 537 struct hostapd_table *table; 538 539 if (hostapd_table_lookup(cfg, name) != NULL) 540 return (NULL); 541 if ((table = (struct hostapd_table *) 542 calloc(1, sizeof(struct hostapd_table))) == NULL) 543 return (NULL); 544 if (strlcpy(table->t_name, name, sizeof(table->t_name)) >= 545 sizeof(table->t_name)) { 546 free(table); 547 return (NULL); 548 } 549 RB_INIT(&table->t_tree); 550 TAILQ_INIT(&table->t_mask_head); 551 TAILQ_INSERT_TAIL(&cfg->c_tables, table, t_entries); 552 553 return (table); 554 } 555 556 struct hostapd_table * 557 hostapd_table_lookup(struct hostapd_config *cfg, const char *name) 558 { 559 struct hostapd_table *table; 560 561 TAILQ_FOREACH(table, &cfg->c_tables, t_entries) { 562 if (strcmp(name, table->t_name) == 0) 563 return (table); 564 } 565 566 return (NULL); 567 } 568 569 struct hostapd_entry * 570 hostapd_entry_add(struct hostapd_table *table, u_int8_t *lladdr) 571 { 572 struct hostapd_entry *entry; 573 574 if (hostapd_entry_lookup(table, lladdr) != NULL) 575 return (NULL); 576 577 if ((entry = (struct hostapd_entry *) 578 calloc(1, sizeof(struct hostapd_entry))) == NULL) 579 return (NULL); 580 581 bcopy(lladdr, entry->e_lladdr, IEEE80211_ADDR_LEN); 582 RB_INSERT(hostapd_tree, &table->t_tree, entry); 583 584 return (entry); 585 } 586 587 struct hostapd_entry * 588 hostapd_entry_lookup(struct hostapd_table *table, u_int8_t *lladdr) 589 { 590 struct hostapd_entry *entry, key; 591 592 bcopy(lladdr, key.e_lladdr, IEEE80211_ADDR_LEN); 593 if ((entry = RB_FIND(hostapd_tree, &table->t_tree, &key)) != NULL) 594 return (entry); 595 596 /* Masked entries can't be handled by the red-black tree */ 597 TAILQ_FOREACH(entry, &table->t_mask_head, e_entries) { 598 if (HOSTAPD_ENTRY_MASK_MATCH(entry, lladdr)) 599 return (entry); 600 } 601 602 return (NULL); 603 } 604 605 void 606 hostapd_entry_update(struct hostapd_table *table, struct hostapd_entry *entry) 607 { 608 RB_REMOVE(hostapd_tree, &table->t_tree, entry); 609 610 /* Apply mask to entry */ 611 if (entry->e_flags & HOSTAPD_ENTRY_F_MASK) { 612 HOSTAPD_ENTRY_MASK_ADD(entry->e_lladdr, entry->e_mask); 613 TAILQ_INSERT_TAIL(&table->t_mask_head, entry, e_entries); 614 } else { 615 RB_INSERT(hostapd_tree, &table->t_tree, entry); 616 } 617 } 618 619 static __inline int 620 hostapd_entry_cmp(struct hostapd_entry *a, struct hostapd_entry *b) 621 { 622 return (memcmp(a->e_lladdr, b->e_lladdr, IEEE80211_ADDR_LEN)); 623 } 624 625 RB_GENERATE(hostapd_tree, hostapd_entry, e_nodes, hostapd_entry_cmp); 626