1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #include <sys/cnv.h> 30 #include <sys/dnv.h> 31 #include <sys/nv.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 35 #include <assert.h> 36 #include <errno.h> 37 #include <netdb.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include <libcasper.h> 43 #include <libcasper_service.h> 44 45 #include "cap_net.h" 46 47 #define CAPNET_MASK (CAPNET_ADDR2NAME | CAPNET_NAME2ADDR \ 48 CAPNET_DEPRECATED_ADDR2NAME | CAPNET_DEPRECATED_NAME2ADDR | \ 49 CAPNET_CONNECT | CAPNET_BIND | CAPNET_CONNECTDNS) 50 51 /* 52 * Defines for the names of the limits. 53 * XXX: we should convert all string constats to this to avoid typos. 54 */ 55 #define LIMIT_NV_BIND "bind" 56 #define LIMIT_NV_CONNECT "connect" 57 #define LIMIT_NV_ADDR2NAME "addr2name" 58 #define LIMIT_NV_NAME2ADDR "name2addr" 59 60 struct cap_net_limit { 61 cap_channel_t *cnl_chan; 62 uint64_t cnl_mode; 63 nvlist_t *cnl_addr2name; 64 nvlist_t *cnl_name2addr; 65 nvlist_t *cnl_connect; 66 nvlist_t *cnl_bind; 67 }; 68 69 static struct hostent hent; 70 71 static void 72 hostent_free(struct hostent *hp) 73 { 74 unsigned int ii; 75 76 free(hp->h_name); 77 hp->h_name = NULL; 78 if (hp->h_aliases != NULL) { 79 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) 80 free(hp->h_aliases[ii]); 81 free(hp->h_aliases); 82 hp->h_aliases = NULL; 83 } 84 if (hp->h_addr_list != NULL) { 85 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) 86 free(hp->h_addr_list[ii]); 87 free(hp->h_addr_list); 88 hp->h_addr_list = NULL; 89 } 90 } 91 92 static struct hostent * 93 hostent_unpack(const nvlist_t *nvl, struct hostent *hp) 94 { 95 unsigned int ii, nitems; 96 char nvlname[64]; 97 int n; 98 99 hostent_free(hp); 100 101 hp->h_name = strdup(nvlist_get_string(nvl, "name")); 102 if (hp->h_name == NULL) 103 goto fail; 104 hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype"); 105 hp->h_length = (int)nvlist_get_number(nvl, "length"); 106 107 nitems = (unsigned int)nvlist_get_number(nvl, "naliases"); 108 hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1); 109 if (hp->h_aliases == NULL) 110 goto fail; 111 for (ii = 0; ii < nitems; ii++) { 112 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 113 assert(n > 0 && n < (int)sizeof(nvlname)); 114 hp->h_aliases[ii] = 115 strdup(nvlist_get_string(nvl, nvlname)); 116 if (hp->h_aliases[ii] == NULL) 117 goto fail; 118 } 119 hp->h_aliases[ii] = NULL; 120 121 nitems = (unsigned int)nvlist_get_number(nvl, "naddrs"); 122 hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1); 123 if (hp->h_addr_list == NULL) 124 goto fail; 125 for (ii = 0; ii < nitems; ii++) { 126 hp->h_addr_list[ii] = malloc(hp->h_length); 127 if (hp->h_addr_list[ii] == NULL) 128 goto fail; 129 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 130 assert(n > 0 && n < (int)sizeof(nvlname)); 131 bcopy(nvlist_get_binary(nvl, nvlname, NULL), 132 hp->h_addr_list[ii], hp->h_length); 133 } 134 hp->h_addr_list[ii] = NULL; 135 136 return (hp); 137 fail: 138 hostent_free(hp); 139 h_errno = NO_RECOVERY; 140 return (NULL); 141 } 142 143 static int 144 request_cb(cap_channel_t *chan, const char *name, int s, 145 const struct sockaddr *saddr, socklen_t len) 146 { 147 nvlist_t *nvl; 148 int serrno; 149 150 nvl = nvlist_create(0); 151 nvlist_add_string(nvl, "cmd", name); 152 nvlist_add_descriptor(nvl, "s", s); 153 nvlist_add_binary(nvl, "saddr", saddr, len); 154 155 nvl = cap_xfer_nvlist(chan, nvl); 156 if (nvl == NULL) 157 return (-1); 158 159 if (nvlist_get_number(nvl, "error") != 0) { 160 serrno = (int)nvlist_get_number(nvl, "error"); 161 nvlist_destroy(nvl); 162 errno = serrno; 163 return (-1); 164 } 165 166 s = dup2(s, nvlist_get_descriptor(nvl, "s")); 167 nvlist_destroy(nvl); 168 169 return (s == -1 ? -1 : 0); 170 } 171 172 int 173 cap_bind(cap_channel_t *chan, int s, const struct sockaddr *addr, 174 socklen_t addrlen) 175 { 176 177 return (request_cb(chan, LIMIT_NV_BIND, s, addr, addrlen)); 178 } 179 180 int 181 cap_connect(cap_channel_t *chan, int s, const struct sockaddr *name, 182 socklen_t namelen) 183 { 184 185 return (request_cb(chan, LIMIT_NV_CONNECT, s, name, namelen)); 186 } 187 188 189 struct hostent * 190 cap_gethostbyname(cap_channel_t *chan, const char *name) 191 { 192 193 return (cap_gethostbyname2(chan, name, AF_INET)); 194 } 195 196 struct hostent * 197 cap_gethostbyname2(cap_channel_t *chan, const char *name, int af) 198 { 199 struct hostent *hp; 200 nvlist_t *nvl; 201 202 nvl = nvlist_create(0); 203 nvlist_add_string(nvl, "cmd", "gethostbyname"); 204 nvlist_add_number(nvl, "family", (uint64_t)af); 205 nvlist_add_string(nvl, "name", name); 206 nvl = cap_xfer_nvlist(chan, nvl); 207 if (nvl == NULL) { 208 h_errno = NO_RECOVERY; 209 return (NULL); 210 } 211 if (nvlist_get_number(nvl, "error") != 0) { 212 h_errno = (int)nvlist_get_number(nvl, "error"); 213 nvlist_destroy(nvl); 214 return (NULL); 215 } 216 217 hp = hostent_unpack(nvl, &hent); 218 nvlist_destroy(nvl); 219 return (hp); 220 } 221 222 struct hostent * 223 cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len, 224 int af) 225 { 226 struct hostent *hp; 227 nvlist_t *nvl; 228 229 nvl = nvlist_create(0); 230 nvlist_add_string(nvl, "cmd", "gethostbyaddr"); 231 nvlist_add_binary(nvl, "addr", addr, (size_t)len); 232 nvlist_add_number(nvl, "family", (uint64_t)af); 233 nvl = cap_xfer_nvlist(chan, nvl); 234 if (nvl == NULL) { 235 h_errno = NO_RECOVERY; 236 return (NULL); 237 } 238 if (nvlist_get_number(nvl, "error") != 0) { 239 h_errno = (int)nvlist_get_number(nvl, "error"); 240 nvlist_destroy(nvl); 241 return (NULL); 242 } 243 hp = hostent_unpack(nvl, &hent); 244 nvlist_destroy(nvl); 245 return (hp); 246 } 247 248 static struct addrinfo * 249 addrinfo_unpack(const nvlist_t *nvl) 250 { 251 struct addrinfo *ai; 252 const void *addr; 253 size_t addrlen; 254 const char *canonname; 255 256 addr = nvlist_get_binary(nvl, "ai_addr", &addrlen); 257 ai = malloc(sizeof(*ai) + addrlen); 258 if (ai == NULL) 259 return (NULL); 260 ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags"); 261 ai->ai_family = (int)nvlist_get_number(nvl, "ai_family"); 262 ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype"); 263 ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol"); 264 ai->ai_addrlen = (socklen_t)addrlen; 265 canonname = dnvlist_get_string(nvl, "ai_canonname", NULL); 266 if (canonname != NULL) { 267 ai->ai_canonname = strdup(canonname); 268 if (ai->ai_canonname == NULL) { 269 free(ai); 270 return (NULL); 271 } 272 } else { 273 ai->ai_canonname = NULL; 274 } 275 ai->ai_addr = (void *)(ai + 1); 276 bcopy(addr, ai->ai_addr, addrlen); 277 ai->ai_next = NULL; 278 279 return (ai); 280 } 281 282 int 283 cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname, 284 const struct addrinfo *hints, struct addrinfo **res) 285 { 286 struct addrinfo *firstai, *prevai, *curai; 287 unsigned int ii; 288 const nvlist_t *nvlai; 289 char nvlname[64]; 290 nvlist_t *nvl; 291 int error, n; 292 293 nvl = nvlist_create(0); 294 nvlist_add_string(nvl, "cmd", "getaddrinfo"); 295 if (hostname != NULL) 296 nvlist_add_string(nvl, "hostname", hostname); 297 if (servname != NULL) 298 nvlist_add_string(nvl, "servname", servname); 299 if (hints != NULL) { 300 nvlist_add_number(nvl, "hints.ai_flags", 301 (uint64_t)hints->ai_flags); 302 nvlist_add_number(nvl, "hints.ai_family", 303 (uint64_t)hints->ai_family); 304 nvlist_add_number(nvl, "hints.ai_socktype", 305 (uint64_t)hints->ai_socktype); 306 nvlist_add_number(nvl, "hints.ai_protocol", 307 (uint64_t)hints->ai_protocol); 308 } 309 nvl = cap_xfer_nvlist(chan, nvl); 310 if (nvl == NULL) 311 return (EAI_MEMORY); 312 if (nvlist_get_number(nvl, "error") != 0) { 313 error = (int)nvlist_get_number(nvl, "error"); 314 nvlist_destroy(nvl); 315 return (error); 316 } 317 318 nvlai = NULL; 319 firstai = prevai = curai = NULL; 320 for (ii = 0; ; ii++) { 321 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 322 assert(n > 0 && n < (int)sizeof(nvlname)); 323 if (!nvlist_exists_nvlist(nvl, nvlname)) 324 break; 325 nvlai = nvlist_get_nvlist(nvl, nvlname); 326 curai = addrinfo_unpack(nvlai); 327 if (curai == NULL) { 328 nvlist_destroy(nvl); 329 return (EAI_MEMORY); 330 } 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); 372 if (serv != NULL && nvlist_exists_string(nvl, "serv")) 373 strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen); 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); 881 if (host == NULL) { 882 error = EAI_MEMORY; 883 goto out; 884 } 885 } 886 if (servlen > 0) { 887 serv = calloc(1, servlen); 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 error = ENOTCAPABLE; 901 goto out; 902 } 903 904 memcpy(&sast, sabin, sabinsize); 905 salen = (socklen_t)sabinsize; 906 907 if ((sast.ss_family != AF_INET || 908 salen != sizeof(struct sockaddr_in)) && 909 (sast.ss_family != AF_INET6 || 910 salen != sizeof(struct sockaddr_in6))) { 911 error = EAI_FAIL; 912 goto out; 913 } 914 915 if (!net_allowed_family(funclimit, (int)sast.ss_family)) { 916 error = ENOTCAPABLE; 917 goto out; 918 } 919 920 flags = (int)nvlist_get_number(nvlin, "flags"); 921 922 error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen, 923 serv, servlen, flags); 924 if (error != 0) 925 goto out; 926 927 if (host != NULL) 928 nvlist_move_string(nvlout, "host", host); 929 if (serv != NULL) 930 nvlist_move_string(nvlout, "serv", serv); 931 out: 932 if (error != 0) { 933 free(host); 934 free(serv); 935 } 936 return (error); 937 } 938 939 static nvlist_t * 940 addrinfo_pack(const struct addrinfo *ai) 941 { 942 nvlist_t *nvl; 943 944 nvl = nvlist_create(0); 945 nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags); 946 nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family); 947 nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype); 948 nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol); 949 nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen); 950 if (ai->ai_canonname != NULL) 951 nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname); 952 953 return (nvl); 954 } 955 956 static int 957 net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 958 { 959 struct addrinfo hints, *hintsp, *res, *cur; 960 const char *hostname, *servname; 961 char nvlname[64]; 962 nvlist_t *elem; 963 unsigned int ii; 964 int error, family, n; 965 const nvlist_t *funclimit; 966 bool dnscache; 967 968 if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) 969 return (ENOTCAPABLE); 970 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 971 funclimit = NULL; 972 if (limits != NULL) { 973 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 974 NULL); 975 } 976 977 hostname = dnvlist_get_string(nvlin, "hostname", NULL); 978 servname = dnvlist_get_string(nvlin, "servname", NULL); 979 if (nvlist_exists_number(nvlin, "hints.ai_flags")) { 980 hints.ai_flags = (int)nvlist_get_number(nvlin, 981 "hints.ai_flags"); 982 hints.ai_family = (int)nvlist_get_number(nvlin, 983 "hints.ai_family"); 984 hints.ai_socktype = (int)nvlist_get_number(nvlin, 985 "hints.ai_socktype"); 986 hints.ai_protocol = (int)nvlist_get_number(nvlin, 987 "hints.ai_protocol"); 988 hints.ai_addrlen = 0; 989 hints.ai_addr = NULL; 990 hints.ai_canonname = NULL; 991 hints.ai_next = NULL; 992 hintsp = &hints; 993 family = hints.ai_family; 994 } else { 995 hintsp = NULL; 996 family = AF_UNSPEC; 997 } 998 999 if (!net_allowed_family(funclimit, family)) 1000 return (ENOTCAPABLE); 1001 if (!net_allowed_hosts(funclimit, hostname, servname)) 1002 return (ENOTCAPABLE); 1003 error = getaddrinfo(hostname, servname, hintsp, &res); 1004 if (error != 0) { 1005 goto out; 1006 } 1007 1008 for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) { 1009 elem = addrinfo_pack(cur); 1010 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 1011 assert(n > 0 && n < (int)sizeof(nvlname)); 1012 nvlist_move_nvlist(nvlout, nvlname, elem); 1013 if (dnscache) { 1014 net_add_sockaddr_to_cache(cur->ai_addr, 1015 cur->ai_addrlen, false); 1016 } 1017 } 1018 1019 freeaddrinfo(res); 1020 error = 0; 1021 out: 1022 return (error); 1023 } 1024 1025 static int 1026 net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1027 { 1028 int socket, serrno; 1029 const void *saddr; 1030 size_t len; 1031 const nvlist_t *funclimit; 1032 1033 if (!net_allowed_mode(limits, CAPNET_BIND)) 1034 return (ENOTCAPABLE); 1035 funclimit = NULL; 1036 if (limits != NULL) 1037 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL); 1038 1039 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1040 1041 if (!net_allowed_bsaddr(funclimit, saddr, len)) 1042 return (ENOTCAPABLE); 1043 1044 socket = nvlist_take_descriptor(nvlin, "s"); 1045 if (bind(socket, saddr, len) < 0) { 1046 serrno = errno; 1047 close(socket); 1048 return (serrno); 1049 } 1050 1051 nvlist_move_descriptor(nvlout, "s", socket); 1052 1053 return (0); 1054 } 1055 1056 static int 1057 net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1058 { 1059 int socket, serrno; 1060 const void *saddr; 1061 const nvlist_t *funclimit; 1062 size_t len; 1063 bool conn, conndns, allowed; 1064 1065 conn = net_allowed_mode(limits, CAPNET_CONNECT); 1066 conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS); 1067 1068 if (!conn && !conndns) 1069 return (ENOTCAPABLE); 1070 1071 funclimit = NULL; 1072 if (limits != NULL) 1073 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL); 1074 1075 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1076 allowed = false; 1077 1078 if (conn && net_allowed_bsaddr(funclimit, saddr, len)) { 1079 allowed = true; 1080 } 1081 if (conndns && capdnscache != NULL && 1082 net_allowed_bsaddr_impl(capdnscache, saddr, len)) { 1083 allowed = true; 1084 } 1085 1086 if (allowed == false) { 1087 return (ENOTCAPABLE); 1088 } 1089 1090 socket = dup(nvlist_get_descriptor(nvlin, "s")); 1091 if (connect(socket, saddr, len) < 0) { 1092 serrno = errno; 1093 close(socket); 1094 return (serrno); 1095 } 1096 1097 nvlist_move_descriptor(nvlout, "s", socket); 1098 1099 return (0); 1100 } 1101 1102 static bool 1103 verify_only_sa_newlimts(const nvlist_t *oldfunclimits, 1104 const nvlist_t *newfunclimit) 1105 { 1106 void *cookie; 1107 1108 cookie = NULL; 1109 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1110 void *sacookie; 1111 1112 if (strcmp(cnvlist_name(cookie), "sockaddr") != 0) 1113 return (false); 1114 1115 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1116 return (false); 1117 1118 sacookie = NULL; 1119 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1120 &sacookie) != NULL) { 1121 const void *sa; 1122 size_t sasize; 1123 1124 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1125 return (false); 1126 1127 sa = cnvlist_get_binary(sacookie, &sasize); 1128 if (!net_allowed_bsaddr(oldfunclimits, sa, sasize)) 1129 return (false); 1130 } 1131 } 1132 1133 return (true); 1134 } 1135 1136 static bool 1137 verify_bind_newlimts(const nvlist_t *oldlimits, 1138 const nvlist_t *newfunclimit) 1139 { 1140 const nvlist_t *oldfunclimits; 1141 1142 oldfunclimits = NULL; 1143 if (oldlimits != NULL) { 1144 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND, 1145 NULL); 1146 } 1147 1148 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1149 } 1150 1151 1152 static bool 1153 verify_connect_newlimits(const nvlist_t *oldlimits, 1154 const nvlist_t *newfunclimit) 1155 { 1156 const nvlist_t *oldfunclimits; 1157 1158 oldfunclimits = NULL; 1159 if (oldlimits != NULL) { 1160 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT, 1161 NULL); 1162 } 1163 1164 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1165 } 1166 1167 static bool 1168 verify_addr2name_newlimits(const nvlist_t *oldlimits, 1169 const nvlist_t *newfunclimit) 1170 { 1171 void *cookie; 1172 const nvlist_t *oldfunclimits; 1173 1174 oldfunclimits = NULL; 1175 if (oldlimits != NULL) { 1176 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1177 LIMIT_NV_ADDR2NAME, NULL); 1178 } 1179 1180 cookie = NULL; 1181 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1182 if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) { 1183 void *sacookie; 1184 1185 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1186 return (false); 1187 1188 sacookie = NULL; 1189 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1190 &sacookie) != NULL) { 1191 const void *sa; 1192 size_t sasize; 1193 1194 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1195 return (false); 1196 1197 sa = cnvlist_get_binary(sacookie, &sasize); 1198 if (!net_allowed_bsaddr(oldfunclimits, sa, 1199 sasize)) { 1200 return (false); 1201 } 1202 } 1203 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1204 size_t i, sfamilies; 1205 const uint64_t *families; 1206 1207 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1208 return (false); 1209 1210 families = cnvlist_get_number_array(cookie, &sfamilies); 1211 for (i = 0; i < sfamilies; i++) { 1212 if (!net_allowed_family(oldfunclimits, 1213 families[i])) { 1214 return (false); 1215 } 1216 } 1217 } else { 1218 return (false); 1219 } 1220 } 1221 1222 return (true); 1223 } 1224 1225 static bool 1226 verify_name2addr_newlimits(const nvlist_t *oldlimits, 1227 const nvlist_t *newfunclimit) 1228 { 1229 void *cookie; 1230 const nvlist_t *oldfunclimits; 1231 1232 oldfunclimits = NULL; 1233 if (oldlimits != NULL) { 1234 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1235 LIMIT_NV_NAME2ADDR, NULL); 1236 } 1237 1238 cookie = NULL; 1239 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1240 if (strcmp(cnvlist_name(cookie), "hosts") == 0) { 1241 void *hostcookie; 1242 1243 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1244 return (false); 1245 1246 hostcookie = NULL; 1247 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1248 &hostcookie) != NULL) { 1249 if (cnvlist_type(hostcookie) != NV_TYPE_STRING) 1250 return (false); 1251 1252 if (!net_allowed_hosts(oldfunclimits, 1253 cnvlist_name(hostcookie), 1254 cnvlist_get_string(hostcookie))) { 1255 return (false); 1256 } 1257 } 1258 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1259 size_t i, sfamilies; 1260 const uint64_t *families; 1261 1262 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1263 return (false); 1264 1265 families = cnvlist_get_number_array(cookie, &sfamilies); 1266 for (i = 0; i < sfamilies; i++) { 1267 if (!net_allowed_family(oldfunclimits, 1268 families[i])) { 1269 return (false); 1270 } 1271 } 1272 } else { 1273 return (false); 1274 } 1275 } 1276 1277 return (true); 1278 } 1279 1280 static int 1281 net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 1282 { 1283 const char *name; 1284 void *cookie; 1285 bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr; 1286 1287 /* 1288 * Modes: 1289 * ADDR2NAME: 1290 * getnameinfo 1291 * DEPRECATED_ADDR2NAME: 1292 * gethostbyaddr 1293 * 1294 * NAME2ADDR: 1295 * getaddrinfo 1296 * DEPRECATED_NAME2ADDR: 1297 * gethostbyname 1298 * 1299 * Limit scheme: 1300 * mode : NV_TYPE_NUMBER 1301 * connect : NV_TYPE_NVLIST 1302 * sockaddr : NV_TYPE_NVLIST 1303 * "" : NV_TYPE_BINARY 1304 * ... : NV_TYPE_BINARY 1305 * bind : NV_TYPE_NVLIST 1306 * sockaddr : NV_TYPE_NVLIST 1307 * "" : NV_TYPE_BINARY 1308 * ... : NV_TYPE_BINARY 1309 * addr2name : NV_TYPE_NVLIST 1310 * family : NV_TYPE_NUMBER_ARRAY 1311 * sockaddr : NV_TYPE_NVLIST 1312 * "" : NV_TYPE_BINARY 1313 * ... : NV_TYPE_BINARY 1314 * name2addr : NV_TYPE_NVLIST 1315 * family : NV_TYPE_NUMBER 1316 * hosts : NV_TYPE_NVLIST 1317 * host : servname : NV_TYPE_STRING 1318 */ 1319 1320 hasmode = false; 1321 hasconnect = false; 1322 hasbind = false; 1323 hasaddr2name = false; 1324 hasname2addr = false; 1325 1326 cookie = NULL; 1327 while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) { 1328 if (strcmp(name, "mode") == 0) { 1329 if (cnvlist_type(cookie) != NV_TYPE_NUMBER) { 1330 return (NO_RECOVERY); 1331 } 1332 if (!net_allowed_mode(oldlimits, 1333 cnvlist_get_number(cookie))) { 1334 return (ENOTCAPABLE); 1335 } 1336 hasmode = true; 1337 continue; 1338 } 1339 1340 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) { 1341 return (NO_RECOVERY); 1342 } 1343 1344 if (strcmp(name, LIMIT_NV_BIND) == 0) { 1345 hasbind = true; 1346 if (!verify_bind_newlimts(oldlimits, 1347 cnvlist_get_nvlist(cookie))) { 1348 return (ENOTCAPABLE); 1349 } 1350 } else if (strcmp(name, LIMIT_NV_CONNECT) == 0) { 1351 hasconnect = true; 1352 if (!verify_connect_newlimits(oldlimits, 1353 cnvlist_get_nvlist(cookie))) { 1354 return (ENOTCAPABLE); 1355 } 1356 } else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) { 1357 hasaddr2name = true; 1358 if (!verify_addr2name_newlimits(oldlimits, 1359 cnvlist_get_nvlist(cookie))) { 1360 return (ENOTCAPABLE); 1361 } 1362 } else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) { 1363 hasname2addr = true; 1364 if (!verify_name2addr_newlimits(oldlimits, 1365 cnvlist_get_nvlist(cookie))) { 1366 return (ENOTCAPABLE); 1367 } 1368 } 1369 } 1370 1371 /* Mode is required. */ 1372 if (!hasmode) 1373 return (ENOTCAPABLE); 1374 1375 /* 1376 * If the new limit doesn't mention mode or family we have to 1377 * check if the current limit does have those. Missing mode or 1378 * family in the limit means that all modes or families are 1379 * allowed. 1380 */ 1381 if (oldlimits == NULL) 1382 return (0); 1383 if (!hasbind && nvlist_exists(oldlimits, LIMIT_NV_BIND)) 1384 return (ENOTCAPABLE); 1385 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT)) 1386 return (ENOTCAPABLE); 1387 if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME)) 1388 return (ENOTCAPABLE); 1389 if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR)) 1390 return (ENOTCAPABLE); 1391 return (0); 1392 } 1393 1394 static int 1395 net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 1396 nvlist_t *nvlout) 1397 { 1398 1399 if (strcmp(cmd, "bind") == 0) 1400 return (net_bind(limits, nvlin, nvlout)); 1401 else if (strcmp(cmd, "connect") == 0) 1402 return (net_connect(limits, nvlin, nvlout)); 1403 else if (strcmp(cmd, "gethostbyname") == 0) 1404 return (net_gethostbyname(limits, nvlin, nvlout)); 1405 else if (strcmp(cmd, "gethostbyaddr") == 0) 1406 return (net_gethostbyaddr(limits, nvlin, nvlout)); 1407 else if (strcmp(cmd, "getnameinfo") == 0) 1408 return (net_getnameinfo(limits, nvlin, nvlout)); 1409 else if (strcmp(cmd, "getaddrinfo") == 0) 1410 return (net_getaddrinfo(limits, nvlin, nvlout)); 1411 1412 return (EINVAL); 1413 } 1414 1415 CREATE_SERVICE("system.net", net_limit, net_command, 0); 1416