1/* $OpenBSD: privsep.c,v 1.25 2024/01/18 09:58:23 claudio Exp $ */ 2 3/* 4 * Copyright (c) 2010 Yasuoka Masahiko <yasuoka@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18#include <sys/queue.h> 19#include <sys/uio.h> 20#include <sys/socket.h> 21#include <sys/ioctl.h> 22#include <arpa/inet.h> 23#include <net/if.h> 24#include <net/pfkeyv2.h> 25#include <netinet/in.h> 26 27#include <errno.h> 28#include <fcntl.h> 29#include <imsg.h> 30#include <stddef.h> 31#include <stdlib.h> 32#include <string.h> 33#include <unistd.h> 34 35#include "pathnames.h" 36#include "privsep.h" 37 38#include "npppd.h" 39#include "ppp.h" 40 41#ifndef nitems 42#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 43#endif 44 45enum imsg_code { 46 PRIVSEP_OK, 47 PRIVSEP_OPEN, 48 PRIVSEP_SOCKET, 49 PRIVSEP_BIND, 50 PRIVSEP_SENDTO, 51 PRIVSEP_UNLINK, 52 PRIVSEP_GET_USER_INFO, 53 PRIVSEP_GET_IF_ADDR, 54 PRIVSEP_SET_IF_ADDR, 55 PRIVSEP_DEL_IF_ADDR, 56 PRIVSEP_GET_IF_FLAGS, 57 PRIVSEP_SET_IF_FLAGS 58}; 59 60struct PRIVSEP_OPEN_ARG { 61 char path[PATH_MAX]; 62 int flags; 63}; 64 65struct PRIVSEP_SOCKET_ARG { 66 int domain; 67 int type; 68 int protocol; 69}; 70 71struct PRIVSEP_BIND_ARG { 72 struct sockaddr_storage name; 73 socklen_t namelen; 74}; 75 76struct PRIVSEP_SENDTO_ARG { 77 size_t len; 78 int flags; 79 struct sockaddr_storage to; 80 socklen_t tolen; 81 u_char msg[0]; 82}; 83 84struct PRIVSEP_UNLINK_ARG { 85 char path[PATH_MAX]; 86}; 87 88struct PRIVSEP_GET_USER_INFO_ARG { 89 char path[PATH_MAX]; 90 char username[MAX_USERNAME_LENGTH]; 91}; 92 93struct PRIVSEP_GET_IF_ADDR_ARG { 94 char ifname[IFNAMSIZ]; 95}; 96 97struct PRIVSEP_GET_IF_ADDR_RESP { 98 int retval; 99 int rerrno; 100 struct in_addr addr; 101}; 102 103struct PRIVSEP_SET_IF_ADDR_ARG { 104 char ifname[IFNAMSIZ]; 105 struct in_addr addr; 106}; 107 108struct PRIVSEP_DEL_IF_ADDR_ARG { 109 char ifname[IFNAMSIZ]; 110}; 111 112struct PRIVSEP_GET_IF_FLAGS_ARG { 113 char ifname[IFNAMSIZ]; 114 int flags; 115}; 116 117struct PRIVSEP_GET_IF_FLAGS_RESP { 118 int retval; 119 int rerrno; 120 int flags; 121}; 122 123struct PRIVSEP_SET_IF_FLAGS_ARG { 124 char ifname[IFNAMSIZ]; 125 int flags; 126}; 127 128struct PRIVSEP_COMMON_RESP { 129 int retval; 130 int rerrno; 131}; 132 133struct PRIVSEP_GET_USER_INFO_RESP { 134 int retval; 135 int rerrno; 136 char password[MAX_PASSWORD_LENGTH]; 137 struct in_addr framed_ip_address; 138 struct in_addr framed_ip_netmask; 139 char calling_number[NPPPD_PHONE_NUMBER_LEN + 1]; 140}; 141 142static void privsep_priv_main (int); 143static void privsep_priv_dispatch_imsg (struct imsgbuf *); 144int imsg_read_and_get(struct imsgbuf *, struct imsg *); 145static int startswith(const char *, const char *); 146static int privsep_recvfd (void); 147static int privsep_common_resp (void); 148 149static int privsep_npppd_check_open (struct PRIVSEP_OPEN_ARG *); 150static int privsep_npppd_check_socket (struct PRIVSEP_SOCKET_ARG *); 151static int privsep_npppd_check_bind (struct PRIVSEP_BIND_ARG *); 152static int privsep_npppd_check_sendto (struct PRIVSEP_SENDTO_ARG *); 153static int privsep_npppd_check_unlink (struct PRIVSEP_UNLINK_ARG *); 154static int privsep_npppd_check_get_user_info ( 155 struct PRIVSEP_GET_USER_INFO_ARG *); 156static int privsep_npppd_check_get_if_addr ( 157 struct PRIVSEP_GET_IF_ADDR_ARG *); 158static int privsep_npppd_check_set_if_addr ( 159 struct PRIVSEP_SET_IF_ADDR_ARG *); 160static int privsep_npppd_check_del_if_addr ( 161 struct PRIVSEP_DEL_IF_ADDR_ARG *); 162static int privsep_npppd_check_get_if_flags ( 163 struct PRIVSEP_GET_IF_FLAGS_ARG *); 164static int privsep_npppd_check_set_if_flags ( 165 struct PRIVSEP_SET_IF_FLAGS_ARG *); 166 167static int privsep_sock = -1; 168static struct imsgbuf privsep_ibuf; 169static pid_t privsep_pid; 170 171int 172privsep_init(void) 173{ 174 pid_t pid; 175 int pairsock[2]; 176 177 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pairsock) == -1) 178 return (-1); 179 180 if ((pid = fork()) < 0) 181 goto fail; 182 else if (pid == 0) { 183 setsid(); 184 /* privileged process */ 185 setproctitle("[priv]"); 186 close(pairsock[1]); 187 privsep_priv_main(pairsock[0]); 188 _exit(0); 189 /* NOTREACHED */ 190 } 191 close(pairsock[0]); 192 privsep_sock = pairsock[1]; 193 privsep_pid = pid; 194 imsg_init(&privsep_ibuf, privsep_sock); 195 196 return (0); 197 /* NOTREACHED */ 198fail: 199 if (pairsock[0] >= 0) { 200 close(pairsock[0]); 201 close(pairsock[1]); 202 } 203 204 return (-1); 205} 206 207void 208privsep_fini(void) 209{ 210 imsg_clear(&privsep_ibuf); 211 if (privsep_sock >= 0) { 212 close(privsep_sock); 213 privsep_sock = -1; 214 } 215} 216 217pid_t 218privsep_priv_pid(void) 219{ 220 return (privsep_pid); 221} 222 223/*********************************************************************** 224 * Functions for from jail 225 ***********************************************************************/ 226int 227priv_bind(int sock, const struct sockaddr *name, socklen_t namelen) 228{ 229 struct PRIVSEP_BIND_ARG a; 230 231 if (namelen > sizeof(a.name)) { 232 errno = EINVAL; 233 return (-1); 234 } 235 if ((sock = dup(sock)) == -1) 236 return (-1); 237 238 memcpy(&a.name, name, namelen); 239 a.namelen = namelen; 240 241 (void)imsg_compose(&privsep_ibuf, PRIVSEP_BIND, 0, 0, sock, 242 &a, sizeof(a)); 243 imsg_flush(&privsep_ibuf); 244 245 return (privsep_common_resp()); 246} 247 248int 249priv_socket(int domain, int type, int protocol) 250{ 251 struct PRIVSEP_SOCKET_ARG a; 252 253 a.domain = domain; 254 a.type = type; 255 a.protocol = protocol; 256 (void)imsg_compose(&privsep_ibuf, PRIVSEP_SOCKET, 0, 0, -1, 257 &a, sizeof(a)); 258 imsg_flush(&privsep_ibuf); 259 260 return (privsep_recvfd()); 261} 262 263int 264priv_open(const char *path, int flags) 265{ 266 struct PRIVSEP_OPEN_ARG a; 267 268 strlcpy(a.path, path, sizeof(a.path)); 269 a.flags = flags; 270 (void)imsg_compose(&privsep_ibuf, PRIVSEP_OPEN, 0, 0, -1, 271 &a, sizeof(a)); 272 imsg_flush(&privsep_ibuf); 273 274 return (privsep_recvfd()); 275} 276 277FILE * 278priv_fopen(const char *path) 279{ 280 int f; 281 FILE *fp; 282 283 if ((f = priv_open(path, O_RDONLY)) < 0) 284 return (NULL); 285 286 if ((fp = fdopen(f, "r")) == NULL) { 287 close(f); 288 return (NULL); 289 } else 290 return (fp); 291} 292 293int 294priv_sendto(int s, const void *msg, int len, int flags, 295 const struct sockaddr *to, socklen_t tolen) 296{ 297 struct PRIVSEP_SENDTO_ARG a; 298 struct iovec iov[2]; 299 300 if (tolen > sizeof(a.to)) { 301 errno = EINVAL; 302 return (-1); 303 } 304 if ((s = dup(s)) == -1) 305 return (-1); 306 307 a.len = len; 308 a.flags = flags; 309 a.tolen = tolen; 310 if (tolen > 0) 311 memcpy(&a.to, to, tolen); 312 iov[0].iov_base = &a; 313 iov[0].iov_len = offsetof(struct PRIVSEP_SENDTO_ARG, msg); 314 iov[1].iov_base = (void *)msg; 315 iov[1].iov_len = len; 316 317 (void)imsg_composev(&privsep_ibuf, PRIVSEP_SENDTO, 0, 0, s, 318 iov, nitems(iov)); 319 imsg_flush(&privsep_ibuf); 320 321 return (privsep_common_resp()); 322} 323 324int 325priv_send(int s, const void *msg, int len, int flags) 326{ 327 return (priv_sendto(s, msg, len, flags, NULL, 0)); 328} 329 330int 331priv_unlink(const char *path) 332{ 333 struct PRIVSEP_UNLINK_ARG a; 334 335 strlcpy(a.path, path, sizeof(a.path)); 336 (void)imsg_compose(&privsep_ibuf, PRIVSEP_UNLINK, 0, 0, -1, 337 &a, sizeof(a)); 338 imsg_flush(&privsep_ibuf); 339 340 return (privsep_common_resp()); 341} 342 343int 344priv_get_user_info(const char *path, const char *username, 345 npppd_auth_user **puser) 346{ 347 struct imsg imsg; 348 ssize_t n; 349 struct PRIVSEP_GET_USER_INFO_RESP *r; 350 struct PRIVSEP_GET_USER_INFO_ARG a; 351 npppd_auth_user *u; 352 char *cp; 353 int sz; 354 355 strlcpy(a.path, path, sizeof(a.path)); 356 strlcpy(a.username, username, sizeof(a.username)); 357 358 (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_USER_INFO, 0, 0, -1, 359 &a, sizeof(a)); 360 imsg_flush(&privsep_ibuf); 361 362 if ((n = imsg_read_and_get(&privsep_ibuf, &imsg)) == -1) 363 return (-1); 364 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r)) { 365 errno = EACCES; 366 goto on_error; 367 } 368 r = imsg.data; 369 if (r->retval != 0) { 370 errno = r->rerrno; 371 goto on_error; 372 } 373 374 sz = strlen(username) + strlen(r->password) + 375 strlen(r->calling_number) + 3; 376 377 if ((u = malloc(offsetof(npppd_auth_user, space[sz]))) == NULL) 378 goto on_error; 379 380 cp = u->space; 381 382 u->username = cp; 383 n = strlcpy(cp, username, sz); 384 cp += ++n; sz -= n; 385 386 u->password = cp; 387 n = strlcpy(cp, r->password, sz); 388 cp += ++n; sz -= n; 389 390 u->calling_number = cp; 391 n = strlcpy(cp, r->calling_number, sz); 392 cp += ++n; sz -= n; 393 394 u->framed_ip_address = r->framed_ip_address; 395 u->framed_ip_netmask = r->framed_ip_netmask; 396 397 *puser = u; 398 imsg_free(&imsg); 399 400 return (0); 401 402on_error: 403 imsg_free(&imsg); 404 return (-1); 405} 406 407int 408priv_get_if_addr(const char *ifname, struct in_addr *addr) 409{ 410 struct PRIVSEP_GET_IF_ADDR_ARG a; 411 struct PRIVSEP_GET_IF_ADDR_RESP *r; 412 struct imsg imsg; 413 int retval = -1; 414 415 strlcpy(a.ifname, ifname, sizeof(a.ifname)); 416 417 (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_IF_ADDR, 0, 0, -1, 418 &a, sizeof(a)); 419 imsg_flush(&privsep_ibuf); 420 421 if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) 422 return (-1); 423 424 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r)) 425 errno = EACCES; 426 else { 427 r = imsg.data; 428 if (r->retval != -1) 429 *addr = r->addr; 430 else 431 errno = r->rerrno; 432 retval = r->retval; 433 } 434 imsg_free(&imsg); 435 436 return (retval); 437} 438 439int 440priv_delete_if_addr(const char *ifname) 441{ 442 struct PRIVSEP_DEL_IF_ADDR_ARG a; 443 444 strlcpy(a.ifname, ifname, sizeof(a.ifname)); 445 (void)imsg_compose(&privsep_ibuf, PRIVSEP_DEL_IF_ADDR, 0, 0, -1, 446 &a, sizeof(a)); 447 imsg_flush(&privsep_ibuf); 448 449 return (privsep_common_resp()); 450} 451 452int 453priv_set_if_addr(const char *ifname, struct in_addr *addr) 454{ 455 struct PRIVSEP_SET_IF_ADDR_ARG a; 456 457 strlcpy(a.ifname, ifname, sizeof(a.ifname)); 458 a.addr = *addr; 459 (void)imsg_compose(&privsep_ibuf, PRIVSEP_SET_IF_ADDR, 0, 0, -1, 460 &a, sizeof(a)); 461 imsg_flush(&privsep_ibuf); 462 463 return (privsep_common_resp()); 464} 465 466int 467priv_get_if_flags(const char *ifname, int *pflags) 468{ 469 struct PRIVSEP_GET_IF_FLAGS_ARG a; 470 struct PRIVSEP_GET_IF_FLAGS_RESP *r; 471 struct imsg imsg; 472 int retval = -1; 473 474 strlcpy(a.ifname, ifname, sizeof(a.ifname)); 475 a.flags = 0; 476 477 (void)imsg_compose(&privsep_ibuf, PRIVSEP_GET_IF_FLAGS, 0, 0, -1, 478 &a, sizeof(a)); 479 imsg_flush(&privsep_ibuf); 480 481 if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) 482 return (-1); 483 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r)) 484 errno = EACCES; 485 else { 486 r = imsg.data; 487 *pflags = r->flags; 488 if (r->retval != 0) 489 errno = r->rerrno; 490 retval = r->retval; 491 } 492 imsg_free(&imsg); 493 494 return (retval); 495} 496 497int 498priv_set_if_flags(const char *ifname, int flags) 499{ 500 struct PRIVSEP_SET_IF_FLAGS_ARG a; 501 502 strlcpy(a.ifname, ifname, sizeof(a.ifname)); 503 a.flags = flags; 504 505 (void)imsg_compose(&privsep_ibuf, PRIVSEP_SET_IF_FLAGS, 0, 0, -1, 506 &a, sizeof(a)); 507 imsg_flush(&privsep_ibuf); 508 509 return (privsep_common_resp()); 510} 511 512static int 513privsep_recvfd(void) 514{ 515 struct PRIVSEP_COMMON_RESP *r; 516 struct imsg imsg; 517 int retval = -1; 518 519 if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) 520 return (-1); 521 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r)) 522 errno = EACCES; 523 else { 524 r = imsg.data; 525 retval = r->retval; 526 if (r->retval != 0) 527 errno = r->rerrno; 528 else 529 retval = imsg_get_fd(&imsg); 530 } 531 imsg_free(&imsg); 532 533 return (retval); 534} 535 536static int 537privsep_common_resp(void) 538{ 539 struct PRIVSEP_COMMON_RESP *r; 540 struct imsg imsg; 541 int retval = -1; 542 543 if (imsg_read_and_get(&privsep_ibuf, &imsg) == -1) { 544 errno = EACCES; 545 return (-1); 546 } 547 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*r)) 548 errno = EACCES; 549 else { 550 r = imsg.data; 551 if (r->retval != 0) 552 errno = r->rerrno; 553 retval = r->retval; 554 } 555 imsg_free(&imsg); 556 557 return (retval); 558} 559 560/*********************************************************************** 561 * privileged process 562 ***********************************************************************/ 563static void 564privsep_priv_main(int sock) 565{ 566 struct imsgbuf ibuf; 567 568 imsg_init(&ibuf, sock); 569 privsep_priv_dispatch_imsg(&ibuf); 570 imsg_clear(&ibuf); 571 close(sock); 572 573 exit(EXIT_SUCCESS); 574} 575 576static void 577privsep_priv_dispatch_imsg(struct imsgbuf *ibuf) 578{ 579 struct imsg imsg; 580 581 for (;;) { 582 if (imsg_read_and_get(ibuf, &imsg) == -1) 583 return; 584 585 switch (imsg.hdr.type) { 586 case PRIVSEP_OPEN: { 587 int f = -1; 588 struct PRIVSEP_OPEN_ARG *a = imsg.data; 589 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 590 591 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 592 r.rerrno = EINVAL; 593 else if (privsep_npppd_check_open(a)) 594 r.rerrno = EACCES; 595 else { 596 if ((f = open(a->path, a->flags & ~O_CREAT)) 597 == -1) 598 r.rerrno = errno; 599 else 600 r.retval = 0; 601 } 602 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, f, 603 &r, sizeof(r)); 604 imsg_flush(ibuf); 605 } 606 break; 607 case PRIVSEP_SOCKET: { 608 int s = -1; 609 struct PRIVSEP_SOCKET_ARG *a = imsg.data; 610 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 611 612 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 613 r.rerrno = EINVAL; 614 else if (privsep_npppd_check_socket(a)) 615 r.rerrno = EACCES; 616 else { 617 if ((s = socket(a->domain, a->type, 618 a->protocol)) == -1) 619 r.rerrno = errno; 620 else 621 r.retval = 0; 622 } 623 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, s, 624 &r, sizeof(r)); 625 imsg_flush(ibuf); 626 } 627 break; 628 case PRIVSEP_UNLINK: { 629 struct PRIVSEP_UNLINK_ARG *a = imsg.data; 630 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 631 632 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 633 r.rerrno = EINVAL; 634 else if (privsep_npppd_check_unlink(a)) 635 r.rerrno = EACCES; 636 else { 637 if ((r.retval = unlink(a->path)) != 0) 638 r.rerrno = errno; 639 } 640 641 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 642 &r, sizeof(r)); 643 imsg_flush(ibuf); 644 } 645 break; 646 case PRIVSEP_BIND: { 647 struct PRIVSEP_BIND_ARG *a = imsg.data; 648 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 649 int fd; 650 651 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a) || 652 (fd = imsg_get_fd(&imsg)) < 0) 653 r.rerrno = EINVAL; 654 else if (privsep_npppd_check_bind(a)) 655 r.rerrno = EACCES; 656 else { 657 if ((r.retval = bind(fd, 658 (struct sockaddr *)&a->name, a->namelen)) 659 != 0) 660 r.rerrno = errno; 661 close(fd); 662 } 663 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 664 &r, sizeof(r)); 665 imsg_flush(ibuf); 666 } 667 break; 668 case PRIVSEP_GET_USER_INFO: { 669 struct PRIVSEP_GET_USER_INFO_ARG *a = imsg.data; 670 struct PRIVSEP_GET_USER_INFO_RESP r; 671 int retval; 672 char *str, *buf, *db[2] = { NULL, NULL }; 673 674 memset(&r, 0, sizeof(r)); 675 r.retval = -1; 676 r.framed_ip_address.s_addr = INADDR_NAS_SELECT; 677 r.framed_ip_netmask.s_addr = INADDR_NONE; 678 str = buf = NULL; 679 680 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) { 681 r.rerrno = EINVAL; 682 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 683 &r, sizeof(r)); 684 return; 685 } 686 db[0] = a->path; 687 if (privsep_npppd_check_get_user_info(a)) 688 r.rerrno = EACCES; 689 else if ((retval = cgetent(&buf, db, a->username)) 690 == 0) { 691 if ((retval = cgetstr(buf, "password", &str)) 692 >= 0) { 693 if (strlcpy(r.password, str, 694 sizeof(r.password)) >= 695 sizeof(r.password)) 696 goto on_broken_entry; 697 free(str); 698 str = NULL; 699 } 700 if ((retval = cgetstr(buf, "calling-number", 701 &str)) >= 0) { 702 if (strlcpy(r.calling_number, str, 703 sizeof(r.calling_number)) >= 704 sizeof(r.calling_number)) 705 goto on_broken_entry; 706 free(str); 707 str = NULL; 708 } 709 if ((retval = cgetstr(buf, "framed-ip-address", 710 &str)) >= 0) { 711 if (inet_aton(str, 712 &r.framed_ip_address) != 1) 713 goto on_broken_entry; 714 free(str); 715 str = NULL; 716 } 717 718 if ((retval = cgetstr(buf, "framed-ip-netmask", 719 &str)) >= 0) { 720 if (inet_aton(str, 721 &r.framed_ip_netmask) != 1) 722 goto on_broken_entry; 723 free(str); 724 str = NULL; 725 } 726 cgetclose(); 727 free(buf); 728 r.retval = 0; 729 } else if (retval == -1) { 730 buf = NULL; 731on_broken_entry: 732 free(buf); 733 free(str); 734 r.retval = -1; 735 r.rerrno = ENOENT; 736 } else { 737 r.retval = retval; 738 r.rerrno = errno; 739 } 740 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 741 &r, sizeof(r)); 742 imsg_flush(ibuf); 743 } 744 break; 745 case PRIVSEP_SENDTO: { 746 struct PRIVSEP_SENDTO_ARG *a = imsg.data; 747 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 748 int fd; 749 750 if (imsg.hdr.len < IMSG_HEADER_SIZE + sizeof(*a) || 751 imsg.hdr.len < IMSG_HEADER_SIZE + 752 offsetof(struct PRIVSEP_SENDTO_ARG, 753 msg[a->len])) 754 r.rerrno = EMSGSIZE; 755 else if ((fd = imsg_get_fd(&imsg)) < 0) 756 r.rerrno = EINVAL; 757 else if (privsep_npppd_check_sendto(a)) 758 r.rerrno = EACCES; 759 else { 760 if (a->tolen > 0) 761 r.retval = sendto(fd, a->msg, 762 a->len, a->flags, 763 (struct sockaddr *)&a->to, 764 a->tolen); 765 else 766 r.retval = send(fd, a->msg, a->len, 767 a->flags); 768 if (r.retval < 0) 769 r.rerrno = errno; 770 close(fd); 771 } 772 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 773 &r, sizeof(r)); 774 imsg_flush(ibuf); 775 } 776 break; 777 case PRIVSEP_GET_IF_ADDR: { 778 int s; 779 struct ifreq ifr; 780 struct PRIVSEP_GET_IF_ADDR_ARG *a = imsg.data; 781 struct PRIVSEP_GET_IF_ADDR_RESP r; 782 783 memset(&r, 0, sizeof(r)); 784 r.retval = -1; 785 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 786 r.rerrno = EINVAL; 787 else if (privsep_npppd_check_get_if_addr(a)) 788 r.rerrno = EACCES; 789 else { 790 memset(&ifr, 0, sizeof(ifr)); 791 strlcpy(ifr.ifr_name, a->ifname, 792 sizeof(ifr.ifr_name)); 793 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 794 ioctl(s, SIOCGIFADDR, &ifr) != 0) { 795 r.retval = -1; 796 r.rerrno = errno; 797 } else { 798 r.retval = 0; 799 r.addr = ((struct sockaddr_in *) 800 &ifr.ifr_addr)->sin_addr; 801 } 802 if (s >= 0) 803 close(s); 804 } 805 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 806 &r, sizeof(r)); 807 imsg_flush(ibuf); 808 } 809 break; 810 case PRIVSEP_SET_IF_ADDR: { 811 int s; 812 struct ifaliasreq ifra; 813 struct PRIVSEP_SET_IF_ADDR_ARG *a = imsg.data; 814 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 815 struct sockaddr_in *sin4; 816 817 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 818 r.rerrno = EINVAL; 819 else if (privsep_npppd_check_set_if_addr(a)) 820 r.rerrno = EACCES; 821 else { 822 memset(&ifra, 0, sizeof(ifra)); 823 strlcpy(ifra.ifra_name, a->ifname, 824 sizeof(ifra.ifra_name)); 825 826 sin4 = (struct sockaddr_in *)&ifra.ifra_addr; 827 sin4->sin_family = AF_INET; 828 sin4->sin_len = sizeof(struct sockaddr_in); 829 sin4->sin_addr = a->addr; 830 831 sin4 = (struct sockaddr_in *)&ifra.ifra_mask; 832 sin4->sin_family = AF_INET; 833 sin4->sin_len = sizeof(struct sockaddr_in); 834 sin4->sin_addr.s_addr = 0xffffffffUL; 835 836 sin4 = 837 (struct sockaddr_in *)&ifra.ifra_broadaddr; 838 sin4->sin_family = AF_INET; 839 sin4->sin_len = sizeof(struct sockaddr_in); 840 sin4->sin_addr.s_addr = 0; 841 842 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 843 ioctl(s, SIOCAIFADDR, &ifra) != 0) { 844 r.retval = -1; 845 r.rerrno = errno; 846 } else 847 r.retval = 0; 848 if (s >= 0) 849 close(s); 850 } 851 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 852 &r, sizeof(r)); 853 imsg_flush(ibuf); 854 } 855 break; 856 case PRIVSEP_DEL_IF_ADDR: { 857 int s; 858 struct ifreq ifr; 859 struct PRIVSEP_DEL_IF_ADDR_ARG *a = imsg.data; 860 struct PRIVSEP_COMMON_RESP r = { 0, -1 }; 861 862 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 863 r.rerrno = EINVAL; 864 else if (privsep_npppd_check_del_if_addr(a)) 865 r.rerrno = EACCES; 866 else { 867 memset(&ifr, 0, sizeof(ifr)); 868 strlcpy(ifr.ifr_name, a->ifname, 869 sizeof(ifr.ifr_name)); 870 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 871 ioctl(s, SIOCDIFADDR, &ifr) != 0) { 872 r.retval = -1; 873 r.rerrno = errno; 874 } else 875 r.retval = 0; 876 if (s >= 0) 877 close(s); 878 } 879 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 880 &r, sizeof(r)); 881 imsg_flush(ibuf); 882 } 883 break; 884 case PRIVSEP_GET_IF_FLAGS: { 885 int s; 886 struct ifreq ifr; 887 struct PRIVSEP_GET_IF_FLAGS_ARG *a = imsg.data; 888 struct PRIVSEP_GET_IF_FLAGS_RESP r; 889 890 memset(&r, 0, sizeof(r)); 891 r.retval = -1; 892 893 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 894 r.rerrno = EINVAL; 895 else if (privsep_npppd_check_get_if_flags(a)) { 896 r.rerrno = EACCES; 897 } else { 898 memset(&ifr, 0, sizeof(ifr)); 899 strlcpy(ifr.ifr_name, a->ifname, 900 sizeof(ifr.ifr_name)); 901 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 902 ioctl(s, SIOCGIFFLAGS, &ifr) != 0) { 903 r.retval = -1; 904 r.rerrno = errno; 905 } else { 906 r.retval = 0; 907 r.flags = ifr.ifr_flags; 908 } 909 if (s >= 0) 910 close(s); 911 } 912 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 913 &r, sizeof(r)); 914 imsg_flush(ibuf); 915 } 916 break; 917 case PRIVSEP_SET_IF_FLAGS: { 918 int s; 919 struct ifreq ifr; 920 struct PRIVSEP_SET_IF_FLAGS_ARG *a = imsg.data; 921 struct PRIVSEP_COMMON_RESP r = { -1, 0 }; 922 923 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(*a)) 924 r.rerrno = EINVAL; 925 else if (privsep_npppd_check_set_if_flags(a)) 926 r.rerrno = EACCES; 927 else { 928 memset(&ifr, 0, sizeof(ifr)); 929 strlcpy(ifr.ifr_name, a->ifname, 930 sizeof(ifr.ifr_name)); 931 ifr.ifr_flags = a->flags; 932 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 933 ioctl(s, SIOCGIFFLAGS, &ifr) != 0) { 934 r.retval = -1; 935 r.rerrno = errno; 936 } else 937 r.retval = 0; 938 if (s >= 0) 939 close(s); 940 } 941 (void)imsg_compose(ibuf, PRIVSEP_OK, 0, 0, -1, 942 &r, sizeof(r)); 943 imsg_flush(ibuf); 944 } 945 break; 946 } 947 imsg_free(&imsg); 948 } 949} 950 951int 952imsg_read_and_get(struct imsgbuf *ibuf, struct imsg *imsg) 953{ 954 ssize_t n; 955 956 for (;;) { 957 if ((n = imsg_read(ibuf)) <= 0) { 958 if (n == -1 && (errno == EAGAIN || errno == EINTR)) 959 continue; 960 return (-1); 961 } 962 if ((n = imsg_get(ibuf, imsg)) < 0) 963 return (-1); 964 if (n == 0) 965 continue; 966 break; 967 } 968 969 return (0); 970} 971 972static int 973startswith(const char *str, const char *prefix) 974{ 975 return (strncmp(str, prefix, strlen(prefix)) == 0)? 1 : 0; 976} 977 978static int 979privsep_npppd_check_open(struct PRIVSEP_OPEN_ARG *arg) 980{ 981 int i; 982 struct _allow_paths { 983 const char *path; 984 int path_is_prefix; 985 int readonly; 986 } const allow_paths[] = { 987 { NPPPD_DIR "/", 1, 1 }, 988 { "/dev/bpf", 0, 0 }, 989 { "/etc/resolv.conf", 0, 1 }, 990 { "/dev/tun", 1, 0 }, 991 { "/dev/pppac", 1, 0 }, 992 { "/dev/pppx", 1, 0 } 993 }; 994 995 /* O_NONBLOCK is the only 'extra' flag permitted */ 996 if (arg->flags & ~(O_ACCMODE | O_NONBLOCK)) 997 return (1); 998 for (i = 0; i < (int)nitems(allow_paths); i++) { 999 if (allow_paths[i].path_is_prefix) { 1000 if (!startswith(arg->path, allow_paths[i].path)) 1001 continue; 1002 } else if (strcmp(arg->path, allow_paths[i].path) != 0) 1003 continue; 1004 if (allow_paths[i].readonly) { 1005 if ((arg->flags & O_ACCMODE) != O_RDONLY) 1006 continue; 1007 } 1008 return (0); 1009 } 1010 return (1); 1011} 1012 1013static int 1014privsep_npppd_check_socket(struct PRIVSEP_SOCKET_ARG *arg) 1015{ 1016 /* npppd uses routing socket */ 1017 if (arg->domain == PF_ROUTE && arg->type == SOCK_RAW && 1018 arg->protocol == AF_UNSPEC) 1019 return (0); 1020 1021 /* npppd uses raw ip socket for GRE */ 1022 if (arg->domain == AF_INET && arg->type == SOCK_RAW && 1023 arg->protocol == IPPROTO_GRE) 1024 return (0); 1025 1026 /* L2TP uses PF_KEY socket to delete IPsec-SA */ 1027 if (arg->domain == PF_KEY && arg->type == SOCK_RAW && 1028 arg->protocol == PF_KEY_V2) 1029 return (0); 1030 1031 return (1); 1032} 1033 1034static int 1035privsep_npppd_check_bind(struct PRIVSEP_BIND_ARG *arg) 1036{ 1037 return (1); 1038} 1039 1040static int 1041privsep_npppd_check_sendto(struct PRIVSEP_SENDTO_ARG *arg) 1042{ 1043 /* for reply npppdctl's request */ 1044 if (arg->flags == 0 && arg->tolen > 0 && 1045 arg->to.ss_family == AF_UNIX) 1046 return (0); 1047 1048 /* for sending a routing socket message. */ 1049 if (arg->flags == 0 && arg->tolen == 0) 1050 return (0); 1051 1052 return (1); 1053} 1054 1055static int 1056privsep_npppd_check_unlink(struct PRIVSEP_UNLINK_ARG *arg) 1057{ 1058 1059 return (1); 1060} 1061 1062static int 1063privsep_npppd_check_get_user_info(struct PRIVSEP_GET_USER_INFO_ARG *arg) 1064{ 1065 int l; 1066 1067 l = strlen(NPPPD_DIR "/"); 1068 if (strncmp(arg->path, NPPPD_DIR "/", l) == 0) 1069 return (0); 1070 1071 return (1); 1072} 1073 1074static int 1075privsep_npppd_check_ifname(const char *ifname) 1076{ 1077 if (startswith(ifname, "tun") || 1078 startswith(ifname, "pppac") || 1079 startswith(ifname, "pppx")) 1080 return (0); 1081 1082 return (0); 1083} 1084 1085static int 1086privsep_npppd_check_get_if_addr(struct PRIVSEP_GET_IF_ADDR_ARG *arg) 1087{ 1088 return (privsep_npppd_check_ifname(arg->ifname)); 1089} 1090 1091static int 1092privsep_npppd_check_set_if_addr(struct PRIVSEP_SET_IF_ADDR_ARG *arg) 1093{ 1094 return (privsep_npppd_check_ifname(arg->ifname)); 1095} 1096 1097static int 1098privsep_npppd_check_del_if_addr(struct PRIVSEP_DEL_IF_ADDR_ARG *arg) 1099{ 1100 return (privsep_npppd_check_ifname(arg->ifname)); 1101} 1102 1103static int 1104privsep_npppd_check_get_if_flags(struct PRIVSEP_GET_IF_FLAGS_ARG *arg) 1105{ 1106 return (privsep_npppd_check_ifname(arg->ifname)); 1107} 1108 1109static int 1110privsep_npppd_check_set_if_flags(struct PRIVSEP_SET_IF_FLAGS_ARG *arg) 1111{ 1112 return (privsep_npppd_check_ifname(arg->ifname)); 1113} 1114