1 /* $OpenBSD: hostapd.c,v 1.34 2008/05/12 23:49:28 millert 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/param.h> 21 #include <sys/ioctl.h> 22 #include <sys/types.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 <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 if (nfmt != NULL) 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 u_int i; 174 int fd = -1; 175 char *dev; 176 struct bpf_version bpv; 177 178 /* 179 * Try to open the next available BPF device 180 */ 181 for (i = 0; i < 255; i++) { 182 if (asprintf(&dev, "/dev/bpf%u", i) == -1) 183 hostapd_fatal("failed to allocate buffer\n"); 184 185 if ((fd = open(dev, flags)) != -1) { 186 free(dev); 187 break; 188 } 189 190 free(dev); 191 } 192 193 if (fd == -1) 194 hostapd_fatal("unable to open BPF device\n"); 195 196 /* 197 * Get and validate the BPF version 198 */ 199 200 if (ioctl(fd, BIOCVERSION, &bpv) == -1) 201 hostapd_fatal("failed to get BPF version: %s\n", 202 strerror(errno)); 203 204 if (bpv.bv_major != BPF_MAJOR_VERSION || 205 bpv.bv_minor < BPF_MINOR_VERSION) 206 hostapd_fatal("invalid BPF version\n"); 207 208 return (fd); 209 } 210 211 void 212 hostapd_udp_init(struct hostapd_config *cfg) 213 { 214 struct hostapd_iapp *iapp = &cfg->c_iapp; 215 struct ifreq ifr; 216 struct sockaddr_in *addr, baddr; 217 struct ip_mreq mreq; 218 int brd = 1; 219 220 bzero(&ifr, sizeof(ifr)); 221 222 /* 223 * Open a listening UDP socket 224 */ 225 226 if ((iapp->i_udp = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 227 hostapd_fatal("unable to open udp socket\n"); 228 229 cfg->c_flags |= HOSTAPD_CFG_F_UDP; 230 231 (void)strlcpy(ifr.ifr_name, iapp->i_iface, sizeof(ifr.ifr_name)); 232 233 if (ioctl(iapp->i_udp, SIOCGIFADDR, &ifr) == -1) 234 hostapd_fatal("UDP ioctl %s on \"%s\" failed: %s\n", 235 "SIOCGIFADDR", ifr.ifr_name, strerror(errno)); 236 237 addr = (struct sockaddr_in *)&ifr.ifr_addr; 238 iapp->i_addr.sin_family = AF_INET; 239 iapp->i_addr.sin_addr.s_addr = addr->sin_addr.s_addr; 240 if (iapp->i_addr.sin_port == 0) 241 iapp->i_addr.sin_port = htons(IAPP_PORT); 242 243 if (ioctl(iapp->i_udp, SIOCGIFBRDADDR, &ifr) == -1) 244 hostapd_fatal("UDP ioctl %s on \"%s\" failed: %s\n", 245 "SIOCGIFBRDADDR", ifr.ifr_name, strerror(errno)); 246 247 addr = (struct sockaddr_in *)&ifr.ifr_addr; 248 iapp->i_broadcast.sin_family = AF_INET; 249 iapp->i_broadcast.sin_addr.s_addr = addr->sin_addr.s_addr; 250 iapp->i_broadcast.sin_port = iapp->i_addr.sin_port; 251 252 baddr.sin_family = AF_INET; 253 baddr.sin_addr.s_addr = htonl(INADDR_ANY); 254 baddr.sin_port = iapp->i_addr.sin_port; 255 256 if (bind(iapp->i_udp, (struct sockaddr *)&baddr, 257 sizeof(baddr)) == -1) 258 hostapd_fatal("failed to bind UDP socket: %s\n", 259 strerror(errno)); 260 261 /* 262 * The revised 802.11F standard requires IAPP messages to be 263 * sent via multicast to the default group 224.0.1.178. 264 * Nevertheless, some implementations still use broadcasts 265 * for IAPP messages. 266 */ 267 if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) { 268 /* 269 * Enable broadcast 270 */ 271 if (setsockopt(iapp->i_udp, SOL_SOCKET, SO_BROADCAST, 272 &brd, sizeof(brd)) == -1) 273 hostapd_fatal("failed to enable broadcast on socket\n"); 274 275 hostapd_log(HOSTAPD_LOG_DEBUG, "%s: using broadcast mode " 276 "(address %s)", iapp->i_iface, inet_ntoa(addr->sin_addr)); 277 } else { 278 /* 279 * Enable multicast 280 */ 281 bzero(&mreq, sizeof(mreq)); 282 283 iapp->i_multicast.sin_family = AF_INET; 284 if (iapp->i_multicast.sin_addr.s_addr == INADDR_ANY) 285 iapp->i_multicast.sin_addr.s_addr = 286 inet_addr(IAPP_MCASTADDR); 287 iapp->i_multicast.sin_port = iapp->i_addr.sin_port; 288 289 mreq.imr_multiaddr.s_addr = 290 iapp->i_multicast.sin_addr.s_addr; 291 mreq.imr_interface.s_addr = 292 iapp->i_addr.sin_addr.s_addr; 293 294 if (setsockopt(iapp->i_udp, IPPROTO_IP, 295 IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) 296 hostapd_fatal("failed to add multicast membership to " 297 "%s: %s\n", IAPP_MCASTADDR, strerror(errno)); 298 299 if (setsockopt(iapp->i_udp, IPPROTO_IP, IP_MULTICAST_TTL, 300 &iapp->i_ttl, sizeof(iapp->i_ttl)) < 0) 301 hostapd_fatal("failed to set multicast ttl to " 302 "%u: %s\n", iapp->i_ttl, strerror(errno)); 303 304 hostapd_log(HOSTAPD_LOG_DEBUG, "%s: using multicast mode " 305 "(ttl %u, group %s)", iapp->i_iface, iapp->i_ttl, 306 inet_ntoa(iapp->i_multicast.sin_addr)); 307 } 308 } 309 310 /* ARGSUSED */ 311 void 312 hostapd_sig_handler(int sig, short event, void *arg) 313 { 314 switch (sig) { 315 case SIGALRM: 316 case SIGTERM: 317 case SIGQUIT: 318 case SIGINT: 319 (void)event_loopexit(NULL); 320 } 321 } 322 323 void 324 hostapd_cleanup(struct hostapd_config *cfg) 325 { 326 struct hostapd_iapp *iapp = &cfg->c_iapp; 327 struct ip_mreq mreq; 328 struct hostapd_apme *apme; 329 struct hostapd_table *table; 330 struct hostapd_entry *entry; 331 332 /* Release all Host APs */ 333 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 334 while ((apme = TAILQ_FIRST(&cfg->c_apmes)) != NULL) 335 hostapd_apme_term(apme); 336 } 337 338 if (cfg->c_flags & HOSTAPD_CFG_F_PRIV && 339 (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) == 0) { 340 /* 341 * Disable multicast and let the kernel unsubscribe 342 * from the multicast group. 343 */ 344 345 bzero(&mreq, sizeof(mreq)); 346 347 mreq.imr_multiaddr.s_addr = 348 inet_addr(IAPP_MCASTADDR); 349 mreq.imr_interface.s_addr = 350 iapp->i_addr.sin_addr.s_addr; 351 352 if (setsockopt(iapp->i_udp, IPPROTO_IP, 353 IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) 354 hostapd_log(HOSTAPD_LOG, "failed to remove multicast" 355 " membership to %s: %s", 356 IAPP_MCASTADDR, strerror(errno)); 357 } 358 359 if ((cfg->c_flags & HOSTAPD_CFG_F_PRIV) == 0 && 360 cfg->c_flags & HOSTAPD_CFG_F_APME) { 361 /* Shutdown the Host AP protocol handler */ 362 hostapd_iapp_term(&hostapd_cfg); 363 } 364 365 /* Cleanup tables */ 366 while ((table = TAILQ_FIRST(&cfg->c_tables)) != NULL) { 367 while ((entry = RB_MIN(hostapd_tree, &table->t_tree)) != NULL) { 368 RB_REMOVE(hostapd_tree, &table->t_tree, entry); 369 free(entry); 370 } 371 while ((entry = TAILQ_FIRST(&table->t_mask_head)) != NULL) { 372 TAILQ_REMOVE(&table->t_mask_head, entry, e_entries); 373 free(entry); 374 } 375 TAILQ_REMOVE(&cfg->c_tables, table, t_entries); 376 free(table); 377 } 378 379 hostapd_log(HOSTAPD_LOG_VERBOSE, "bye!"); 380 } 381 382 int 383 main(int argc, char *argv[]) 384 { 385 struct event ev_sigalrm; 386 struct event ev_sigterm; 387 struct event ev_sigquit; 388 struct event ev_sigint; 389 struct hostapd_config *cfg = &hostapd_cfg; 390 struct hostapd_iapp *iapp; 391 struct hostapd_apme *apme; 392 char *config = NULL; 393 u_int debug = 0, ret; 394 int ch; 395 396 /* Set startup logging */ 397 cfg->c_debug = 1; 398 399 /* 400 * Get and parse command line options 401 */ 402 while ((ch = getopt(argc, argv, "f:D:dv")) != -1) { 403 switch (ch) { 404 case 'f': 405 config = optarg; 406 break; 407 case 'D': 408 if (hostapd_parse_symset(optarg) < 0) 409 hostapd_fatal("could not parse macro " 410 "definition %s\n", optarg); 411 break; 412 case 'd': 413 debug++; 414 break; 415 case 'v': 416 cfg->c_verbose++; 417 break; 418 default: 419 hostapd_usage(); 420 } 421 } 422 423 argc -= optind; 424 argv += optind; 425 if (argc > 0) 426 hostapd_usage(); 427 428 if (config == NULL) 429 ret = strlcpy(cfg->c_config, HOSTAPD_CONFIG, sizeof(cfg->c_config)); 430 else 431 ret = strlcpy(cfg->c_config, config, sizeof(cfg->c_config)); 432 if (ret >= sizeof(cfg->c_config)) 433 hostapd_fatal("invalid configuration file\n"); 434 435 if (geteuid()) 436 hostapd_fatal("need root privileges\n"); 437 438 /* Parse the configuration file */ 439 if (hostapd_parse_file(cfg) != 0) 440 hostapd_fatal("invalid configuration in %s\n", cfg->c_config); 441 442 iapp = &cfg->c_iapp; 443 444 if ((cfg->c_flags & HOSTAPD_CFG_F_IAPP) == 0) 445 hostapd_fatal("IAPP interface not specified\n"); 446 447 if (cfg->c_apme_dlt == 0) 448 cfg->c_apme_dlt = HOSTAPD_DLT; 449 450 /* 451 * Setup the hostapd handlers 452 */ 453 hostapd_udp_init(cfg); 454 hostapd_llc_init(cfg); 455 456 /* 457 * Set runtime logging and detach as daemon 458 */ 459 if ((cfg->c_debug = debug) == 0) { 460 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 461 tzset(); 462 if (daemon(0, 0) == -1) 463 hostapd_fatal("failed to daemonize\n"); 464 } 465 466 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 467 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) 468 hostapd_apme_init(apme); 469 } else 470 hostapd_log(HOSTAPD_LOG, "%s: running without a Host AP", 471 iapp->i_iface); 472 473 /* Drop all privileges in an unprivileged child process */ 474 hostapd_priv_init(cfg); 475 476 if (cfg->c_flags & HOSTAPD_CFG_F_APME) 477 setproctitle("IAPP: %s, Host AP", iapp->i_iface); 478 else 479 setproctitle("IAPP: %s", iapp->i_iface); 480 481 /* 482 * Unprivileged child process 483 */ 484 485 (void)event_init(); 486 487 /* 488 * Set signal handlers 489 */ 490 signal_set(&ev_sigalrm, SIGALRM, hostapd_sig_handler, NULL); 491 signal_set(&ev_sigterm, SIGTERM, hostapd_sig_handler, NULL); 492 signal_set(&ev_sigquit, SIGQUIT, hostapd_sig_handler, NULL); 493 signal_set(&ev_sigint, SIGINT, hostapd_sig_handler, NULL); 494 signal_add(&ev_sigalrm, NULL); 495 signal_add(&ev_sigterm, NULL); 496 signal_add(&ev_sigquit, NULL); 497 signal_add(&ev_sigint, NULL); 498 signal(SIGHUP, SIG_IGN); 499 signal(SIGCHLD, SIG_IGN); 500 501 /* Initialize the IAPP protocol handler */ 502 hostapd_iapp_init(cfg); 503 504 /* 505 * Schedule the Host AP listener 506 */ 507 if (cfg->c_flags & HOSTAPD_CFG_F_APME) { 508 TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) { 509 event_set(&apme->a_ev, apme->a_raw, 510 EV_READ | EV_PERSIST, hostapd_apme_input, apme); 511 if (event_add(&apme->a_ev, NULL) == -1) 512 hostapd_fatal("failed to add APME event"); 513 } 514 } 515 516 /* 517 * Schedule the IAPP listener 518 */ 519 event_set(&iapp->i_udp_ev, iapp->i_udp, EV_READ | EV_PERSIST, 520 hostapd_iapp_input, cfg); 521 if (event_add(&iapp->i_udp_ev, NULL) == -1) 522 hostapd_fatal("failed to add IAPP event"); 523 524 hostapd_log(HOSTAPD_LOG, "starting hostapd with pid %u", 525 getpid()); 526 527 /* Run event loop */ 528 if (event_dispatch() == -1) 529 hostapd_fatal("failed to dispatch hostapd"); 530 531 /* Executed after the event loop has been terminated */ 532 hostapd_cleanup(cfg); 533 return (EXIT_SUCCESS); 534 } 535 536 void 537 hostapd_randval(u_int8_t *buf, const u_int len) 538 { 539 u_int32_t data = 0; 540 u_int i; 541 542 for (i = 0; i < len; i++) { 543 if ((i % sizeof(data)) == 0) 544 data = arc4random(); 545 buf[i] = data & 0xff; 546 data >>= 8; 547 } 548 } 549 550 struct hostapd_table * 551 hostapd_table_add(struct hostapd_config *cfg, const char *name) 552 { 553 struct hostapd_table *table; 554 555 if (hostapd_table_lookup(cfg, name) != NULL) 556 return (NULL); 557 if ((table = (struct hostapd_table *) 558 calloc(1, sizeof(struct hostapd_table))) == NULL) 559 return (NULL); 560 if (strlcpy(table->t_name, name, sizeof(table->t_name)) >= 561 sizeof(table->t_name)) { 562 free(table); 563 return (NULL); 564 } 565 RB_INIT(&table->t_tree); 566 TAILQ_INIT(&table->t_mask_head); 567 TAILQ_INSERT_TAIL(&cfg->c_tables, table, t_entries); 568 569 return (table); 570 } 571 572 struct hostapd_table * 573 hostapd_table_lookup(struct hostapd_config *cfg, const char *name) 574 { 575 struct hostapd_table *table; 576 577 TAILQ_FOREACH(table, &cfg->c_tables, t_entries) { 578 if (strcmp(name, table->t_name) == 0) 579 return (table); 580 } 581 582 return (NULL); 583 } 584 585 struct hostapd_entry * 586 hostapd_entry_add(struct hostapd_table *table, u_int8_t *lladdr) 587 { 588 struct hostapd_entry *entry; 589 590 if (hostapd_entry_lookup(table, lladdr) != NULL) 591 return (NULL); 592 593 if ((entry = (struct hostapd_entry *) 594 calloc(1, sizeof(struct hostapd_entry))) == NULL) 595 return (NULL); 596 597 bcopy(lladdr, entry->e_lladdr, IEEE80211_ADDR_LEN); 598 RB_INSERT(hostapd_tree, &table->t_tree, entry); 599 600 return (entry); 601 } 602 603 struct hostapd_entry * 604 hostapd_entry_lookup(struct hostapd_table *table, u_int8_t *lladdr) 605 { 606 struct hostapd_entry *entry, key; 607 608 bcopy(lladdr, key.e_lladdr, IEEE80211_ADDR_LEN); 609 if ((entry = RB_FIND(hostapd_tree, &table->t_tree, &key)) != NULL) 610 return (entry); 611 612 /* Masked entries can't be handled by the red-black tree */ 613 TAILQ_FOREACH(entry, &table->t_mask_head, e_entries) { 614 if (HOSTAPD_ENTRY_MASK_MATCH(entry, lladdr)) 615 return (entry); 616 } 617 618 return (NULL); 619 } 620 621 void 622 hostapd_entry_update(struct hostapd_table *table, struct hostapd_entry *entry) 623 { 624 RB_REMOVE(hostapd_tree, &table->t_tree, entry); 625 626 /* Apply mask to entry */ 627 if (entry->e_flags & HOSTAPD_ENTRY_F_MASK) { 628 HOSTAPD_ENTRY_MASK_ADD(entry->e_lladdr, entry->e_mask); 629 TAILQ_INSERT_TAIL(&table->t_mask_head, entry, e_entries); 630 } else { 631 RB_INSERT(hostapd_tree, &table->t_tree, entry); 632 } 633 } 634 635 static __inline int 636 hostapd_entry_cmp(struct hostapd_entry *a, struct hostapd_entry *b) 637 { 638 return (memcmp(a->e_lladdr, b->e_lladdr, IEEE80211_ADDR_LEN)); 639 } 640 641 RB_GENERATE(hostapd_tree, hostapd_entry, e_nodes, hostapd_entry_cmp); 642