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