1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/cnv.h> 32 #include <sys/dnv.h> 33 #include <sys/nv.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <netdb.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <libcasper.h> 45 #include <libcasper_service.h> 46 47 #include "cap_net.h" 48 49 #define CAPNET_MASK (CAPNET_ADDR2NAME | CAPNET_NAME2ADDR \ 50 CAPNET_DEPRECATED_ADDR2NAME | CAPNET_DEPRECATED_NAME2ADDR | \ 51 CAPNET_CONNECT | CAPNET_BIND | CAPNET_CONNECTDNS) 52 53 /* 54 * Defines for the names of the limits. 55 * XXX: we should convert all string constats to this to avoid typos. 56 */ 57 #define LIMIT_NV_BIND "bind" 58 #define LIMIT_NV_CONNECT "connect" 59 #define LIMIT_NV_ADDR2NAME "addr2name" 60 #define LIMIT_NV_NAME2ADDR "name2addr" 61 62 struct cap_net_limit { 63 cap_channel_t *cnl_chan; 64 uint64_t cnl_mode; 65 nvlist_t *cnl_addr2name; 66 nvlist_t *cnl_name2addr; 67 nvlist_t *cnl_connect; 68 nvlist_t *cnl_bind; 69 }; 70 71 static struct hostent hent; 72 73 static void 74 hostent_free(struct hostent *hp) 75 { 76 unsigned int ii; 77 78 free(hp->h_name); 79 hp->h_name = NULL; 80 if (hp->h_aliases != NULL) { 81 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) 82 free(hp->h_aliases[ii]); 83 free(hp->h_aliases); 84 hp->h_aliases = NULL; 85 } 86 if (hp->h_addr_list != NULL) { 87 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) 88 free(hp->h_addr_list[ii]); 89 free(hp->h_addr_list); 90 hp->h_addr_list = NULL; 91 } 92 } 93 94 static struct hostent * 95 hostent_unpack(const nvlist_t *nvl, struct hostent *hp) 96 { 97 unsigned int ii, nitems; 98 char nvlname[64]; 99 int n; 100 101 hostent_free(hp); 102 103 hp->h_name = strdup(nvlist_get_string(nvl, "name")); 104 if (hp->h_name == NULL) 105 goto fail; 106 hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype"); 107 hp->h_length = (int)nvlist_get_number(nvl, "length"); 108 109 nitems = (unsigned int)nvlist_get_number(nvl, "naliases"); 110 hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1); 111 if (hp->h_aliases == NULL) 112 goto fail; 113 for (ii = 0; ii < nitems; ii++) { 114 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 115 assert(n > 0 && n < (int)sizeof(nvlname)); 116 hp->h_aliases[ii] = 117 strdup(nvlist_get_string(nvl, nvlname)); 118 if (hp->h_aliases[ii] == NULL) 119 goto fail; 120 } 121 hp->h_aliases[ii] = NULL; 122 123 nitems = (unsigned int)nvlist_get_number(nvl, "naddrs"); 124 hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1); 125 if (hp->h_addr_list == NULL) 126 goto fail; 127 for (ii = 0; ii < nitems; ii++) { 128 hp->h_addr_list[ii] = malloc(hp->h_length); 129 if (hp->h_addr_list[ii] == NULL) 130 goto fail; 131 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 132 assert(n > 0 && n < (int)sizeof(nvlname)); 133 bcopy(nvlist_get_binary(nvl, nvlname, NULL), 134 hp->h_addr_list[ii], hp->h_length); 135 } 136 hp->h_addr_list[ii] = NULL; 137 138 return (hp); 139 fail: 140 hostent_free(hp); 141 h_errno = NO_RECOVERY; 142 return (NULL); 143 } 144 145 static int 146 request_cb(cap_channel_t *chan, const char *name, int s, 147 const struct sockaddr *saddr, socklen_t len) 148 { 149 nvlist_t *nvl; 150 int serrno; 151 152 nvl = nvlist_create(0); 153 nvlist_add_string(nvl, "cmd", name); 154 nvlist_add_descriptor(nvl, "s", s); 155 nvlist_add_binary(nvl, "saddr", saddr, len); 156 157 nvl = cap_xfer_nvlist(chan, nvl); 158 if (nvl == NULL) 159 return (-1); 160 161 if (nvlist_get_number(nvl, "error") != 0) { 162 serrno = (int)nvlist_get_number(nvl, "error"); 163 nvlist_destroy(nvl); 164 errno = serrno; 165 return (-1); 166 } 167 168 s = dup2(s, nvlist_get_descriptor(nvl, "s")); 169 nvlist_destroy(nvl); 170 171 return (s == -1 ? -1 : 0); 172 } 173 174 int 175 cap_bind(cap_channel_t *chan, int s, const struct sockaddr *addr, 176 socklen_t addrlen) 177 { 178 179 return (request_cb(chan, LIMIT_NV_BIND, s, addr, addrlen)); 180 } 181 182 int 183 cap_connect(cap_channel_t *chan, int s, const struct sockaddr *name, 184 socklen_t namelen) 185 { 186 187 return (request_cb(chan, LIMIT_NV_CONNECT, s, name, namelen)); 188 } 189 190 191 struct hostent * 192 cap_gethostbyname(cap_channel_t *chan, const char *name) 193 { 194 195 return (cap_gethostbyname2(chan, name, AF_INET)); 196 } 197 198 struct hostent * 199 cap_gethostbyname2(cap_channel_t *chan, const char *name, int af) 200 { 201 struct hostent *hp; 202 nvlist_t *nvl; 203 204 nvl = nvlist_create(0); 205 nvlist_add_string(nvl, "cmd", "gethostbyname"); 206 nvlist_add_number(nvl, "family", (uint64_t)af); 207 nvlist_add_string(nvl, "name", name); 208 nvl = cap_xfer_nvlist(chan, nvl); 209 if (nvl == NULL) { 210 h_errno = NO_RECOVERY; 211 return (NULL); 212 } 213 if (nvlist_get_number(nvl, "error") != 0) { 214 h_errno = (int)nvlist_get_number(nvl, "error"); 215 nvlist_destroy(nvl); 216 return (NULL); 217 } 218 219 hp = hostent_unpack(nvl, &hent); 220 nvlist_destroy(nvl); 221 return (hp); 222 } 223 224 struct hostent * 225 cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len, 226 int af) 227 { 228 struct hostent *hp; 229 nvlist_t *nvl; 230 231 nvl = nvlist_create(0); 232 nvlist_add_string(nvl, "cmd", "gethostbyaddr"); 233 nvlist_add_binary(nvl, "addr", addr, (size_t)len); 234 nvlist_add_number(nvl, "family", (uint64_t)af); 235 nvl = cap_xfer_nvlist(chan, nvl); 236 if (nvl == NULL) { 237 h_errno = NO_RECOVERY; 238 return (NULL); 239 } 240 if (nvlist_get_number(nvl, "error") != 0) { 241 h_errno = (int)nvlist_get_number(nvl, "error"); 242 nvlist_destroy(nvl); 243 return (NULL); 244 } 245 hp = hostent_unpack(nvl, &hent); 246 nvlist_destroy(nvl); 247 return (hp); 248 } 249 250 static struct addrinfo * 251 addrinfo_unpack(const nvlist_t *nvl) 252 { 253 struct addrinfo *ai; 254 const void *addr; 255 size_t addrlen; 256 const char *canonname; 257 258 addr = nvlist_get_binary(nvl, "ai_addr", &addrlen); 259 ai = malloc(sizeof(*ai) + addrlen); 260 if (ai == NULL) 261 return (NULL); 262 ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags"); 263 ai->ai_family = (int)nvlist_get_number(nvl, "ai_family"); 264 ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype"); 265 ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol"); 266 ai->ai_addrlen = (socklen_t)addrlen; 267 canonname = dnvlist_get_string(nvl, "ai_canonname", NULL); 268 if (canonname != NULL) { 269 ai->ai_canonname = strdup(canonname); 270 if (ai->ai_canonname == NULL) { 271 free(ai); 272 return (NULL); 273 } 274 } else { 275 ai->ai_canonname = NULL; 276 } 277 ai->ai_addr = (void *)(ai + 1); 278 bcopy(addr, ai->ai_addr, addrlen); 279 ai->ai_next = NULL; 280 281 return (ai); 282 } 283 284 int 285 cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname, 286 const struct addrinfo *hints, struct addrinfo **res) 287 { 288 struct addrinfo *firstai, *prevai, *curai; 289 unsigned int ii; 290 const nvlist_t *nvlai; 291 char nvlname[64]; 292 nvlist_t *nvl; 293 int error, n; 294 295 nvl = nvlist_create(0); 296 nvlist_add_string(nvl, "cmd", "getaddrinfo"); 297 if (hostname != NULL) 298 nvlist_add_string(nvl, "hostname", hostname); 299 if (servname != NULL) 300 nvlist_add_string(nvl, "servname", servname); 301 if (hints != NULL) { 302 nvlist_add_number(nvl, "hints.ai_flags", 303 (uint64_t)hints->ai_flags); 304 nvlist_add_number(nvl, "hints.ai_family", 305 (uint64_t)hints->ai_family); 306 nvlist_add_number(nvl, "hints.ai_socktype", 307 (uint64_t)hints->ai_socktype); 308 nvlist_add_number(nvl, "hints.ai_protocol", 309 (uint64_t)hints->ai_protocol); 310 } 311 nvl = cap_xfer_nvlist(chan, nvl); 312 if (nvl == NULL) 313 return (EAI_MEMORY); 314 if (nvlist_get_number(nvl, "error") != 0) { 315 error = (int)nvlist_get_number(nvl, "error"); 316 nvlist_destroy(nvl); 317 return (error); 318 } 319 320 nvlai = NULL; 321 firstai = prevai = curai = NULL; 322 for (ii = 0; ; ii++) { 323 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 324 assert(n > 0 && n < (int)sizeof(nvlname)); 325 if (!nvlist_exists_nvlist(nvl, nvlname)) 326 break; 327 nvlai = nvlist_get_nvlist(nvl, nvlname); 328 curai = addrinfo_unpack(nvlai); 329 if (curai == NULL) 330 return (EAI_MEMORY); 331 if (prevai != NULL) 332 prevai->ai_next = curai; 333 else 334 firstai = curai; 335 prevai = curai; 336 } 337 nvlist_destroy(nvl); 338 if (curai == NULL && nvlai != NULL) { 339 if (firstai == NULL) 340 freeaddrinfo(firstai); 341 return (EAI_MEMORY); 342 } 343 344 *res = firstai; 345 return (0); 346 } 347 348 int 349 cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen, 350 char *host, size_t hostlen, char *serv, size_t servlen, int flags) 351 { 352 nvlist_t *nvl; 353 int error; 354 355 nvl = nvlist_create(0); 356 nvlist_add_string(nvl, "cmd", "getnameinfo"); 357 nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen); 358 nvlist_add_number(nvl, "servlen", (uint64_t)servlen); 359 nvlist_add_binary(nvl, "sa", sa, (size_t)salen); 360 nvlist_add_number(nvl, "flags", (uint64_t)flags); 361 nvl = cap_xfer_nvlist(chan, nvl); 362 if (nvl == NULL) 363 return (EAI_MEMORY); 364 if (nvlist_get_number(nvl, "error") != 0) { 365 error = (int)nvlist_get_number(nvl, "error"); 366 nvlist_destroy(nvl); 367 return (error); 368 } 369 370 if (host != NULL && nvlist_exists_string(nvl, "host")) 371 strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1); 372 if (serv != NULL && nvlist_exists_string(nvl, "serv")) 373 strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1); 374 nvlist_destroy(nvl); 375 return (0); 376 } 377 378 cap_net_limit_t * 379 cap_net_limit_init(cap_channel_t *chan, uint64_t mode) 380 { 381 cap_net_limit_t *limit; 382 383 limit = calloc(1, sizeof(*limit)); 384 if (limit != NULL) { 385 limit->cnl_mode = mode; 386 limit->cnl_chan = chan; 387 limit->cnl_addr2name = nvlist_create(0); 388 limit->cnl_name2addr = nvlist_create(0); 389 limit->cnl_connect = nvlist_create(0); 390 limit->cnl_bind = nvlist_create(0); 391 } 392 393 return (limit); 394 } 395 396 static void 397 pack_limit(nvlist_t *lnvl, const char *name, nvlist_t *limit) 398 { 399 400 if (!nvlist_empty(limit)) { 401 nvlist_move_nvlist(lnvl, name, limit); 402 } else { 403 nvlist_destroy(limit); 404 } 405 } 406 407 int 408 cap_net_limit(cap_net_limit_t *limit) 409 { 410 nvlist_t *lnvl; 411 cap_channel_t *chan; 412 413 lnvl = nvlist_create(0); 414 nvlist_add_number(lnvl, "mode", limit->cnl_mode); 415 416 pack_limit(lnvl, LIMIT_NV_ADDR2NAME, limit->cnl_addr2name); 417 pack_limit(lnvl, LIMIT_NV_NAME2ADDR, limit->cnl_name2addr); 418 pack_limit(lnvl, LIMIT_NV_CONNECT, limit->cnl_connect); 419 pack_limit(lnvl, LIMIT_NV_BIND, limit->cnl_bind); 420 421 chan = limit->cnl_chan; 422 free(limit); 423 424 return (cap_limit_set(chan, lnvl)); 425 } 426 427 void 428 cap_net_free(cap_net_limit_t *limit) 429 { 430 431 if (limit == NULL) 432 return; 433 434 nvlist_destroy(limit->cnl_addr2name); 435 nvlist_destroy(limit->cnl_name2addr); 436 nvlist_destroy(limit->cnl_connect); 437 nvlist_destroy(limit->cnl_bind); 438 439 free(limit); 440 } 441 442 static void 443 pack_family(nvlist_t *nvl, int *family, size_t size) 444 { 445 size_t i; 446 447 i = 0; 448 if (!nvlist_exists_number_array(nvl, "family")) { 449 uint64_t val; 450 451 val = family[0]; 452 nvlist_add_number_array(nvl, "family", &val, 1); 453 i += 1; 454 } 455 456 for (; i < size; i++) { 457 nvlist_append_number_array(nvl, "family", family[i]); 458 } 459 } 460 461 static void 462 pack_sockaddr(nvlist_t *res, const struct sockaddr *sa, socklen_t salen) 463 { 464 nvlist_t *nvl; 465 466 if (!nvlist_exists_nvlist(res, "sockaddr")) { 467 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 468 } else { 469 nvl = nvlist_take_nvlist(res, "sockaddr"); 470 } 471 472 nvlist_add_binary(nvl, "", sa, salen); 473 nvlist_move_nvlist(res, "sockaddr", nvl); 474 } 475 476 cap_net_limit_t * 477 cap_net_limit_addr2name_family(cap_net_limit_t *limit, int *family, size_t size) 478 { 479 480 pack_family(limit->cnl_addr2name, family, size); 481 return (limit); 482 } 483 484 cap_net_limit_t * 485 cap_net_limit_name2addr_family(cap_net_limit_t *limit, int *family, size_t size) 486 { 487 488 pack_family(limit->cnl_name2addr, family, size); 489 return (limit); 490 } 491 492 cap_net_limit_t * 493 cap_net_limit_name2addr(cap_net_limit_t *limit, const char *host, 494 const char *serv) 495 { 496 nvlist_t *nvl; 497 498 if (!nvlist_exists_nvlist(limit->cnl_name2addr, "hosts")) { 499 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 500 } else { 501 nvl = nvlist_take_nvlist(limit->cnl_name2addr, "hosts"); 502 } 503 504 nvlist_add_string(nvl, 505 host != NULL ? host : "", 506 serv != NULL ? serv : ""); 507 508 nvlist_move_nvlist(limit->cnl_name2addr, "hosts", nvl); 509 return (limit); 510 } 511 512 cap_net_limit_t * 513 cap_net_limit_addr2name(cap_net_limit_t *limit, const struct sockaddr *sa, 514 socklen_t salen) 515 { 516 517 pack_sockaddr(limit->cnl_addr2name, sa, salen); 518 return (limit); 519 } 520 521 522 cap_net_limit_t * 523 cap_net_limit_connect(cap_net_limit_t *limit, const struct sockaddr *sa, 524 socklen_t salen) 525 { 526 527 pack_sockaddr(limit->cnl_connect, sa, salen); 528 return (limit); 529 } 530 531 cap_net_limit_t * 532 cap_net_limit_bind(cap_net_limit_t *limit, const struct sockaddr *sa, 533 socklen_t salen) 534 { 535 536 pack_sockaddr(limit->cnl_bind, sa, salen); 537 return (limit); 538 } 539 540 /* 541 * Service functions. 542 */ 543 544 static nvlist_t *capdnscache; 545 546 static void 547 net_add_sockaddr_to_cache(struct sockaddr *sa, socklen_t salen, bool deprecated) 548 { 549 void *cookie; 550 551 if (capdnscache == NULL) { 552 capdnscache = nvlist_create(NV_FLAG_NO_UNIQUE); 553 } else { 554 /* Lets keep it clean. Look for dups. */ 555 cookie = NULL; 556 while (nvlist_next(capdnscache, NULL, &cookie) != NULL) { 557 const void *data; 558 size_t size; 559 560 assert(cnvlist_type(cookie) == NV_TYPE_BINARY); 561 562 data = cnvlist_get_binary(cookie, &size); 563 if (salen != size) 564 continue; 565 if (memcmp(data, sa, size) == 0) 566 return; 567 } 568 } 569 570 nvlist_add_binary(capdnscache, deprecated ? "d" : "", sa, salen); 571 } 572 573 static void 574 net_add_hostent_to_cache(const char *address, size_t asize, int family) 575 { 576 577 if (family != AF_INET && family != AF_INET6) 578 return; 579 580 if (family == AF_INET6) { 581 struct sockaddr_in6 connaddr; 582 583 memset(&connaddr, 0, sizeof(connaddr)); 584 connaddr.sin6_family = AF_INET6; 585 memcpy((char *)&connaddr.sin6_addr, address, asize); 586 connaddr.sin6_port = 0; 587 588 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 589 sizeof(connaddr), true); 590 } else { 591 struct sockaddr_in connaddr; 592 593 memset(&connaddr, 0, sizeof(connaddr)); 594 connaddr.sin_family = AF_INET; 595 memcpy((char *)&connaddr.sin_addr.s_addr, address, asize); 596 connaddr.sin_port = 0; 597 598 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 599 sizeof(connaddr), true); 600 } 601 } 602 603 static bool 604 net_allowed_mode(const nvlist_t *limits, uint64_t mode) 605 { 606 607 if (limits == NULL) 608 return (true); 609 610 return ((nvlist_get_number(limits, "mode") & mode) == mode); 611 } 612 613 static bool 614 net_allowed_family(const nvlist_t *limits, int family) 615 { 616 const uint64_t *allowedfamily; 617 size_t i, allsize; 618 619 if (limits == NULL) 620 return (true); 621 622 /* If there are no familes at all, allow any mode. */ 623 if (!nvlist_exists_number_array(limits, "family")) 624 return (true); 625 626 allowedfamily = nvlist_get_number_array(limits, "family", &allsize); 627 for (i = 0; i < allsize; i++) { 628 /* XXX: what with AF_UNSPEC? */ 629 if (allowedfamily[i] == (uint64_t)family) { 630 return (true); 631 } 632 } 633 634 return (false); 635 } 636 637 static bool 638 net_allowed_bsaddr_impl(const nvlist_t *salimits, const void *saddr, 639 size_t saddrsize) 640 { 641 void *cookie; 642 const void *limit; 643 size_t limitsize; 644 645 cookie = NULL; 646 while (nvlist_next(salimits, NULL, &cookie) != NULL) { 647 limit = cnvlist_get_binary(cookie, &limitsize); 648 649 if (limitsize != saddrsize) { 650 continue; 651 } 652 if (memcmp(limit, saddr, limitsize) == 0) { 653 return (true); 654 } 655 656 /* 657 * In case of deprecated version (gethostbyname) we have to 658 * ignore port, because there is no such info in the hostent. 659 * Suporting only AF_INET and AF_INET6. 660 */ 661 if (strcmp(cnvlist_name(cookie), "d") != 0 || 662 (saddrsize != sizeof(struct sockaddr_in) && 663 saddrsize != sizeof(struct sockaddr_in6))) { 664 continue; 665 } 666 if (saddrsize == sizeof(struct sockaddr_in)) { 667 const struct sockaddr_in *saddrptr; 668 struct sockaddr_in sockaddr; 669 670 saddrptr = (const struct sockaddr_in *)saddr; 671 memcpy(&sockaddr, limit, sizeof(sockaddr)); 672 sockaddr.sin_port = saddrptr->sin_port; 673 674 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 675 return (true); 676 } 677 } else if (saddrsize == sizeof(struct sockaddr_in6)) { 678 const struct sockaddr_in6 *saddrptr; 679 struct sockaddr_in6 sockaddr; 680 681 saddrptr = (const struct sockaddr_in6 *)saddr; 682 memcpy(&sockaddr, limit, sizeof(sockaddr)); 683 sockaddr.sin6_port = saddrptr->sin6_port; 684 685 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 686 return (true); 687 } 688 } 689 } 690 691 return (false); 692 } 693 694 static bool 695 net_allowed_bsaddr(const nvlist_t *limits, const void *saddr, size_t saddrsize) 696 { 697 698 if (limits == NULL) 699 return (true); 700 701 if (!nvlist_exists_nvlist(limits, "sockaddr")) 702 return (true); 703 704 return (net_allowed_bsaddr_impl(nvlist_get_nvlist(limits, "sockaddr"), 705 saddr, saddrsize)); 706 } 707 708 static bool 709 net_allowed_hosts(const nvlist_t *limits, const char *name, const char *srvname) 710 { 711 void *cookie; 712 const nvlist_t *hlimits; 713 const char *testname, *testsrvname; 714 715 if (limits == NULL) { 716 return (true); 717 } 718 719 /* If there are no hosts at all, allow any. */ 720 if (!nvlist_exists_nvlist(limits, "hosts")) { 721 return (true); 722 } 723 724 cookie = NULL; 725 testname = (name == NULL ? "" : name); 726 testsrvname = (srvname == NULL ? "" : srvname); 727 hlimits = nvlist_get_nvlist(limits, "hosts"); 728 while (nvlist_next(hlimits, NULL, &cookie) != NULL) { 729 if (strcmp(cnvlist_name(cookie), "") != 0 && 730 strcmp(cnvlist_name(cookie), testname) != 0) { 731 continue; 732 } 733 734 if (strcmp(cnvlist_get_string(cookie), "") != 0 && 735 strcmp(cnvlist_get_string(cookie), testsrvname) != 0) { 736 continue; 737 } 738 739 return (true); 740 } 741 742 return (false); 743 } 744 745 static void 746 hostent_pack(const struct hostent *hp, nvlist_t *nvl, bool addtocache) 747 { 748 unsigned int ii; 749 char nvlname[64]; 750 int n; 751 752 nvlist_add_string(nvl, "name", hp->h_name); 753 nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype); 754 nvlist_add_number(nvl, "length", (uint64_t)hp->h_length); 755 756 if (hp->h_aliases == NULL) { 757 nvlist_add_number(nvl, "naliases", 0); 758 } else { 759 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) { 760 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 761 assert(n > 0 && n < (int)sizeof(nvlname)); 762 nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]); 763 } 764 nvlist_add_number(nvl, "naliases", (uint64_t)ii); 765 } 766 767 if (hp->h_addr_list == NULL) { 768 nvlist_add_number(nvl, "naddrs", 0); 769 } else { 770 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) { 771 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 772 assert(n > 0 && n < (int)sizeof(nvlname)); 773 nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii], 774 (size_t)hp->h_length); 775 if (addtocache) { 776 net_add_hostent_to_cache(hp->h_addr_list[ii], 777 hp->h_length, hp->h_addrtype); 778 } 779 } 780 nvlist_add_number(nvl, "naddrs", (uint64_t)ii); 781 } 782 } 783 784 static int 785 net_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin, 786 nvlist_t *nvlout) 787 { 788 struct hostent *hp; 789 int family; 790 const nvlist_t *funclimit; 791 const char *name; 792 bool dnscache; 793 794 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_NAME2ADDR)) 795 return (ENOTCAPABLE); 796 797 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 798 funclimit = NULL; 799 if (limits != NULL) { 800 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 801 NULL); 802 } 803 804 family = (int)nvlist_get_number(nvlin, "family"); 805 if (!net_allowed_family(funclimit, family)) 806 return (ENOTCAPABLE); 807 808 name = nvlist_get_string(nvlin, "name"); 809 if (!net_allowed_hosts(funclimit, name, "")) 810 return (ENOTCAPABLE); 811 812 hp = gethostbyname2(name, family); 813 if (hp == NULL) 814 return (h_errno); 815 hostent_pack(hp, nvlout, dnscache); 816 return (0); 817 } 818 819 static int 820 net_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin, 821 nvlist_t *nvlout) 822 { 823 struct hostent *hp; 824 const void *addr; 825 size_t addrsize; 826 int family; 827 const nvlist_t *funclimit; 828 829 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_ADDR2NAME)) 830 return (ENOTCAPABLE); 831 832 funclimit = NULL; 833 if (limits != NULL) { 834 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 835 NULL); 836 } 837 838 family = (int)nvlist_get_number(nvlin, "family"); 839 if (!net_allowed_family(funclimit, family)) 840 return (ENOTCAPABLE); 841 842 addr = nvlist_get_binary(nvlin, "addr", &addrsize); 843 if (!net_allowed_bsaddr(funclimit, addr, addrsize)) 844 return (ENOTCAPABLE); 845 846 hp = gethostbyaddr(addr, (socklen_t)addrsize, family); 847 if (hp == NULL) 848 return (h_errno); 849 hostent_pack(hp, nvlout, false); 850 return (0); 851 } 852 853 static int 854 net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 855 { 856 struct sockaddr_storage sast; 857 const void *sabin; 858 char *host, *serv; 859 size_t sabinsize, hostlen, servlen; 860 socklen_t salen; 861 int error, flags; 862 const nvlist_t *funclimit; 863 864 if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) 865 return (ENOTCAPABLE); 866 funclimit = NULL; 867 if (limits != NULL) { 868 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 869 NULL); 870 } 871 872 error = 0; 873 host = serv = NULL; 874 memset(&sast, 0, sizeof(sast)); 875 876 hostlen = (size_t)nvlist_get_number(nvlin, "hostlen"); 877 servlen = (size_t)nvlist_get_number(nvlin, "servlen"); 878 879 if (hostlen > 0) { 880 host = calloc(1, hostlen + 1); 881 if (host == NULL) { 882 error = EAI_MEMORY; 883 goto out; 884 } 885 } 886 if (servlen > 0) { 887 serv = calloc(1, servlen + 1); 888 if (serv == NULL) { 889 error = EAI_MEMORY; 890 goto out; 891 } 892 } 893 894 sabin = nvlist_get_binary(nvlin, "sa", &sabinsize); 895 if (sabinsize > sizeof(sast)) { 896 error = EAI_FAIL; 897 goto out; 898 } 899 if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) 900 return (ENOTCAPABLE); 901 902 memcpy(&sast, sabin, sabinsize); 903 salen = (socklen_t)sabinsize; 904 905 if ((sast.ss_family != AF_INET || 906 salen != sizeof(struct sockaddr_in)) && 907 (sast.ss_family != AF_INET6 || 908 salen != sizeof(struct sockaddr_in6))) { 909 error = EAI_FAIL; 910 goto out; 911 } 912 913 if (!net_allowed_family(funclimit, (int)sast.ss_family)) { 914 error = ENOTCAPABLE; 915 goto out; 916 } 917 918 flags = (int)nvlist_get_number(nvlin, "flags"); 919 920 error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen, 921 serv, servlen, flags); 922 if (error != 0) 923 goto out; 924 925 if (host != NULL) 926 nvlist_move_string(nvlout, "host", host); 927 if (serv != NULL) 928 nvlist_move_string(nvlout, "serv", serv); 929 out: 930 if (error != 0) { 931 free(host); 932 free(serv); 933 } 934 return (error); 935 } 936 937 static nvlist_t * 938 addrinfo_pack(const struct addrinfo *ai) 939 { 940 nvlist_t *nvl; 941 942 nvl = nvlist_create(0); 943 nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags); 944 nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family); 945 nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype); 946 nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol); 947 nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen); 948 if (ai->ai_canonname != NULL) 949 nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname); 950 951 return (nvl); 952 } 953 954 static int 955 net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 956 { 957 struct addrinfo hints, *hintsp, *res, *cur; 958 const char *hostname, *servname; 959 char nvlname[64]; 960 nvlist_t *elem; 961 unsigned int ii; 962 int error, family, n; 963 const nvlist_t *funclimit; 964 bool dnscache; 965 966 if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) 967 return (ENOTCAPABLE); 968 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 969 funclimit = NULL; 970 if (limits != NULL) { 971 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 972 NULL); 973 } 974 975 hostname = dnvlist_get_string(nvlin, "hostname", NULL); 976 servname = dnvlist_get_string(nvlin, "servname", NULL); 977 if (nvlist_exists_number(nvlin, "hints.ai_flags")) { 978 hints.ai_flags = (int)nvlist_get_number(nvlin, 979 "hints.ai_flags"); 980 hints.ai_family = (int)nvlist_get_number(nvlin, 981 "hints.ai_family"); 982 hints.ai_socktype = (int)nvlist_get_number(nvlin, 983 "hints.ai_socktype"); 984 hints.ai_protocol = (int)nvlist_get_number(nvlin, 985 "hints.ai_protocol"); 986 hints.ai_addrlen = 0; 987 hints.ai_addr = NULL; 988 hints.ai_canonname = NULL; 989 hints.ai_next = NULL; 990 hintsp = &hints; 991 family = hints.ai_family; 992 } else { 993 hintsp = NULL; 994 family = AF_UNSPEC; 995 } 996 997 if (!net_allowed_family(funclimit, family)) 998 return (ENOTCAPABLE); 999 if (!net_allowed_hosts(funclimit, hostname, servname)) 1000 return (ENOTCAPABLE); 1001 error = getaddrinfo(hostname, servname, hintsp, &res); 1002 if (error != 0) { 1003 goto out; 1004 } 1005 1006 for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) { 1007 elem = addrinfo_pack(cur); 1008 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 1009 assert(n > 0 && n < (int)sizeof(nvlname)); 1010 nvlist_move_nvlist(nvlout, nvlname, elem); 1011 if (dnscache) { 1012 net_add_sockaddr_to_cache(cur->ai_addr, 1013 cur->ai_addrlen, false); 1014 } 1015 } 1016 1017 freeaddrinfo(res); 1018 error = 0; 1019 out: 1020 return (error); 1021 } 1022 1023 static int 1024 net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1025 { 1026 int socket, serrno; 1027 const void *saddr; 1028 size_t len; 1029 const nvlist_t *funclimit; 1030 1031 if (!net_allowed_mode(limits, CAPNET_BIND)) 1032 return (ENOTCAPABLE); 1033 funclimit = NULL; 1034 if (limits != NULL) 1035 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL); 1036 1037 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1038 1039 if (!net_allowed_bsaddr(funclimit, saddr, len)) 1040 return (ENOTCAPABLE); 1041 1042 socket = nvlist_take_descriptor(nvlin, "s"); 1043 if (bind(socket, saddr, len) < 0) { 1044 serrno = errno; 1045 close(socket); 1046 return (serrno); 1047 } 1048 1049 nvlist_move_descriptor(nvlout, "s", socket); 1050 1051 return (0); 1052 } 1053 1054 static int 1055 net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1056 { 1057 int socket, serrno; 1058 const void *saddr; 1059 const nvlist_t *funclimit; 1060 size_t len; 1061 bool conn, conndns, allowed; 1062 1063 conn = net_allowed_mode(limits, CAPNET_CONNECT); 1064 conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS); 1065 1066 if (!conn && !conndns) 1067 return (ENOTCAPABLE); 1068 1069 funclimit = NULL; 1070 if (limits != NULL) 1071 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL); 1072 1073 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1074 allowed = false; 1075 1076 if (conn && net_allowed_bsaddr(funclimit, saddr, len)) { 1077 allowed = true; 1078 } 1079 if (conndns && capdnscache != NULL && 1080 net_allowed_bsaddr_impl(capdnscache, saddr, len)) { 1081 allowed = true; 1082 } 1083 1084 if (allowed == false) { 1085 return (ENOTCAPABLE); 1086 } 1087 1088 socket = dup(nvlist_get_descriptor(nvlin, "s")); 1089 if (connect(socket, saddr, len) < 0) { 1090 serrno = errno; 1091 close(socket); 1092 return (serrno); 1093 } 1094 1095 nvlist_move_descriptor(nvlout, "s", socket); 1096 1097 return (0); 1098 } 1099 1100 static bool 1101 verify_only_sa_newlimts(const nvlist_t *oldfunclimits, 1102 const nvlist_t *newfunclimit) 1103 { 1104 void *cookie; 1105 1106 cookie = NULL; 1107 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1108 void *sacookie; 1109 1110 if (strcmp(cnvlist_name(cookie), "sockaddr") != 0) 1111 return (false); 1112 1113 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1114 return (false); 1115 1116 sacookie = NULL; 1117 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1118 &sacookie) != NULL) { 1119 const void *sa; 1120 size_t sasize; 1121 1122 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1123 return (false); 1124 1125 sa = cnvlist_get_binary(sacookie, &sasize); 1126 if (!net_allowed_bsaddr(oldfunclimits, sa, sasize)) 1127 return (false); 1128 } 1129 } 1130 1131 return (true); 1132 } 1133 1134 static bool 1135 verify_bind_newlimts(const nvlist_t *oldlimits, 1136 const nvlist_t *newfunclimit) 1137 { 1138 const nvlist_t *oldfunclimits; 1139 1140 oldfunclimits = NULL; 1141 if (oldlimits != NULL) { 1142 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND, 1143 NULL); 1144 } 1145 1146 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1147 } 1148 1149 1150 static bool 1151 verify_connect_newlimits(const nvlist_t *oldlimits, 1152 const nvlist_t *newfunclimit) 1153 { 1154 const nvlist_t *oldfunclimits; 1155 1156 oldfunclimits = NULL; 1157 if (oldlimits != NULL) { 1158 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT, 1159 NULL); 1160 } 1161 1162 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1163 } 1164 1165 static bool 1166 verify_addr2name_newlimits(const nvlist_t *oldlimits, 1167 const nvlist_t *newfunclimit) 1168 { 1169 void *cookie; 1170 const nvlist_t *oldfunclimits; 1171 1172 oldfunclimits = NULL; 1173 if (oldlimits != NULL) { 1174 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1175 LIMIT_NV_ADDR2NAME, NULL); 1176 } 1177 1178 cookie = NULL; 1179 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1180 if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) { 1181 void *sacookie; 1182 1183 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1184 return (false); 1185 1186 sacookie = NULL; 1187 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1188 &sacookie) != NULL) { 1189 const void *sa; 1190 size_t sasize; 1191 1192 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1193 return (false); 1194 1195 sa = cnvlist_get_binary(sacookie, &sasize); 1196 if (!net_allowed_bsaddr(oldfunclimits, sa, 1197 sasize)) { 1198 return (false); 1199 } 1200 } 1201 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1202 size_t i, sfamilies; 1203 const uint64_t *families; 1204 1205 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1206 return (false); 1207 1208 families = cnvlist_get_number_array(cookie, &sfamilies); 1209 for (i = 0; i < sfamilies; i++) { 1210 if (!net_allowed_family(oldfunclimits, 1211 families[i])) { 1212 return (false); 1213 } 1214 } 1215 } else { 1216 return (false); 1217 } 1218 } 1219 1220 return (true); 1221 } 1222 1223 static bool 1224 verify_name2addr_newlimits(const nvlist_t *oldlimits, 1225 const nvlist_t *newfunclimit) 1226 { 1227 void *cookie; 1228 const nvlist_t *oldfunclimits; 1229 1230 oldfunclimits = NULL; 1231 if (oldlimits != NULL) { 1232 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1233 LIMIT_NV_ADDR2NAME, NULL); 1234 } 1235 1236 cookie = NULL; 1237 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1238 if (strcmp(cnvlist_name(cookie), "hosts") == 0) { 1239 void *hostcookie; 1240 1241 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1242 return (false); 1243 1244 hostcookie = NULL; 1245 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1246 &hostcookie) != NULL) { 1247 if (cnvlist_type(hostcookie) != NV_TYPE_STRING) 1248 return (false); 1249 1250 if (!net_allowed_hosts(oldfunclimits, 1251 cnvlist_name(hostcookie), 1252 cnvlist_get_string(hostcookie))) { 1253 return (false); 1254 } 1255 } 1256 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1257 size_t i, sfamilies; 1258 const uint64_t *families; 1259 1260 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1261 return (false); 1262 1263 families = cnvlist_get_number_array(cookie, &sfamilies); 1264 for (i = 0; i < sfamilies; i++) { 1265 if (!net_allowed_family(oldfunclimits, 1266 families[i])) { 1267 return (false); 1268 } 1269 } 1270 } else { 1271 return (false); 1272 } 1273 } 1274 1275 return (true); 1276 } 1277 1278 static int 1279 net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 1280 { 1281 const char *name; 1282 void *cookie; 1283 bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr; 1284 1285 /* 1286 * Modes: 1287 * ADDR2NAME: 1288 * getnameinfo 1289 * DEPRECATED_ADDR2NAME: 1290 * gethostbyaddr 1291 * 1292 * NAME2ADDR: 1293 * getaddrinfo 1294 * DEPRECATED_NAME2ADDR: 1295 * gethostbyname 1296 * 1297 * Limit scheme: 1298 * mode : NV_TYPE_NUMBER 1299 * connect : NV_TYPE_NVLIST 1300 * sockaddr : NV_TYPE_NVLIST 1301 * "" : NV_TYPE_BINARY 1302 * ... : NV_TYPE_BINARY 1303 * bind : NV_TYPE_NVLIST 1304 * sockaddr : NV_TYPE_NVLIST 1305 * "" : NV_TYPE_BINARY 1306 * ... : NV_TYPE_BINARY 1307 * addr2name : NV_TYPE_NVLIST 1308 * family : NV_TYPE_NUMBER_ARRAY 1309 * sockaddr : NV_TYPE_NVLIST 1310 * "" : NV_TYPE_BINARY 1311 * ... : NV_TYPE_BINARY 1312 * name2addr : NV_TYPE_NVLIST 1313 * family : NV_TYPE_NUMBER 1314 * hosts : NV_TYPE_NVLIST 1315 * host : servname : NV_TYPE_STRING 1316 */ 1317 1318 hasmode = false; 1319 hasconnect = false; 1320 hasbind = false; 1321 hasaddr2name = false; 1322 hasname2addr = false; 1323 1324 cookie = NULL; 1325 while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) { 1326 if (strcmp(name, "mode") == 0) { 1327 if (cnvlist_type(cookie) != NV_TYPE_NUMBER) { 1328 return (NO_RECOVERY); 1329 } 1330 if (!net_allowed_mode(oldlimits, 1331 cnvlist_get_number(cookie))) { 1332 return (ENOTCAPABLE); 1333 } 1334 hasmode = true; 1335 continue; 1336 } 1337 1338 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) { 1339 return (NO_RECOVERY); 1340 } 1341 1342 if (strcmp(name, LIMIT_NV_BIND) == 0) { 1343 hasbind = true; 1344 if (!verify_bind_newlimts(oldlimits, 1345 cnvlist_get_nvlist(cookie))) { 1346 return (ENOTCAPABLE); 1347 } 1348 } else if (strcmp(name, LIMIT_NV_CONNECT) == 0) { 1349 hasconnect = true; 1350 if (!verify_connect_newlimits(oldlimits, 1351 cnvlist_get_nvlist(cookie))) { 1352 return (ENOTCAPABLE); 1353 } 1354 } else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) { 1355 hasaddr2name = true; 1356 if (!verify_addr2name_newlimits(oldlimits, 1357 cnvlist_get_nvlist(cookie))) { 1358 return (ENOTCAPABLE); 1359 } 1360 } else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) { 1361 hasname2addr = true; 1362 if (!verify_name2addr_newlimits(oldlimits, 1363 cnvlist_get_nvlist(cookie))) { 1364 return (ENOTCAPABLE); 1365 } 1366 } 1367 } 1368 1369 /* Mode is required. */ 1370 if (!hasmode) 1371 return (ENOTCAPABLE); 1372 1373 /* 1374 * If the new limit doesn't mention mode or family we have to 1375 * check if the current limit does have those. Missing mode or 1376 * family in the limit means that all modes or families are 1377 * allowed. 1378 */ 1379 if (oldlimits == NULL) 1380 return (0); 1381 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_BIND)) 1382 return (ENOTCAPABLE); 1383 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT)) 1384 return (ENOTCAPABLE); 1385 if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME)) 1386 return (ENOTCAPABLE); 1387 if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR)) 1388 return (ENOTCAPABLE); 1389 return (0); 1390 } 1391 1392 static int 1393 net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 1394 nvlist_t *nvlout) 1395 { 1396 1397 if (strcmp(cmd, "bind") == 0) 1398 return (net_bind(limits, nvlin, nvlout)); 1399 else if (strcmp(cmd, "connect") == 0) 1400 return (net_connect(limits, nvlin, nvlout)); 1401 else if (strcmp(cmd, "gethostbyname") == 0) 1402 return (net_gethostbyname(limits, nvlin, nvlout)); 1403 else if (strcmp(cmd, "gethostbyaddr") == 0) 1404 return (net_gethostbyaddr(limits, nvlin, nvlout)); 1405 else if (strcmp(cmd, "getnameinfo") == 0) 1406 return (net_getnameinfo(limits, nvlin, nvlout)); 1407 else if (strcmp(cmd, "getaddrinfo") == 0) 1408 return (net_getaddrinfo(limits, nvlin, nvlout)); 1409 1410 return (EINVAL); 1411 } 1412 1413 CREATE_SERVICE("system.net", net_limit, net_command, 0); 1414