6 changed files with 580 additions and 4 deletions
@ -0,0 +1,41 @@ |
|||
# Building vlc
|
|||
#
|
|||
bin_PROGRAMS = vlc |
|||
EXTRA_PROGRAMS = vlc-wrapper |
|||
|
|||
if !HAVE_WIN32 |
|||
bin_PROGRAMS += vlc-wrapper |
|||
endif |
|||
|
|||
EXTRA_vlc_SOURCES = vlc.c winvlc.c |
|||
if !HAVE_WIN32 |
|||
vlc_SOURCES = vlc.c |
|||
else |
|||
vlc_SOURCES = winvlc.c |
|||
endif |
|||
vlc_wrapper_SOURCES = rootwrap.c |
|||
|
|||
vlc_DEPENDENCIES = $(DATA_win32_rc) ../src/libvlc.la |
|||
|
|||
vlc_CFLAGS = `$(VLC_CONFIG) --cflags vlc` |
|||
vlc_LDFLAGS = `$(VLC_CONFIG) --ldflags vlc` |
|||
# vlc needs libvlccore for locale conversion
|
|||
vlc_LDADD = ../src/libvlc.la ../src/libvlccore.la $(LTLIBINTL) \
|
|||
`$(VLC_CONFIG) -libs vlc` |
|||
|
|||
#vlc$(EXEEXT): $(vlc_OBJECTS) $(vlc_DEPENDENCIES)
|
|||
# $(LINK) $(vlc_OBJECTS) $(vlc_LDADD) $(vlc_LDFLAGS)
|
|||
|
|||
DATA_win32_rc = vlc_win32_rc.$(OBJEXT) |
|||
DATA_win32_rc_lib = libvlc_win32_rc.$(OBJEXT) |
|||
EXTRA_DATA = $(DATA_win32_rc) $(DATA_win32_rc_lib) |
|||
if HAVE_WIN32 |
|||
vlc_LDADD += $(DATA_win32_rc) |
|||
noinst_DATA = $(DATA_win32_rc) $(DATA_win32_rc_lib) |
|||
endif |
|||
|
|||
vlc_win32_rc.$(OBJEXT): $(top_builddir)/share/vlc_win32_rc.rc |
|||
$(WINDRES) --include-dir $(top_srcdir)/share -i $< -o $@ |
|||
|
|||
libvlc_win32_rc.$(OBJEXT): $(top_builddir)/share/libvlc_win32_rc.rc |
|||
$(WINDRES) --include-dir $(top_srcdir)/share -i $< -o $@ |
|||
@ -0,0 +1,240 @@ |
|||
/*****************************************************************************
|
|||
* rootwrap.c |
|||
***************************************************************************** |
|||
* Copyright © 2005-2008 Rémi Denis-Courmont |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#if HAVE_CONFIG_H |
|||
# include <config.h> |
|||
#endif |
|||
|
|||
#include <stdlib.h> /* exit() */ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
#include <sys/types.h> |
|||
#include <unistd.h> |
|||
#include <fcntl.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/uio.h> |
|||
#include <sys/resource.h> /* getrlimit() */ |
|||
#include <sched.h> |
|||
#include <errno.h> |
|||
#include <netinet/in.h> |
|||
|
|||
#if defined (AF_INET6) && !defined (IPV6_V6ONLY) |
|||
# warning Uho, your IPv6 support is broken and has been disabled. Fix your C library. |
|||
# undef AF_INET6 |
|||
#endif |
|||
|
|||
#ifndef AF_LOCAL |
|||
# define AF_LOCAL AF_UNIX |
|||
#endif |
|||
|
|||
static inline int is_allowed_port (uint16_t port) |
|||
{ |
|||
port = ntohs (port); |
|||
return (port == 80) || (port == 443) || (port == 554); |
|||
} |
|||
|
|||
|
|||
static inline int send_err (int fd, int err) |
|||
{ |
|||
return send (fd, &err, sizeof (err), 0) == sizeof (err) ? 0 : -1; |
|||
} |
|||
|
|||
/**
|
|||
* Send a file descriptor to another process |
|||
*/ |
|||
static int send_fd (int p, int fd) |
|||
{ |
|||
struct msghdr hdr; |
|||
struct iovec iov; |
|||
struct cmsghdr *cmsg; |
|||
char buf[CMSG_SPACE (sizeof (fd))]; |
|||
int val = 0; |
|||
|
|||
hdr.msg_name = NULL; |
|||
hdr.msg_namelen = 0; |
|||
hdr.msg_iov = &iov; |
|||
hdr.msg_iovlen = 1; |
|||
hdr.msg_control = buf; |
|||
hdr.msg_controllen = sizeof (buf); |
|||
|
|||
iov.iov_base = &val; |
|||
iov.iov_len = sizeof (val); |
|||
|
|||
cmsg = CMSG_FIRSTHDR (&hdr); |
|||
cmsg->cmsg_level = SOL_SOCKET; |
|||
cmsg->cmsg_type = SCM_RIGHTS; |
|||
cmsg->cmsg_len = CMSG_LEN (sizeof (fd)); |
|||
memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); |
|||
hdr.msg_controllen = cmsg->cmsg_len; |
|||
|
|||
return sendmsg (p, &hdr, 0) == sizeof (val) ? 0 : -1; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
* Background process run as root to open privileged TCP ports. |
|||
*/ |
|||
static void rootprocess (int fd) |
|||
{ |
|||
struct sockaddr_storage ss; |
|||
|
|||
while (recv (fd, &ss, sizeof (ss), 0) == sizeof (ss)) |
|||
{ |
|||
unsigned len; |
|||
int sock; |
|||
|
|||
switch (ss.ss_family) |
|||
{ |
|||
case AF_INET: |
|||
if (!is_allowed_port (((struct sockaddr_in *)&ss)->sin_port)) |
|||
{ |
|||
if (send_err (fd, EACCES)) |
|||
return; |
|||
continue; |
|||
} |
|||
len = sizeof (struct sockaddr_in); |
|||
break; |
|||
|
|||
#ifdef AF_INET6 |
|||
case AF_INET6: |
|||
if (!is_allowed_port (((struct sockaddr_in6 *)&ss)->sin6_port)) |
|||
{ |
|||
if (send_err (fd, EACCES)) |
|||
return; |
|||
continue; |
|||
} |
|||
len = sizeof (struct sockaddr_in6); |
|||
break; |
|||
#endif |
|||
|
|||
default: |
|||
if (send_err (fd, EAFNOSUPPORT)) |
|||
return; |
|||
continue; |
|||
} |
|||
|
|||
sock = socket (ss.ss_family, SOCK_STREAM, IPPROTO_TCP); |
|||
if (sock != -1) |
|||
{ |
|||
const int val = 1; |
|||
|
|||
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)); |
|||
#ifdef AF_INET6 |
|||
if (ss.ss_family == AF_INET6) |
|||
setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof (val)); |
|||
#endif |
|||
if (bind (sock, (struct sockaddr *)&ss, len) == 0) |
|||
{ |
|||
send_fd (fd, sock); |
|||
close (sock); |
|||
continue; |
|||
} |
|||
} |
|||
send_err (fd, errno); |
|||
} |
|||
} |
|||
|
|||
/* TODO?
|
|||
* - use libcap if available, |
|||
* - call chroot |
|||
*/ |
|||
|
|||
int main (int argc, char *argv[]) |
|||
{ |
|||
/* Support for dynamically opening RTSP, HTTP and HTTP/SSL ports */ |
|||
int pair[2]; |
|||
|
|||
if (socketpair (AF_LOCAL, SOCK_STREAM, 0, pair)) |
|||
return 1; |
|||
if (pair[0] < 3) |
|||
goto error; /* we want 0, 1 and 2 open */ |
|||
|
|||
pid_t pid = fork (); |
|||
switch (pid) |
|||
{ |
|||
case -1: |
|||
goto error; |
|||
|
|||
case 0: |
|||
{ |
|||
int null = open ("/dev/null", O_RDWR); |
|||
if (null != -1) |
|||
{ |
|||
dup2 (null, 0); |
|||
dup2 (null, 1); |
|||
dup2 (null, 2); |
|||
close (null); |
|||
} |
|||
close (pair[0]); |
|||
setsid (); |
|||
rootprocess (pair[1]); |
|||
exit (0); |
|||
} |
|||
} |
|||
|
|||
close (pair[1]); |
|||
pair[1] = -1; |
|||
|
|||
char buf[21]; |
|||
snprintf (buf, sizeof (buf), "%d", pair[0]); |
|||
setenv ("VLC_ROOTWRAP_SOCK", buf, 1); |
|||
|
|||
/* Support for real-time priorities */ |
|||
#ifdef RLIMIT_RTPRIO |
|||
struct rlimit rlim; |
|||
rlim.rlim_max = rlim.rlim_cur = sched_get_priority_min (SCHED_RR) + 24; |
|||
setrlimit (RLIMIT_RTPRIO, &rlim); |
|||
#endif |
|||
|
|||
uid_t uid = getuid (); |
|||
if (uid == 0) |
|||
{ |
|||
const char *sudo = getenv ("SUDO_UID"); |
|||
if (sudo) |
|||
uid = atoi (sudo); |
|||
} |
|||
if (uid == 0) |
|||
{ |
|||
fprintf (stderr, "Cannot determine unprivileged user for VLC!\n"); |
|||
exit (1); |
|||
} |
|||
setuid (uid); |
|||
|
|||
if (!setuid (0)) /* sanity check: we cannot get root back */ |
|||
exit (1); |
|||
|
|||
/* Yeah, the user can execute just about anything from here.
|
|||
* But we've dropped privileges, so it does not matter. */ |
|||
if (strlen (argv[0]) < sizeof ("-wrapper")) |
|||
goto error; |
|||
argv[0][strlen (argv[0]) - strlen ("-wrapper")] = '\0'; |
|||
|
|||
(void)argc; |
|||
if (execvp (argv[0], argv)) |
|||
perror (argv[0]); |
|||
|
|||
error: |
|||
close (pair[0]); |
|||
if (pair[1] != -1) |
|||
close (pair[1]); |
|||
return 1; |
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
/*****************************************************************************
|
|||
* vlc.c: the VLC player |
|||
***************************************************************************** |
|||
* Copyright (C) 1998-2008 the VideoLAN team |
|||
* $Id$ |
|||
* |
|||
* Authors: Vincent Seguin <seguin@via.ecp.fr> |
|||
* Samuel Hocevar <sam@zoy.org> |
|||
* Gildas Bazin <gbazin@videolan.org> |
|||
* Derk-Jan Hartman <hartman at videolan dot org> |
|||
* Lots of other people, see the libvlc AUTHORS file |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#ifdef HAVE_CONFIG_H |
|||
# include "config.h" |
|||
#endif |
|||
|
|||
#include <vlc/vlc.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <locale.h> |
|||
|
|||
|
|||
/* Explicit HACK */ |
|||
extern void LocaleFree (const char *); |
|||
extern char *FromLocale (const char *); |
|||
|
|||
#include <signal.h> |
|||
#include <time.h> |
|||
#include <pthread.h> |
|||
#include <unistd.h> |
|||
|
|||
/*****************************************************************************
|
|||
* main: parse command line, start interface and spawn threads. |
|||
*****************************************************************************/ |
|||
int main( int i_argc, const char *ppsz_argv[] ) |
|||
{ |
|||
int i_ret; |
|||
|
|||
if (geteuid () == 0) |
|||
{ |
|||
fprintf (stderr, "VLC is not supposed to be run as root. Sorry.\n" |
|||
"If you need to use real-time priorities and/or privileged TCP ports\n" |
|||
"you can use %s-wrapper (make sure it is Set-UID root first and\n" |
|||
"cannot be run by non-trusted users first).\n", ppsz_argv[0]); |
|||
return 1; |
|||
} |
|||
|
|||
setlocale (LC_ALL, ""); |
|||
|
|||
#ifndef __APPLE__ |
|||
/* This clutters OSX GUI error logs */ |
|||
fprintf( stderr, "VLC media player %s\n", libvlc_get_version() ); |
|||
#endif |
|||
|
|||
#ifdef HAVE_PUTENV |
|||
# ifndef NDEBUG |
|||
/* Activate malloc checking routines to detect heap corruptions. */ |
|||
putenv( (char*)"MALLOC_CHECK_=2" ); |
|||
# ifdef __APPLE__ |
|||
putenv( (char*)"MallocErrorAbort=crash_my_baby_crash" ); |
|||
# endif |
|||
|
|||
/* Disable the ugly Gnome crash dialog so that we properly segfault */ |
|||
putenv( (char *)"GNOME_DISABLE_CRASH_DIALOG=1" ); |
|||
# endif |
|||
#endif |
|||
|
|||
#if defined (HAVE_GETEUID) && !defined (SYS_BEOS) |
|||
/* FIXME: rootwrap (); */ |
|||
#endif |
|||
|
|||
/* Synchronously intercepted POSIX signals.
|
|||
* |
|||
* In a threaded program such as VLC, the only sane way to handle signals |
|||
* is to block them in all thread but one - this is the only way to |
|||
* predict which thread will receive them. If any piece of code depends |
|||
* on delivery of one of this signal it is intrinsically not thread-safe |
|||
* and MUST NOT be used in VLC, whether we like it or not. |
|||
* There is only one exception: if the signal is raised with |
|||
* pthread_kill() - we do not use this in LibVLC but some pthread |
|||
* implementations use them internally. You should really use conditions |
|||
* for thread synchronization anyway. |
|||
* |
|||
* Signal that request a clean shutdown, and force an unclean shutdown |
|||
* if they are triggered again 2+ seconds later. |
|||
* We have to handle SIGTERM cleanly because of daemon mode. |
|||
* Note that we set the signals after the vlc_create call. */ |
|||
static const int sigs[] = { |
|||
SIGINT, SIGHUP, SIGQUIT, SIGTERM, |
|||
/* Signals that cause a no-op:
|
|||
* - SIGPIPE might happen with sockets and would crash VLC. It MUST be |
|||
* blocked by any LibVLC-dependent application, in addition to VLC. |
|||
* - SIGCHLD is comes after exec*() (such as httpd CGI support) and must |
|||
* be dequeued to cleanup zombie processes. |
|||
*/ |
|||
SIGPIPE, SIGCHLD |
|||
}; |
|||
|
|||
sigset_t set; |
|||
sigemptyset (&set); |
|||
for (unsigned i = 0; i < sizeof (sigs) / sizeof (sigs[0]); i++) |
|||
sigaddset (&set, sigs[i]); |
|||
|
|||
/* Block all these signals */ |
|||
pthread_sigmask (SIG_BLOCK, &set, NULL); |
|||
|
|||
/* Note that FromLocale() can be used before libvlc is initialized */ |
|||
for (int i = 0; i < i_argc; i++) |
|||
if ((ppsz_argv[i] = FromLocale (ppsz_argv[i])) == NULL) |
|||
return 1; // BOOM!
|
|||
|
|||
libvlc_exception_t ex, dummy; |
|||
libvlc_exception_init (&ex); |
|||
libvlc_exception_init (&dummy); |
|||
|
|||
/* Initialize libvlc */ |
|||
int i_argc_real = i_argc ? i_argc - 1 : 0; |
|||
const char **ppsz_argv_real = i_argc ? &ppsz_argv[1] : ppsz_argv; |
|||
libvlc_instance_t *vlc = libvlc_new (i_argc_real, ppsz_argv_real, &ex); |
|||
|
|||
if (vlc != NULL) |
|||
{ |
|||
libvlc_add_intf (vlc, "signals", &dummy); |
|||
libvlc_add_intf (vlc, NULL, &ex); |
|||
libvlc_playlist_play (vlc, -1, 0, NULL, &dummy); |
|||
libvlc_wait (vlc); |
|||
libvlc_release (vlc); |
|||
} |
|||
i_ret = libvlc_exception_raised (&ex); |
|||
if( i_ret ) |
|||
fprintf( stderr, "%s\n", libvlc_exception_get_message( &ex)); |
|||
|
|||
libvlc_exception_clear (&ex); |
|||
libvlc_exception_clear (&dummy); |
|||
|
|||
for (int i = 0; i < i_argc; i++) |
|||
LocaleFree (ppsz_argv[i]); |
|||
|
|||
return i_ret; |
|||
} |
|||
@ -0,0 +1,136 @@ |
|||
/*****************************************************************************
|
|||
* winvlc.c: the Windows VLC player |
|||
***************************************************************************** |
|||
* Copyright (C) 1998-2008 the VideoLAN team |
|||
* |
|||
* Authors: Vincent Seguin <seguin@via.ecp.fr> |
|||
* Samuel Hocevar <sam@zoy.org> |
|||
* Gildas Bazin <gbazin@videolan.org> |
|||
* Derk-Jan Hartman <hartman at videolan dot org> |
|||
* Lots of other people, see the libvlc AUTHORS file |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#ifdef HAVE_CONFIG_H |
|||
# include "config.h" |
|||
#endif |
|||
|
|||
#define UNICODE |
|||
#include <vlc/vlc.h> |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <windows.h> |
|||
|
|||
static int parse_cmdline (char *line, char ***argvp) |
|||
{ |
|||
char **argv = malloc (sizeof (char *)); |
|||
int argc = 0; |
|||
|
|||
while (*line != '\0') |
|||
{ |
|||
char quote = 0; |
|||
|
|||
/* Skips white spaces */ |
|||
while (strchr ("\t ", *line)) |
|||
line++; |
|||
if (!*line) |
|||
break; |
|||
|
|||
/* Starts a new parameter */ |
|||
argv = realloc (argv, (argc + 2) * sizeof (char *)); |
|||
if (*line == '"') |
|||
{ |
|||
quote = '"'; |
|||
line++; |
|||
} |
|||
argv[argc++] = line; |
|||
|
|||
more: |
|||
while (*line && !strchr ("\t ", *line)) |
|||
line++; |
|||
|
|||
if (line > argv[argc - 1] && line[-1] == quote) |
|||
/* End of quoted parameter */ |
|||
line[-1] = 0; |
|||
else |
|||
if (*line && quote) |
|||
{ |
|||
/* Space within a quote */ |
|||
line++; |
|||
goto more; |
|||
} |
|||
else |
|||
/* End of unquoted parameter */ |
|||
if (*line) |
|||
*line++ = 0; |
|||
} |
|||
argv[argc] = NULL; |
|||
*argvp = argv; |
|||
return argc; |
|||
} |
|||
|
|||
#ifdef UNDER_CE |
|||
# define wWinMain WinMain |
|||
#endif |
|||
|
|||
/*****************************************************************************
|
|||
* wWinMain: parse command line, start interface and spawn threads. |
|||
*****************************************************************************/ |
|||
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, |
|||
LPWSTR lpCmdLine, int nCmdShow ) |
|||
{ |
|||
char **argv, psz_cmdline[wcslen(lpCmdLine) * 4 + 1]; |
|||
int argc, ret; |
|||
|
|||
(void)hInstance; (void)hPrevInstance; (void)nCmdShow; |
|||
|
|||
WideCharToMultiByte( CP_UTF8, 0, lpCmdLine, -1, |
|||
psz_cmdline, sizeof (psz_cmdline), NULL, NULL ); |
|||
|
|||
argc = parse_cmdline (psz_cmdline, &argv); |
|||
|
|||
libvlc_exception_t ex, dummy; |
|||
libvlc_exception_init (&ex); |
|||
libvlc_exception_init (&dummy); |
|||
|
|||
/* Initialize libvlc */ |
|||
libvlc_instance_t *vlc = libvlc_new (argc, (const char **)argv, &ex); |
|||
if (vlc != NULL) |
|||
{ |
|||
libvlc_add_intf (vlc, NULL, &ex); |
|||
libvlc_playlist_play (vlc, -1, 0, NULL, &dummy); |
|||
libvlc_wait (vlc); |
|||
libvlc_release (vlc); |
|||
} |
|||
free (argv); |
|||
|
|||
ret = libvlc_exception_raised (&ex); |
|||
libvlc_exception_clear (&ex); |
|||
libvlc_exception_clear (&dummy); |
|||
return ret; |
|||
} |
|||
|
|||
#ifndef IF_MINGW_SUPPORTED_UNICODE |
|||
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, |
|||
LPSTR args, int nCmdShow) |
|||
{ |
|||
/* This makes little sense, but at least it links properly */ |
|||
wchar_t lpCmdLine[(strlen (args) + 1) * 3]; |
|||
MultiByteToWideChar (CP_ACP, 0, args, -1, lpCmdLine, sizeof (lpCmdLine)); |
|||
return wWinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow); |
|||
} |
|||
#endif |
|||
Loading…
Reference in new issue