rootwrap.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:7k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * rootwrap.c
  3.  *****************************************************************************
  4.  * Copyright © 2005-2008 Rémi Denis-Courmont
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  19.  *****************************************************************************/
  20. #if HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23. #define _XPG4_2 /* ancilliary data on Solaris */
  24. #include <stdlib.h> /* exit() */
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <sys/stat.h>
  31. #include <sys/socket.h>
  32. #include <sys/uio.h>
  33. #include <sys/resource.h> /* getrlimit() */
  34. #include <sched.h>
  35. #include <errno.h>
  36. #include <netinet/in.h>
  37. #if defined (AF_INET6) && !defined (IPV6_V6ONLY)
  38. # warning Uho, your IPv6 support is broken and has been disabled. Fix your C library.
  39. # undef AF_INET6
  40. #endif
  41. #ifndef AF_LOCAL
  42. # define AF_LOCAL AF_UNIX
  43. #endif
  44. /* Required yet non-standard cmsg functions */
  45. #ifndef CMSG_ALIGN
  46. # define CMSG_ALIGN(len) (((len) + sizeof(intptr_t)-1) & ~(sizeof(intptr_t)-1))
  47. #endif
  48. #ifndef CMSG_SPACE
  49. # define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
  50. #endif
  51. #ifndef CMSG_LEN
  52. # define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
  53. #endif
  54. static inline int is_allowed_port (uint16_t port)
  55. {
  56.     port = ntohs (port);
  57.     return (port == 80) || (port == 443) || (port == 554);
  58. }
  59. static inline int send_err (int fd, int err)
  60. {
  61.     return send (fd, &err, sizeof (err), 0) == sizeof (err) ? 0 : -1;
  62. }
  63. /**
  64.  * Send a file descriptor to another process
  65.  */
  66. static int send_fd (int p, int fd)
  67. {
  68.     struct msghdr hdr;
  69.     struct iovec iov;
  70.     struct cmsghdr *cmsg;
  71.     char buf[CMSG_SPACE (sizeof (fd))];
  72.     int val = 0;
  73.     hdr.msg_name = NULL;
  74.     hdr.msg_namelen = 0;
  75.     hdr.msg_iov = &iov;
  76.     hdr.msg_iovlen = 1;
  77.     hdr.msg_control = buf;
  78.     hdr.msg_controllen = sizeof (buf);
  79.     iov.iov_base = &val;
  80.     iov.iov_len = sizeof (val);
  81.     cmsg = CMSG_FIRSTHDR (&hdr);
  82.     cmsg->cmsg_level = SOL_SOCKET;
  83.     cmsg->cmsg_type = SCM_RIGHTS;
  84.     cmsg->cmsg_len = CMSG_LEN (sizeof (fd));
  85.     memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
  86.     hdr.msg_controllen = cmsg->cmsg_len;
  87.     return sendmsg (p, &hdr, 0) == sizeof (val) ? 0 : -1;
  88. }
  89. /**
  90.  * Background process run as root to open privileged TCP ports.
  91.  */
  92. static void rootprocess (int fd)
  93. {
  94.     union
  95.     {
  96.         struct sockaddr         sa;
  97.         struct sockaddr_storage ss;
  98.         struct sockaddr_in      sin;
  99. #ifdef AF_INET6
  100.         struct sockaddr_in6     sin6;
  101. #endif
  102.     } addr;
  103.     while (recv (fd, &addr.ss, sizeof (addr.ss), 0) == sizeof (addr.ss))
  104.     {
  105.         unsigned len;
  106.         int sock;
  107.         int family;
  108.         switch (addr.sa.sa_family)
  109.         {
  110.             case AF_INET:
  111.                 if (!is_allowed_port (addr.sin.sin_port))
  112.                 {
  113.                     if (send_err (fd, EACCES))
  114.                         return;
  115.                     continue;
  116.                 }
  117.                 len = sizeof (struct sockaddr_in);
  118.                 family = PF_INET;
  119.                 break;
  120. #ifdef AF_INET6
  121.             case AF_INET6:
  122.                 if (!is_allowed_port (addr.sin6.sin6_port))
  123.                 {
  124.                     if (send_err (fd, EACCES))
  125.                         return;
  126.                     continue;
  127.                 }
  128.                 len = sizeof (struct sockaddr_in6);
  129.                 family = PF_INET6;
  130.                 break;
  131. #endif
  132.             default:
  133.                 if (send_err (fd, EAFNOSUPPORT))
  134.                     return;
  135.                 continue;
  136.         }
  137.         sock = socket (family, SOCK_STREAM, IPPROTO_TCP);
  138.         if (sock != -1)
  139.         {
  140.             const int val = 1;
  141.             setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
  142. #ifdef AF_INET6
  143.             if (addr.sa.sa_family == AF_INET6)
  144.                 setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof (val));
  145. #endif
  146.             if (bind (sock, &addr.sa, len) == 0)
  147.             {
  148.                 send_fd (fd, sock);
  149.                 close (sock);
  150.                 continue;
  151.             }
  152.         }
  153.         send_err (fd, errno);
  154.     }
  155. }
  156. /* TODO?
  157.  *  - use libcap if available,
  158.  *  - call chroot
  159.  */
  160. int main (int argc, char *argv[])
  161. {
  162.     /* Support for dynamically opening RTSP, HTTP and HTTP/SSL ports */
  163.     int pair[2];
  164.     if (socketpair (AF_LOCAL, SOCK_STREAM, 0, pair))
  165.         return 1;
  166.     if (pair[0] < 3)
  167.         goto error; /* we want 0, 1 and 2 open */
  168.     pid_t pid = fork ();
  169.     switch (pid)
  170.     {
  171.         case -1:
  172.             goto error;
  173.         case 0:
  174.         {
  175.             int null = open ("/dev/null", O_RDWR);
  176.             if (null != -1)
  177.             {
  178.                 dup2 (null, 0);
  179.                 dup2 (null, 1);
  180.                 dup2 (null, 2);
  181.                 close (null);
  182.             }
  183.             close (pair[0]);
  184.             setsid ();
  185.             rootprocess (pair[1]);
  186.             exit (0);
  187.         }
  188.     }
  189.     close (pair[1]);
  190.     pair[1] = -1;
  191.     char buf[21];
  192.     snprintf (buf, sizeof (buf), "%d", pair[0]);
  193.     setenv ("VLC_ROOTWRAP_SOCK", buf, 1);
  194.     /* Support for real-time priorities */
  195. #ifdef RLIMIT_RTPRIO
  196.     struct rlimit rlim;
  197.     rlim.rlim_max = rlim.rlim_cur = sched_get_priority_min (SCHED_RR) + 24;
  198.     setrlimit (RLIMIT_RTPRIO, &rlim);
  199. #endif
  200.     uid_t uid = getuid ();
  201.     if (uid == 0)
  202.     {
  203.         const char *sudo = getenv ("SUDO_UID");
  204.         if (sudo)
  205.             uid = atoi (sudo);
  206.     }
  207.     if (uid == 0)
  208.     {
  209.         fprintf (stderr, "Cannot determine unprivileged user for VLC!n");
  210.         exit (1);
  211.     }
  212.     setuid (uid);
  213.     if (!setuid (0)) /* sanity check: we cannot get root back */
  214.         exit (1);
  215.     /* Yeah, the user can execute just about anything from here.
  216.      * But we've dropped privileges, so it does not matter. */
  217.     if (strlen (argv[0]) < sizeof ("-wrapper"))
  218.         goto error;
  219.     argv[0][strlen (argv[0]) - strlen ("-wrapper")] = '';
  220.     (void)argc;
  221.     if (execvp (argv[0], argv))
  222.         perror (argv[0]);
  223. error:
  224.     close (pair[0]);
  225.     if (pair[1] != -1)
  226.         close (pair[1]);
  227.     return 1;
  228. }