Changeset d9799c1965d9d4781f5fd87310cd7052d790eb11

Show
Ignore:
Timestamp:
06/06/08 17:47:56 (3 months ago)
Author:
Rémi Denis-Courmont <rdenis@simphalempin.com>
git-committer:
Rémi Denis-Courmont <rdenis@simphalempin.com> 1212767276 +0300
git-parent:

[793c4fa6eed6c89c4622728c9cf02ac7ebce3d9a]

git-author:
Rémi Denis-Courmont <rdenis@simphalempin.com> 1212767276 +0300
Message:

Bring the root wrapper back

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/Makefile.am

    r793c4fa rd9799c1  
    428428############################################################################### 
    429429 
    430 EXTRA_PROGRAMS = vlc 
     430EXTRA_PROGRAMS = vlc vlc-wrapper 
    431431if BUILD_VLC 
    432432bin_PROGRAMS = vlc 
     433if !HAVE_WIN32 
     434bin_PROGRAMS += vlc-wrapper 
     435endif 
    433436endif 
    434437 
     
    439442vlc_SOURCES = winvlc.c 
    440443endif 
     444vlc_wrapper_SOURCES = network/rootwrap.c 
    441445 
    442446vlc_DEPENDENCIES = $(DATA_win32_rc) libvlc.la 
  • src/network/rootwrap.c

    r487b2b1 rd9799c1  
    22 * rootwrap.c 
    33 ***************************************************************************** 
    4  * Copyright © 2005 Rémi Denis-Courmont 
    5  * $Id$ 
    6  * 
    7  * Author: Rémi Denis-Courmont <rem # videolan.org> 
     4 * Copyright © 2005-2008 Rémi Denis-Courmont 
    85 * 
    96 * This program is free software; you can redistribute it and/or modify 
     
    2623#endif 
    2724 
    28 #if defined (HAVE_GETEUID) && !defined (SYS_BEOS) 
    29 # define ENABLE_ROOTWRAP 1 
    30 #endif 
    31  
    32 #ifdef ENABLE_ROOTWRAP 
    33  
    3425#include <stdlib.h> /* exit() */ 
    3526#include <stdio.h> 
     
    3930#include <unistd.h> 
    4031#include <fcntl.h> 
     32#include <sys/stat.h> 
    4133#include <sys/socket.h> 
    42 #ifdef HAVE_SYS_TIME_H 
    43 #include <sys/time.h> 
    44 #endif 
    4534#include <sys/uio.h> 
    4635#include <sys/resource.h> /* getrlimit() */ 
    47 #include <sys/wait.h> 
    48 #include <sys/un.h> 
    49 #include <pwd.h> /* getpwnam(), getpwuid() */ 
    50 #include <grp.h> /* setgroups() */ 
     36#include <sched.h> 
    5137#include <errno.h> 
    5238#include <netinet/in.h> 
    53 #include <pthread.h> 
    5439 
    5540#if defined (AF_INET6) && !defined (IPV6_V6ONLY) 
     
    6247#endif 
    6348 
    64 /*#ifndef HAVE_CLEARENV 
    65 extern char **environ; 
    66  
    67 static int clearenv (void) 
    68 
    69     environ = NULL; 
    70     return 0; 
    71 
    72 #endif*/ 
     49static inline int is_allowed_port (uint16_t port) 
     50
     51    port = ntohs (port); 
     52    return (port == 80) || (port == 443) || (port == 554); 
     53
     54 
     55 
     56static inline int send_err (int fd, int err) 
     57
     58    return send (fd, &err, sizeof (err), 0) == sizeof (err) ? 0 : -1; 
     59
    7360 
    7461/** 
    75  * Tries to find a real non-root user to use 
    76  */ 
    77 static struct passwd *guess_user (void) 
    78 
    79     const char *name; 
    80     struct passwd *pw; 
    81     uid_t uid; 
    82  
    83     /* Try real UID */ 
    84     uid = getuid (); 
    85     if (uid) 
    86         if ((pw = getpwuid (uid)) != NULL) 
    87             return pw; 
    88  
    89     /* Try sudo */ 
    90     name = getenv ("SUDO_USER"); 
    91     if (name != NULL) 
    92         if ((pw = getpwnam (name)) != NULL) 
    93             return pw; 
    94  
    95     /* Try VLC_USER */ 
    96     name = getenv ("VLC_USER"); 
    97     if (name != NULL) 
    98         if ((pw = getpwnam (name)) != NULL) 
    99             return pw; 
    100  
    101     /* Try vlc */ 
    102     if ((pw = getpwnam ("vlc")) != NULL) 
    103         return pw; 
    104  
    105     return getpwuid (0); 
    106 
    107  
    108  
    109 static int is_allowed_port (uint16_t port) 
    110 
    111     port = ntohs (port); 
    112  
    113     return (port == 80) || (port == 443) || (port == 554); 
    114 
    115  
    116  
    117 static int send_err (int fd, int err) 
    118 
    119     return send (fd, &err, sizeof (err), 0) == sizeof (err) ? 0 : -1; 
    120 
    121  
    122 /** 
    123  * Ugly POSIX(?) code to pass a file descriptor to another process 
     62 * Send a file descriptor to another process 
    12463 */ 
    12564static int send_fd (int p, int fd) 
     
    15998    struct sockaddr_storage ss; 
    16099 
    161     /* TODO: 
    162      *  - use libcap if available, 
    163      *  - call chroot 
    164      */ 
    165100    while (recv (fd, &ss, sizeof (ss), 0) == sizeof (ss)) 
    166101    { 
     
    219154} 
    220155 
    221 static int rootwrap_sock = -1; 
    222 static pid_t rootwrap_pid = -1; 
    223  
    224 static void close_rootwrap (void) 
    225 
    226     close (rootwrap_sock); 
    227     waitpid (rootwrap_pid, NULL, 0); 
    228 
    229  
    230 void rootwrap (void) 
    231 
    232     struct rlimit lim; 
    233     int fd, pair[2]; 
    234     struct passwd *pw; 
    235     uid_t u; 
    236  
    237     u = geteuid (); 
    238     /* Are we running with root privileges? */ 
    239     if (u != 0) 
    240     { 
    241         setuid (u); 
    242         return; 
    243     } 
    244  
    245     /* Make sure 0, 1 and 2 are opened, and only these. */ 
    246     if (getrlimit (RLIMIT_NOFILE, &lim)) 
    247         exit (1); 
    248  
    249     for (fd = 3; ((unsigned)fd) < lim.rlim_cur; fd++) 
    250         close (fd); 
    251  
    252     fd = dup (2); 
    253     if (fd <= 2) 
    254         exit (1); 
    255     close (fd); 
    256  
    257     fputs ("starting VLC root wrapper...", stderr); 
    258  
    259     pw = guess_user (); 
    260     if (pw == NULL) 
    261         return; /* Should we rather print an error and exit ? */ 
    262  
    263     u = pw->pw_uid, 
    264     fprintf (stderr, " using UID %u (%s)\n", (unsigned)u, pw->pw_name); 
    265     if (u == 0) 
    266     { 
    267         fputs ("***************************************\n" 
    268                "* Running VLC as root is discouraged. *\n" 
    269                "***************************************\n" 
    270                "\n" 
    271                " It is potentially dangerous, " 
    272                 "and might not even work properly.\n", stderr); 
    273         return; 
    274     } 
    275  
    276     /* GID */ 
    277     initgroups (pw->pw_name, pw->pw_gid); 
    278     setgid (pw->pw_gid); 
     156/* TODO? 
     157 *  - use libcap if available, 
     158 *  - call chroot 
     159 */ 
     160 
     161int main (int argc, char *argv[]) 
     162
     163    /* Support for dynamically opening RTSP, HTTP and HTTP/SSL ports */ 
     164    int pair[2]; 
    279165 
    280166    if (socketpair (AF_LOCAL, SOCK_STREAM, 0, pair)) 
    281     { 
    282         perror ("socketpair"); 
    283         goto nofork; 
    284     } 
    285  
    286     switch (rootwrap_pid = fork ()
     167        return 1; 
     168    if (pair[0] < 3) 
     169        goto error; /* we want 0, 1 and 2 open */ 
     170 
     171    pid_t pid = fork (); 
     172    switch (pid
    287173    { 
    288174        case -1: 
    289             perror ("fork"); 
     175            goto error; 
     176 
     177        case 0: 
     178        { 
     179            int null = open ("/dev/null", O_RDWR); 
     180            if (null != -1) 
     181            { 
     182                dup2 (null, 0); 
     183                dup2 (null, 1); 
     184                dup2 (null, 2); 
     185                close (null); 
     186            } 
    290187            close (pair[0]); 
    291             close (pair[1]); 
    292             break; 
    293  
    294         case 0: 
    295             close (0); 
    296             close (1); 
    297             close (2); 
    298             close (pair[0]); 
     188            setsid (); 
    299189            rootprocess (pair[1]); 
    300190            exit (0); 
    301  
    302         default: 
    303             close (pair[1]); 
    304             rootwrap_sock = pair[0]; 
    305             break; 
    306     } 
    307  
    308 nofork: 
    309     /* UID */ 
    310     setuid (u); 
    311  
    312     atexit (close_rootwrap); 
    313 } 
    314  
    315  
    316 /** 
    317  * Ugly POSIX(?) code to receive a file descriptor from another process 
    318  */ 
    319 static int recv_fd (int p) 
    320 { 
    321     struct msghdr hdr; 
    322     struct iovec iov; 
    323     struct cmsghdr *cmsg; 
    324     int val, fd; 
    325     char buf[CMSG_SPACE (sizeof (fd))]; 
    326  
    327     hdr.msg_name = NULL; 
    328     hdr.msg_namelen = 0; 
    329     hdr.msg_iov = &iov; 
    330     hdr.msg_iovlen = 1; 
    331     hdr.msg_control = buf; 
    332     hdr.msg_controllen = sizeof (buf); 
    333  
    334     iov.iov_base = &val; 
    335     iov.iov_len = sizeof (val); 
    336  
    337     if (recvmsg (p, &hdr, 0) != sizeof (val)) 
    338         return -1; 
    339  
    340     for (cmsg = CMSG_FIRSTHDR (&hdr); cmsg != NULL; 
    341          cmsg = CMSG_NXTHDR (&hdr, cmsg)) 
    342     { 
    343         if ((cmsg->cmsg_level == SOL_SOCKET) 
    344          && (cmsg->cmsg_type = SCM_RIGHTS) 
    345          && (cmsg->cmsg_len >= CMSG_LEN (sizeof (fd)))) 
    346         { 
    347             memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); 
    348             return fd; 
    349191        } 
    350192    } 
    351193 
    352     return -1; 
    353 
    354  
    355 /** 
    356  * Tries to obtain a bound TCP socket from the root process 
    357  */ 
    358 int rootwrap_bind (int family, int socktype, int protocol, 
    359                    const struct sockaddr *addr, size_t alen) 
    360 
    361     /* can't use libvlc */ 
    362     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
    363  
    364     struct sockaddr_storage ss; 
    365     int fd; 
    366  
    367     if (rootwrap_sock == -1) 
    368     { 
    369         errno = EACCES; 
    370         return -1; 
    371     } 
    372  
    373     switch (family) 
    374     { 
    375         case AF_INET: 
    376             if (alen < sizeof (struct sockaddr_in)) 
    377             { 
    378                 errno = EINVAL; 
    379                 return -1; 
    380             } 
    381             break; 
    382  
    383 #ifdef AF_INET6 
    384         case AF_INET6: 
    385             if (alen < sizeof (struct sockaddr_in6)) 
    386             { 
    387                 errno = EINVAL; 
    388                 return -1; 
    389             } 
    390             break; 
    391 #endif 
    392  
    393         default: 
    394             errno = EAFNOSUPPORT; 
    395             return -1; 
    396     } 
    397  
    398     if (family != addr->sa_family) 
    399     { 
    400         errno = EAFNOSUPPORT; 
    401         return -1; 
    402     } 
    403  
    404     /* Only TCP is implemented at the moment */ 
    405     if ((socktype != SOCK_STREAM) 
    406      || (protocol && (protocol != IPPROTO_TCP))) 
    407     { 
    408         errno = EACCES; 
    409         return -1; 
    410     } 
    411  
    412     memset (&ss, 0, sizeof (ss)); 
    413     memcpy (&ss, addr, alen > sizeof (ss) ? sizeof (ss) : alen); 
    414  
    415     pthread_mutex_lock (&mutex); 
    416     if (send (rootwrap_sock, &ss, sizeof (ss), 0) != sizeof (ss)) 
    417         return -1; 
    418  
    419     fd = recv_fd (rootwrap_sock); 
    420     pthread_mutex_unlock (&mutex); 
    421  
    422     if (fd != -1) 
    423     { 
    424         int val; 
    425  
    426         val = fcntl (fd, F_GETFL, 0); 
    427         fcntl (fd, F_SETFL, ((val != -1) ? val : 0) | O_NONBLOCK); 
    428     } 
    429  
    430     return fd; 
    431 
    432  
    433 #else 
    434 # include <stddef.h> 
    435  
    436 struct sockaddr; 
    437  
    438 void rootwrap (void) 
    439 
    440 
    441  
    442 int rootwrap_bind (int family, int socktype, int protocol, 
    443                    const struct sockaddr *addr, size_t alen) 
    444 
    445     (void)family; 
    446     (void)socktype; 
    447     (void)protocol; 
    448     (void)addr; 
    449     (void)alen; 
    450     return -1; 
    451 
    452  
    453 #endif /* ENABLE_ROOTWRAP */ 
     194    close (pair[1]); 
     195    pair[1] = -1; 
     196 
     197    char buf[21]; 
     198    snprintf (buf, sizeof (buf), "%d", pair[0]); 
     199    setenv ("VLC_ROOTWRAP_SOCK", buf, 1); 
     200 
     201    /* Support for real-time priorities */ 
     202#ifdef RLIMIT_RTPRIO 
     203    struct rlimit rlim; 
     204    rlim.rlim_max = rlim.rlim_cur = sched_get_priority_min (SCHED_RR) + 24; 
     205    setrlimit (RLIMIT_RTPRIO, &rlim); 
     206#endif 
     207 
     208    setuid (getuid ()); 
     209 
     210    if (!setuid (0)) /* sanity check: we cannot get root back */ 
     211        exit (1); 
     212 
     213    /* Yeah, the user can force to execute just about anything from here. 
     214     * But we've dropped privileges, so it does not matter. */ 
     215    if (strlen (argv[0]) < sizeof ("-wrapper")) 
     216        goto error; 
     217    argv[0][strlen (argv[0]) - strlen ("-wrapper")] = '\0'; 
     218 
     219    (void)argc; 
     220    if (execvp (argv[0], argv)) 
     221        perror (argv[0]); 
     222 
     223error: 
     224    close (pair[0]); 
     225    if (pair[1] != -1) 
     226        close (pair[1]); 
     227    return 1; 
     228