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 __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 nvlist_destroy(nvl); 331 return (EAI_MEMORY); 332 } 333 if (prevai != NULL) 334 prevai->ai_next = curai; 335 else 336 firstai = curai; 337 prevai = curai; 338 } 339 nvlist_destroy(nvl); 340 if (curai == NULL && nvlai != NULL) { 341 if (firstai == NULL) 342 freeaddrinfo(firstai); 343 return (EAI_MEMORY); 344 } 345 346 *res = firstai; 347 return (0); 348 } 349 350 int 351 cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen, 352 char *host, size_t hostlen, char *serv, size_t servlen, int flags) 353 { 354 nvlist_t *nvl; 355 int error; 356 357 nvl = nvlist_create(0); 358 nvlist_add_string(nvl, "cmd", "getnameinfo"); 359 nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen); 360 nvlist_add_number(nvl, "servlen", (uint64_t)servlen); 361 nvlist_add_binary(nvl, "sa", sa, (size_t)salen); 362 nvlist_add_number(nvl, "flags", (uint64_t)flags); 363 nvl = cap_xfer_nvlist(chan, nvl); 364 if (nvl == NULL) 365 return (EAI_MEMORY); 366 if (nvlist_get_number(nvl, "error") != 0) { 367 error = (int)nvlist_get_number(nvl, "error"); 368 nvlist_destroy(nvl); 369 return (error); 370 } 371 372 if (host != NULL && nvlist_exists_string(nvl, "host")) 373 strlcpy(host, nvlist_get_string(nvl, "host"), hostlen); 374 if (serv != NULL && nvlist_exists_string(nvl, "serv")) 375 strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen); 376 nvlist_destroy(nvl); 377 return (0); 378 } 379 380 cap_net_limit_t * 381 cap_net_limit_init(cap_channel_t *chan, uint64_t mode) 382 { 383 cap_net_limit_t *limit; 384 385 limit = calloc(1, sizeof(*limit)); 386 if (limit != NULL) { 387 limit->cnl_mode = mode; 388 limit->cnl_chan = chan; 389 limit->cnl_addr2name = nvlist_create(0); 390 limit->cnl_name2addr = nvlist_create(0); 391 limit->cnl_connect = nvlist_create(0); 392 limit->cnl_bind = nvlist_create(0); 393 } 394 395 return (limit); 396 } 397 398 static void 399 pack_limit(nvlist_t *lnvl, const char *name, nvlist_t *limit) 400 { 401 402 if (!nvlist_empty(limit)) { 403 nvlist_move_nvlist(lnvl, name, limit); 404 } else { 405 nvlist_destroy(limit); 406 } 407 } 408 409 int 410 cap_net_limit(cap_net_limit_t *limit) 411 { 412 nvlist_t *lnvl; 413 cap_channel_t *chan; 414 415 lnvl = nvlist_create(0); 416 nvlist_add_number(lnvl, "mode", limit->cnl_mode); 417 418 pack_limit(lnvl, LIMIT_NV_ADDR2NAME, limit->cnl_addr2name); 419 pack_limit(lnvl, LIMIT_NV_NAME2ADDR, limit->cnl_name2addr); 420 pack_limit(lnvl, LIMIT_NV_CONNECT, limit->cnl_connect); 421 pack_limit(lnvl, LIMIT_NV_BIND, limit->cnl_bind); 422 423 chan = limit->cnl_chan; 424 free(limit); 425 426 return (cap_limit_set(chan, lnvl)); 427 } 428 429 void 430 cap_net_free(cap_net_limit_t *limit) 431 { 432 433 if (limit == NULL) 434 return; 435 436 nvlist_destroy(limit->cnl_addr2name); 437 nvlist_destroy(limit->cnl_name2addr); 438 nvlist_destroy(limit->cnl_connect); 439 nvlist_destroy(limit->cnl_bind); 440 441 free(limit); 442 } 443 444 static void 445 pack_family(nvlist_t *nvl, int *family, size_t size) 446 { 447 size_t i; 448 449 i = 0; 450 if (!nvlist_exists_number_array(nvl, "family")) { 451 uint64_t val; 452 453 val = family[0]; 454 nvlist_add_number_array(nvl, "family", &val, 1); 455 i += 1; 456 } 457 458 for (; i < size; i++) { 459 nvlist_append_number_array(nvl, "family", family[i]); 460 } 461 } 462 463 static void 464 pack_sockaddr(nvlist_t *res, const struct sockaddr *sa, socklen_t salen) 465 { 466 nvlist_t *nvl; 467 468 if (!nvlist_exists_nvlist(res, "sockaddr")) { 469 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 470 } else { 471 nvl = nvlist_take_nvlist(res, "sockaddr"); 472 } 473 474 nvlist_add_binary(nvl, "", sa, salen); 475 nvlist_move_nvlist(res, "sockaddr", nvl); 476 } 477 478 cap_net_limit_t * 479 cap_net_limit_addr2name_family(cap_net_limit_t *limit, int *family, size_t size) 480 { 481 482 pack_family(limit->cnl_addr2name, family, size); 483 return (limit); 484 } 485 486 cap_net_limit_t * 487 cap_net_limit_name2addr_family(cap_net_limit_t *limit, int *family, size_t size) 488 { 489 490 pack_family(limit->cnl_name2addr, family, size); 491 return (limit); 492 } 493 494 cap_net_limit_t * 495 cap_net_limit_name2addr(cap_net_limit_t *limit, const char *host, 496 const char *serv) 497 { 498 nvlist_t *nvl; 499 500 if (!nvlist_exists_nvlist(limit->cnl_name2addr, "hosts")) { 501 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 502 } else { 503 nvl = nvlist_take_nvlist(limit->cnl_name2addr, "hosts"); 504 } 505 506 nvlist_add_string(nvl, 507 host != NULL ? host : "", 508 serv != NULL ? serv : ""); 509 510 nvlist_move_nvlist(limit->cnl_name2addr, "hosts", nvl); 511 return (limit); 512 } 513 514 cap_net_limit_t * 515 cap_net_limit_addr2name(cap_net_limit_t *limit, const struct sockaddr *sa, 516 socklen_t salen) 517 { 518 519 pack_sockaddr(limit->cnl_addr2name, sa, salen); 520 return (limit); 521 } 522 523 524 cap_net_limit_t * 525 cap_net_limit_connect(cap_net_limit_t *limit, const struct sockaddr *sa, 526 socklen_t salen) 527 { 528 529 pack_sockaddr(limit->cnl_connect, sa, salen); 530 return (limit); 531 } 532 533 cap_net_limit_t * 534 cap_net_limit_bind(cap_net_limit_t *limit, const struct sockaddr *sa, 535 socklen_t salen) 536 { 537 538 pack_sockaddr(limit->cnl_bind, sa, salen); 539 return (limit); 540 } 541 542 /* 543 * Service functions. 544 */ 545 546 static nvlist_t *capdnscache; 547 548 static void 549 net_add_sockaddr_to_cache(struct sockaddr *sa, socklen_t salen, bool deprecated) 550 { 551 void *cookie; 552 553 if (capdnscache == NULL) { 554 capdnscache = nvlist_create(NV_FLAG_NO_UNIQUE); 555 } else { 556 /* Lets keep it clean. Look for dups. */ 557 cookie = NULL; 558 while (nvlist_next(capdnscache, NULL, &cookie) != NULL) { 559 const void *data; 560 size_t size; 561 562 assert(cnvlist_type(cookie) == NV_TYPE_BINARY); 563 564 data = cnvlist_get_binary(cookie, &size); 565 if (salen != size) 566 continue; 567 if (memcmp(data, sa, size) == 0) 568 return; 569 } 570 } 571 572 nvlist_add_binary(capdnscache, deprecated ? "d" : "", sa, salen); 573 } 574 575 static void 576 net_add_hostent_to_cache(const char *address, size_t asize, int family) 577 { 578 579 if (family != AF_INET && family != AF_INET6) 580 return; 581 582 if (family == AF_INET6) { 583 struct sockaddr_in6 connaddr; 584 585 memset(&connaddr, 0, sizeof(connaddr)); 586 connaddr.sin6_family = AF_INET6; 587 memcpy((char *)&connaddr.sin6_addr, address, asize); 588 connaddr.sin6_port = 0; 589 590 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 591 sizeof(connaddr), true); 592 } else { 593 struct sockaddr_in connaddr; 594 595 memset(&connaddr, 0, sizeof(connaddr)); 596 connaddr.sin_family = AF_INET; 597 memcpy((char *)&connaddr.sin_addr.s_addr, address, asize); 598 connaddr.sin_port = 0; 599 600 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 601 sizeof(connaddr), true); 602 } 603 } 604 605 static bool 606 net_allowed_mode(const nvlist_t *limits, uint64_t mode) 607 { 608 609 if (limits == NULL) 610 return (true); 611 612 return ((nvlist_get_number(limits, "mode") & mode) == mode); 613 } 614 615 static bool 616 net_allowed_family(const nvlist_t *limits, int family) 617 { 618 const uint64_t *allowedfamily; 619 size_t i, allsize; 620 621 if (limits == NULL) 622 return (true); 623 624 /* If there are no familes at all, allow any mode. */ 625 if (!nvlist_exists_number_array(limits, "family")) 626 return (true); 627 628 allowedfamily = nvlist_get_number_array(limits, "family", &allsize); 629 for (i = 0; i < allsize; i++) { 630 /* XXX: what with AF_UNSPEC? */ 631 if (allowedfamily[i] == (uint64_t)family) { 632 return (true); 633 } 634 } 635 636 return (false); 637 } 638 639 static bool 640 net_allowed_bsaddr_impl(const nvlist_t *salimits, const void *saddr, 641 size_t saddrsize) 642 { 643 void *cookie; 644 const void *limit; 645 size_t limitsize; 646 647 cookie = NULL; 648 while (nvlist_next(salimits, NULL, &cookie) != NULL) { 649 limit = cnvlist_get_binary(cookie, &limitsize); 650 651 if (limitsize != saddrsize) { 652 continue; 653 } 654 if (memcmp(limit, saddr, limitsize) == 0) { 655 return (true); 656 } 657 658 /* 659 * In case of deprecated version (gethostbyname) we have to 660 * ignore port, because there is no such info in the hostent. 661 * Suporting only AF_INET and AF_INET6. 662 */ 663 if (strcmp(cnvlist_name(cookie), "d") != 0 || 664 (saddrsize != sizeof(struct sockaddr_in) && 665 saddrsize != sizeof(struct sockaddr_in6))) { 666 continue; 667 } 668 if (saddrsize == sizeof(struct sockaddr_in)) { 669 const struct sockaddr_in *saddrptr; 670 struct sockaddr_in sockaddr; 671 672 saddrptr = (const struct sockaddr_in *)saddr; 673 memcpy(&sockaddr, limit, sizeof(sockaddr)); 674 sockaddr.sin_port = saddrptr->sin_port; 675 676 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 677 return (true); 678 } 679 } else if (saddrsize == sizeof(struct sockaddr_in6)) { 680 const struct sockaddr_in6 *saddrptr; 681 struct sockaddr_in6 sockaddr; 682 683 saddrptr = (const struct sockaddr_in6 *)saddr; 684 memcpy(&sockaddr, limit, sizeof(sockaddr)); 685 sockaddr.sin6_port = saddrptr->sin6_port; 686 687 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 688 return (true); 689 } 690 } 691 } 692 693 return (false); 694 } 695 696 static bool 697 net_allowed_bsaddr(const nvlist_t *limits, const void *saddr, size_t saddrsize) 698 { 699 700 if (limits == NULL) 701 return (true); 702 703 if (!nvlist_exists_nvlist(limits, "sockaddr")) 704 return (true); 705 706 return (net_allowed_bsaddr_impl(nvlist_get_nvlist(limits, "sockaddr"), 707 saddr, saddrsize)); 708 } 709 710 static bool 711 net_allowed_hosts(const nvlist_t *limits, const char *name, const char *srvname) 712 { 713 void *cookie; 714 const nvlist_t *hlimits; 715 const char *testname, *testsrvname; 716 717 if (limits == NULL) { 718 return (true); 719 } 720 721 /* If there are no hosts at all, allow any. */ 722 if (!nvlist_exists_nvlist(limits, "hosts")) { 723 return (true); 724 } 725 726 cookie = NULL; 727 testname = (name == NULL ? "" : name); 728 testsrvname = (srvname == NULL ? "" : srvname); 729 hlimits = nvlist_get_nvlist(limits, "hosts"); 730 while (nvlist_next(hlimits, NULL, &cookie) != NULL) { 731 if (strcmp(cnvlist_name(cookie), "") != 0 && 732 strcmp(cnvlist_name(cookie), testname) != 0) { 733 continue; 734 } 735 736 if (strcmp(cnvlist_get_string(cookie), "") != 0 && 737 strcmp(cnvlist_get_string(cookie), testsrvname) != 0) { 738 continue; 739 } 740 741 return (true); 742 } 743 744 return (false); 745 } 746 747 static void 748 hostent_pack(const struct hostent *hp, nvlist_t *nvl, bool addtocache) 749 { 750 unsigned int ii; 751 char nvlname[64]; 752 int n; 753 754 nvlist_add_string(nvl, "name", hp->h_name); 755 nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype); 756 nvlist_add_number(nvl, "length", (uint64_t)hp->h_length); 757 758 if (hp->h_aliases == NULL) { 759 nvlist_add_number(nvl, "naliases", 0); 760 } else { 761 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) { 762 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 763 assert(n > 0 && n < (int)sizeof(nvlname)); 764 nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]); 765 } 766 nvlist_add_number(nvl, "naliases", (uint64_t)ii); 767 } 768 769 if (hp->h_addr_list == NULL) { 770 nvlist_add_number(nvl, "naddrs", 0); 771 } else { 772 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) { 773 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 774 assert(n > 0 && n < (int)sizeof(nvlname)); 775 nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii], 776 (size_t)hp->h_length); 777 if (addtocache) { 778 net_add_hostent_to_cache(hp->h_addr_list[ii], 779 hp->h_length, hp->h_addrtype); 780 } 781 } 782 nvlist_add_number(nvl, "naddrs", (uint64_t)ii); 783 } 784 } 785 786 static int 787 net_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin, 788 nvlist_t *nvlout) 789 { 790 struct hostent *hp; 791 int family; 792 const nvlist_t *funclimit; 793 const char *name; 794 bool dnscache; 795 796 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_NAME2ADDR)) 797 return (ENOTCAPABLE); 798 799 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 800 funclimit = NULL; 801 if (limits != NULL) { 802 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 803 NULL); 804 } 805 806 family = (int)nvlist_get_number(nvlin, "family"); 807 if (!net_allowed_family(funclimit, family)) 808 return (ENOTCAPABLE); 809 810 name = nvlist_get_string(nvlin, "name"); 811 if (!net_allowed_hosts(funclimit, name, "")) 812 return (ENOTCAPABLE); 813 814 hp = gethostbyname2(name, family); 815 if (hp == NULL) 816 return (h_errno); 817 hostent_pack(hp, nvlout, dnscache); 818 return (0); 819 } 820 821 static int 822 net_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin, 823 nvlist_t *nvlout) 824 { 825 struct hostent *hp; 826 const void *addr; 827 size_t addrsize; 828 int family; 829 const nvlist_t *funclimit; 830 831 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_ADDR2NAME)) 832 return (ENOTCAPABLE); 833 834 funclimit = NULL; 835 if (limits != NULL) { 836 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 837 NULL); 838 } 839 840 family = (int)nvlist_get_number(nvlin, "family"); 841 if (!net_allowed_family(funclimit, family)) 842 return (ENOTCAPABLE); 843 844 addr = nvlist_get_binary(nvlin, "addr", &addrsize); 845 if (!net_allowed_bsaddr(funclimit, addr, addrsize)) 846 return (ENOTCAPABLE); 847 848 hp = gethostbyaddr(addr, (socklen_t)addrsize, family); 849 if (hp == NULL) 850 return (h_errno); 851 hostent_pack(hp, nvlout, false); 852 return (0); 853 } 854 855 static int 856 net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 857 { 858 struct sockaddr_storage sast; 859 const void *sabin; 860 char *host, *serv; 861 size_t sabinsize, hostlen, servlen; 862 socklen_t salen; 863 int error, flags; 864 const nvlist_t *funclimit; 865 866 if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) 867 return (ENOTCAPABLE); 868 funclimit = NULL; 869 if (limits != NULL) { 870 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 871 NULL); 872 } 873 874 error = 0; 875 host = serv = NULL; 876 memset(&sast, 0, sizeof(sast)); 877 878 hostlen = (size_t)nvlist_get_number(nvlin, "hostlen"); 879 servlen = (size_t)nvlist_get_number(nvlin, "servlen"); 880 881 if (hostlen > 0) { 882 host = calloc(1, hostlen); 883 if (host == NULL) { 884 error = EAI_MEMORY; 885 goto out; 886 } 887 } 888 if (servlen > 0) { 889 serv = calloc(1, servlen); 890 if (serv == NULL) { 891 error = EAI_MEMORY; 892 goto out; 893 } 894 } 895 896 sabin = nvlist_get_binary(nvlin, "sa", &sabinsize); 897 if (sabinsize > sizeof(sast)) { 898 error = EAI_FAIL; 899 goto out; 900 } 901 if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) { 902 error = ENOTCAPABLE; 903 goto out; 904 } 905 906 memcpy(&sast, sabin, sabinsize); 907 salen = (socklen_t)sabinsize; 908 909 if ((sast.ss_family != AF_INET || 910 salen != sizeof(struct sockaddr_in)) && 911 (sast.ss_family != AF_INET6 || 912 salen != sizeof(struct sockaddr_in6))) { 913 error = EAI_FAIL; 914 goto out; 915 } 916 917 if (!net_allowed_family(funclimit, (int)sast.ss_family)) { 918 error = ENOTCAPABLE; 919 goto out; 920 } 921 922 flags = (int)nvlist_get_number(nvlin, "flags"); 923 924 error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen, 925 serv, servlen, flags); 926 if (error != 0) 927 goto out; 928 929 if (host != NULL) 930 nvlist_move_string(nvlout, "host", host); 931 if (serv != NULL) 932 nvlist_move_string(nvlout, "serv", serv); 933 out: 934 if (error != 0) { 935 free(host); 936 free(serv); 937 } 938 return (error); 939 } 940 941 static nvlist_t * 942 addrinfo_pack(const struct addrinfo *ai) 943 { 944 nvlist_t *nvl; 945 946 nvl = nvlist_create(0); 947 nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags); 948 nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family); 949 nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype); 950 nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol); 951 nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen); 952 if (ai->ai_canonname != NULL) 953 nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname); 954 955 return (nvl); 956 } 957 958 static int 959 net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 960 { 961 struct addrinfo hints, *hintsp, *res, *cur; 962 const char *hostname, *servname; 963 char nvlname[64]; 964 nvlist_t *elem; 965 unsigned int ii; 966 int error, family, n; 967 const nvlist_t *funclimit; 968 bool dnscache; 969 970 if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) 971 return (ENOTCAPABLE); 972 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 973 funclimit = NULL; 974 if (limits != NULL) { 975 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 976 NULL); 977 } 978 979 hostname = dnvlist_get_string(nvlin, "hostname", NULL); 980 servname = dnvlist_get_string(nvlin, "servname", NULL); 981 if (nvlist_exists_number(nvlin, "hints.ai_flags")) { 982 hints.ai_flags = (int)nvlist_get_number(nvlin, 983 "hints.ai_flags"); 984 hints.ai_family = (int)nvlist_get_number(nvlin, 985 "hints.ai_family"); 986 hints.ai_socktype = (int)nvlist_get_number(nvlin, 987 "hints.ai_socktype"); 988 hints.ai_protocol = (int)nvlist_get_number(nvlin, 989 "hints.ai_protocol"); 990 hints.ai_addrlen = 0; 991 hints.ai_addr = NULL; 992 hints.ai_canonname = NULL; 993 hints.ai_next = NULL; 994 hintsp = &hints; 995 family = hints.ai_family; 996 } else { 997 hintsp = NULL; 998 family = AF_UNSPEC; 999 } 1000 1001 if (!net_allowed_family(funclimit, family)) 1002 return (ENOTCAPABLE); 1003 if (!net_allowed_hosts(funclimit, hostname, servname)) 1004 return (ENOTCAPABLE); 1005 error = getaddrinfo(hostname, servname, hintsp, &res); 1006 if (error != 0) { 1007 goto out; 1008 } 1009 1010 for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) { 1011 elem = addrinfo_pack(cur); 1012 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 1013 assert(n > 0 && n < (int)sizeof(nvlname)); 1014 nvlist_move_nvlist(nvlout, nvlname, elem); 1015 if (dnscache) { 1016 net_add_sockaddr_to_cache(cur->ai_addr, 1017 cur->ai_addrlen, false); 1018 } 1019 } 1020 1021 freeaddrinfo(res); 1022 error = 0; 1023 out: 1024 return (error); 1025 } 1026 1027 static int 1028 net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1029 { 1030 int socket, serrno; 1031 const void *saddr; 1032 size_t len; 1033 const nvlist_t *funclimit; 1034 1035 if (!net_allowed_mode(limits, CAPNET_BIND)) 1036 return (ENOTCAPABLE); 1037 funclimit = NULL; 1038 if (limits != NULL) 1039 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL); 1040 1041 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1042 1043 if (!net_allowed_bsaddr(funclimit, saddr, len)) 1044 return (ENOTCAPABLE); 1045 1046 socket = nvlist_take_descriptor(nvlin, "s"); 1047 if (bind(socket, saddr, len) < 0) { 1048 serrno = errno; 1049 close(socket); 1050 return (serrno); 1051 } 1052 1053 nvlist_move_descriptor(nvlout, "s", socket); 1054 1055 return (0); 1056 } 1057 1058 static int 1059 net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1060 { 1061 int socket, serrno; 1062 const void *saddr; 1063 const nvlist_t *funclimit; 1064 size_t len; 1065 bool conn, conndns, allowed; 1066 1067 conn = net_allowed_mode(limits, CAPNET_CONNECT); 1068 conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS); 1069 1070 if (!conn && !conndns) 1071 return (ENOTCAPABLE); 1072 1073 funclimit = NULL; 1074 if (limits != NULL) 1075 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL); 1076 1077 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1078 allowed = false; 1079 1080 if (conn && net_allowed_bsaddr(funclimit, saddr, len)) { 1081 allowed = true; 1082 } 1083 if (conndns && capdnscache != NULL && 1084 net_allowed_bsaddr_impl(capdnscache, saddr, len)) { 1085 allowed = true; 1086 } 1087 1088 if (allowed == false) { 1089 return (ENOTCAPABLE); 1090 } 1091 1092 socket = dup(nvlist_get_descriptor(nvlin, "s")); 1093 if (connect(socket, saddr, len) < 0) { 1094 serrno = errno; 1095 close(socket); 1096 return (serrno); 1097 } 1098 1099 nvlist_move_descriptor(nvlout, "s", socket); 1100 1101 return (0); 1102 } 1103 1104 static bool 1105 verify_only_sa_newlimts(const nvlist_t *oldfunclimits, 1106 const nvlist_t *newfunclimit) 1107 { 1108 void *cookie; 1109 1110 cookie = NULL; 1111 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1112 void *sacookie; 1113 1114 if (strcmp(cnvlist_name(cookie), "sockaddr") != 0) 1115 return (false); 1116 1117 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1118 return (false); 1119 1120 sacookie = NULL; 1121 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1122 &sacookie) != NULL) { 1123 const void *sa; 1124 size_t sasize; 1125 1126 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1127 return (false); 1128 1129 sa = cnvlist_get_binary(sacookie, &sasize); 1130 if (!net_allowed_bsaddr(oldfunclimits, sa, sasize)) 1131 return (false); 1132 } 1133 } 1134 1135 return (true); 1136 } 1137 1138 static bool 1139 verify_bind_newlimts(const nvlist_t *oldlimits, 1140 const nvlist_t *newfunclimit) 1141 { 1142 const nvlist_t *oldfunclimits; 1143 1144 oldfunclimits = NULL; 1145 if (oldlimits != NULL) { 1146 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND, 1147 NULL); 1148 } 1149 1150 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1151 } 1152 1153 1154 static bool 1155 verify_connect_newlimits(const nvlist_t *oldlimits, 1156 const nvlist_t *newfunclimit) 1157 { 1158 const nvlist_t *oldfunclimits; 1159 1160 oldfunclimits = NULL; 1161 if (oldlimits != NULL) { 1162 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT, 1163 NULL); 1164 } 1165 1166 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1167 } 1168 1169 static bool 1170 verify_addr2name_newlimits(const nvlist_t *oldlimits, 1171 const nvlist_t *newfunclimit) 1172 { 1173 void *cookie; 1174 const nvlist_t *oldfunclimits; 1175 1176 oldfunclimits = NULL; 1177 if (oldlimits != NULL) { 1178 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1179 LIMIT_NV_ADDR2NAME, NULL); 1180 } 1181 1182 cookie = NULL; 1183 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1184 if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) { 1185 void *sacookie; 1186 1187 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1188 return (false); 1189 1190 sacookie = NULL; 1191 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1192 &sacookie) != NULL) { 1193 const void *sa; 1194 size_t sasize; 1195 1196 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1197 return (false); 1198 1199 sa = cnvlist_get_binary(sacookie, &sasize); 1200 if (!net_allowed_bsaddr(oldfunclimits, sa, 1201 sasize)) { 1202 return (false); 1203 } 1204 } 1205 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1206 size_t i, sfamilies; 1207 const uint64_t *families; 1208 1209 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1210 return (false); 1211 1212 families = cnvlist_get_number_array(cookie, &sfamilies); 1213 for (i = 0; i < sfamilies; i++) { 1214 if (!net_allowed_family(oldfunclimits, 1215 families[i])) { 1216 return (false); 1217 } 1218 } 1219 } else { 1220 return (false); 1221 } 1222 } 1223 1224 return (true); 1225 } 1226 1227 static bool 1228 verify_name2addr_newlimits(const nvlist_t *oldlimits, 1229 const nvlist_t *newfunclimit) 1230 { 1231 void *cookie; 1232 const nvlist_t *oldfunclimits; 1233 1234 oldfunclimits = NULL; 1235 if (oldlimits != NULL) { 1236 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1237 LIMIT_NV_ADDR2NAME, NULL); 1238 } 1239 1240 cookie = NULL; 1241 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1242 if (strcmp(cnvlist_name(cookie), "hosts") == 0) { 1243 void *hostcookie; 1244 1245 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1246 return (false); 1247 1248 hostcookie = NULL; 1249 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1250 &hostcookie) != NULL) { 1251 if (cnvlist_type(hostcookie) != NV_TYPE_STRING) 1252 return (false); 1253 1254 if (!net_allowed_hosts(oldfunclimits, 1255 cnvlist_name(hostcookie), 1256 cnvlist_get_string(hostcookie))) { 1257 return (false); 1258 } 1259 } 1260 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1261 size_t i, sfamilies; 1262 const uint64_t *families; 1263 1264 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1265 return (false); 1266 1267 families = cnvlist_get_number_array(cookie, &sfamilies); 1268 for (i = 0; i < sfamilies; i++) { 1269 if (!net_allowed_family(oldfunclimits, 1270 families[i])) { 1271 return (false); 1272 } 1273 } 1274 } else { 1275 return (false); 1276 } 1277 } 1278 1279 return (true); 1280 } 1281 1282 static int 1283 net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 1284 { 1285 const char *name; 1286 void *cookie; 1287 bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr; 1288 1289 /* 1290 * Modes: 1291 * ADDR2NAME: 1292 * getnameinfo 1293 * DEPRECATED_ADDR2NAME: 1294 * gethostbyaddr 1295 * 1296 * NAME2ADDR: 1297 * getaddrinfo 1298 * DEPRECATED_NAME2ADDR: 1299 * gethostbyname 1300 * 1301 * Limit scheme: 1302 * mode : NV_TYPE_NUMBER 1303 * connect : NV_TYPE_NVLIST 1304 * sockaddr : NV_TYPE_NVLIST 1305 * "" : NV_TYPE_BINARY 1306 * ... : NV_TYPE_BINARY 1307 * bind : NV_TYPE_NVLIST 1308 * sockaddr : NV_TYPE_NVLIST 1309 * "" : NV_TYPE_BINARY 1310 * ... : NV_TYPE_BINARY 1311 * addr2name : NV_TYPE_NVLIST 1312 * family : NV_TYPE_NUMBER_ARRAY 1313 * sockaddr : NV_TYPE_NVLIST 1314 * "" : NV_TYPE_BINARY 1315 * ... : NV_TYPE_BINARY 1316 * name2addr : NV_TYPE_NVLIST 1317 * family : NV_TYPE_NUMBER 1318 * hosts : NV_TYPE_NVLIST 1319 * host : servname : NV_TYPE_STRING 1320 */ 1321 1322 hasmode = false; 1323 hasconnect = false; 1324 hasbind = false; 1325 hasaddr2name = false; 1326 hasname2addr = false; 1327 1328 cookie = NULL; 1329 while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) { 1330 if (strcmp(name, "mode") == 0) { 1331 if (cnvlist_type(cookie) != NV_TYPE_NUMBER) { 1332 return (NO_RECOVERY); 1333 } 1334 if (!net_allowed_mode(oldlimits, 1335 cnvlist_get_number(cookie))) { 1336 return (ENOTCAPABLE); 1337 } 1338 hasmode = true; 1339 continue; 1340 } 1341 1342 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) { 1343 return (NO_RECOVERY); 1344 } 1345 1346 if (strcmp(name, LIMIT_NV_BIND) == 0) { 1347 hasbind = true; 1348 if (!verify_bind_newlimts(oldlimits, 1349 cnvlist_get_nvlist(cookie))) { 1350 return (ENOTCAPABLE); 1351 } 1352 } else if (strcmp(name, LIMIT_NV_CONNECT) == 0) { 1353 hasconnect = true; 1354 if (!verify_connect_newlimits(oldlimits, 1355 cnvlist_get_nvlist(cookie))) { 1356 return (ENOTCAPABLE); 1357 } 1358 } else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) { 1359 hasaddr2name = true; 1360 if (!verify_addr2name_newlimits(oldlimits, 1361 cnvlist_get_nvlist(cookie))) { 1362 return (ENOTCAPABLE); 1363 } 1364 } else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) { 1365 hasname2addr = true; 1366 if (!verify_name2addr_newlimits(oldlimits, 1367 cnvlist_get_nvlist(cookie))) { 1368 return (ENOTCAPABLE); 1369 } 1370 } 1371 } 1372 1373 /* Mode is required. */ 1374 if (!hasmode) 1375 return (ENOTCAPABLE); 1376 1377 /* 1378 * If the new limit doesn't mention mode or family we have to 1379 * check if the current limit does have those. Missing mode or 1380 * family in the limit means that all modes or families are 1381 * allowed. 1382 */ 1383 if (oldlimits == NULL) 1384 return (0); 1385 if (!hasbind && nvlist_exists(oldlimits, LIMIT_NV_BIND)) 1386 return (ENOTCAPABLE); 1387 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT)) 1388 return (ENOTCAPABLE); 1389 if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME)) 1390 return (ENOTCAPABLE); 1391 if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR)) 1392 return (ENOTCAPABLE); 1393 return (0); 1394 } 1395 1396 static int 1397 net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 1398 nvlist_t *nvlout) 1399 { 1400 1401 if (strcmp(cmd, "bind") == 0) 1402 return (net_bind(limits, nvlin, nvlout)); 1403 else if (strcmp(cmd, "connect") == 0) 1404 return (net_connect(limits, nvlin, nvlout)); 1405 else if (strcmp(cmd, "gethostbyname") == 0) 1406 return (net_gethostbyname(limits, nvlin, nvlout)); 1407 else if (strcmp(cmd, "gethostbyaddr") == 0) 1408 return (net_gethostbyaddr(limits, nvlin, nvlout)); 1409 else if (strcmp(cmd, "getnameinfo") == 0) 1410 return (net_getnameinfo(limits, nvlin, nvlout)); 1411 else if (strcmp(cmd, "getaddrinfo") == 0) 1412 return (net_getaddrinfo(limits, nvlin, nvlout)); 1413 1414 return (EINVAL); 1415 } 1416 1417 CREATE_SERVICE("system.net", net_limit, net_command, 0); 1418