summaryrefslogtreecommitdiffstats
path: root/x11vnc/misc/desktop.cgi
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/misc/desktop.cgi')
-rwxr-xr-xx11vnc/misc/desktop.cgi1550
1 files changed, 0 insertions, 1550 deletions
diff --git a/x11vnc/misc/desktop.cgi b/x11vnc/misc/desktop.cgi
deleted file mode 100755
index d99a39c..0000000
--- a/x11vnc/misc/desktop.cgi
+++ /dev/null
@@ -1,1550 +0,0 @@
-#!/usr/bin/perl
-#
-##########################################################################
-# desktop.cgi:
-#
-# This is an example CGI script to provide multi-user web access to
-# x11vnc desktops. The user desktop sessions run in 'Xvfb' displays
-# that are created automatically.
-#
-# This script should/must be served by an HTTPS (i.e. SSL) webserver,
-# otherwise the unix and vnc passwords would be sent over the network
-# unencrypted (see below to disable if you really want to.)
-#
-# The Java VNC Viewer applet connections are encrypted by SSL as well.
-#
-# You can use this script to provide unix users desktops available on
-# demand via any Java enabled web browser. One could also use this for
-# a special-purpose 'single application' service running in a minimal
-# window manager.
-#
-# One example of a special-purpose application would be a scientific
-# data visualization tool running on a server where the data is housed.
-# To do this set $x11vnc_extra_opts = '-env FD_PROG=/path/to/app/launcher'
-# where the program launches your special purpose application. A very
-# simple example: '-env FD_PROG=/usr/bin/xclock'
-#
-#
-# Depending on where you place this script, the user accesses the service
-# with the URL:
-#
-# https://your.webserver.net/cgi-bin/desktop.cgi
-#
-# Then they login with their unix username and password to get their
-# own desktop session.
-#
-# If the user has an existing desktop it is connected to directly,
-# otherwise a new session is created inside an Xvfb display and then
-# connected to by VNC.
-#
-# It is possible to do port redirection to other machines running SSL
-# enabled VNC servers (see below.) This script does not start the VNC
-# servers on the other machines, although with some extra rigging you
-# should be able to do that as well.
-#
-# You can customize the login procedure to whatever you want by modifying
-# this script, or by using ideas in this script write your own PHP,
-# (for example), script.
-#
-##########################################################################
-# Overriding default settings:
-#
-# If you want to override any settings in this script and do not
-# want to edit this script create the assignments in a file named
-# 'desktop.cgi.conf' in the same directory as desktop.cgi. It will be
-# sourced after the defaults are set. The format of desktop.cgi.conf
-# is simply perl statements that make the assignments.
-#
-# For example, if you put something like this in desktop.cgi.conf:
-#
-# $x11vnc = '/usr/local/bin/x11vnc';
-#
-# that will set the path to the x11vnc binary to that location. Look at
-# the settings below for the other variables that you can modify, for
-# example one could set $allowed_users_file.
-#
-##########################################################################
-# x11vnc:
-#
-# You need to install x11vnc or otherwise have it available. It is
-# REQUIRED that you use x11vnc 0.9.10 or later. It won't work with
-# earlier versions. See below the $x11vnc parameter that you can set
-# to the full path to x11vnc.
-#
-##########################################################################
-# Xvfb:
-#
-# Note that the x11vnc -create virtual desktop service used below requires
-# that you install the 'Xvfb' program. On debian this is currently done
-# via 'apt-get install xvfb'.
-#
-# If you are having trouble getting 'x11vnc -create' to work with this
-# script (it can be tricky), try it manually and/or see the x11vnc FAQ
-# links below.
-#
-##########################################################################
-# Apache httpd:
-#
-# You should put this script in, say, a cgi-bin directory. Enable cgi
-# scripts in your apache (or other httpd) config. For example, we have
-# these lines (not commented):
-#
-# In httpd.conf:
-#
-# ScriptAlias /cgi-bin/ "/dist/apache/2.0/cgi-bin/"
-#
-# <Directory "/dist/apache/2.0/cgi-bin">
-# AllowOverride None
-# Options None
-# Order allow,deny
-# Allow from all
-# </Directory>
-#
-# and in ssl.conf:
-#
-# <Directory "/dist/apache/2.0/cgi-bin">
-# SSLOptions +StdEnvVars
-# </Directory>
-#
-# Do not be confused by the non-standard /dist/apache/2.0 apache
-# installation location that we happen to use. Yours will be different.
-#
-# You can test that you have CGI scripts working properly with the
-# 'test-cgi' and 'printenv' scripts apache provides.
-#
-# Copy this file (desktop.cgi) to /dist/apache/2.0/cgi-bin and then run
-# 'chmod 755 ...' on it to make it executable.
-#
-##########################################################################
-# Applet Jar files served by apache:
-#
-# You will *also* need to copy the x11vnc classes/ssl/UltraViewerSSL.jar
-# file to the httpd DocumentRoot to be accessible by: /UltraViewerSSL.jar
-# in a URL (or change $applet_jar below or the html in $applet_html if
-# you want to use a different location.)
-#
-# This location is relative to the apache DocumentRoot 'htdocs' directory.
-# For our (non-standard location installation) that meant we copied the
-# file to:
-#
-# /dist/apache/2.0/htdocs/UltraViewerSSL.jar
-#
-# (your DocumentRoot directory will be different.)
-#
-# The VncViewer.jar (tightvnc) will also work, but you need to change
-# the $applet_jar below. You can get these jar files from the x11vnc
-# tarball from:
-#
-# http://www.karlrunge.com/x11vnc/#downloading
-#
-# This script requires x11vnc 0.9.10 or later.
-#
-# Note that the usage mode for this script is a different from regular
-# 'x11vnc -http ...' usage where x11vnc acts as a mini web server and
-# serves its own applet jars. We don't use that mode for this script.
-# Apache (httpd) serves the jars.
-#
-#
-##########################################################################
-# Notes and Information:
-#
-# Each x11vnc server created for a user login will listen on its own port
-# (see below for port selection schemes.) Your firewall must let in *ALL*
-# of these ports (e.g. a port range, see below for the syntax.)
-#
-# It is also possible, although not as reliable, to do all of this through
-# a single port, see the fixed port scheme $find_free_port = 'fixed:5910'
-# below. This single port mode must be different from apache's port
-# (usually 443 for https) and must also be allowed in by your firewall.
-#
-# Note: The fixed port scheme is DISABLED by default.
-#
-# It is also possible to have this script act as a vnc redirector to SSL
-# enabled VNC servers running on *other* machines inside your firewall
-# (presumably the users' desktops) See the $enable_port_redirection
-# setting below. The user provides 'username@host:port' instead of just
-# 'username' when she logs in. This script doesn't start VNC servers
-# on those other machines, the servers must be running there already.
-# (If you want this script to start them you will need to add it
-# yourself.) It is possible to provide a host:port allow list to limit
-# which internal machines and ports can be redirected to. This is the
-# $port_redirection_allowed_hosts parameter.
-#
-# Note: The vnc redirector scheme is DISABLED by default.
-#
-# Note there are *two* SSL certificates involved that the user may be
-# asked to inspect: apache's SSL cert and x11vnc's SSL cert. This may
-# confuse naive users. You may want to use the same cert for both.
-#
-# This script provides one example on how to provide the service. You can
-# customize it to meet your needs, e.g. switch to php, newer cgi modules,
-# different authentication, SQL database for user authentication, etc,
-# etc. If you plan to use it in production, please examine all security
-# aspects of it carefully; read the comments in the script for more info.
-#
-# More information and background and troubleshooting:
-#
-# http://www.karlrunge.com/x11vnc/faq.html#faq-xvfb
-# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-tunnel-viewers
-# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-java-viewer-proxy
-# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-portal
-# http://www.karlrunge.com/x11vnc/faq.html#faq-unix-passwords
-# http://www.karlrunge.com/x11vnc/faq.html#faq-userlogin
-#
-#
-# Please also read the comments below for changing specific settings.
-# You can modify them in this script or by override file 'desktop.cgi.conf'
-
-
-#-------------------------------------------------------------------------
-# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
-#
-# desktop.cgi 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.
-#
-# desktop.cgi 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 desktop.cgi; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
-# or see <http://www.gnu.org/licenses/>.
-#-------------------------------------------------------------------------
-
-use strict;
-use IO::Socket::INET;
-
-# Test for INET6 support:
-#
-my $have_inet6 = 0;
-eval "use IO::Socket::INET6;";
-$have_inet6 = 1 if $@ eq "";
-
-##########################################################################
-# Path to the x11vnc program:
-#
-my $x11vnc = '/usr/bin/x11vnc';
-
-
-##########################################################################
-# You can set some extra x11vnc cmdline options here:
-#
-my $x11vnc_extra_opts = '';
-
-
-##########################################################################
-# Override the default x11vnc viewer connection timeout of 75 seconds:
-#
-my $x11vnc_timeout = '';
-
-
-##########################################################################
-# TCP Ports:
-#
-# Set find_free_port to 1 (or the other modes described below) to
-# autoselect a free port to use. The default is to use a port based on
-# the userid number (7000 + uid).
-#
-my $find_free_port = 0;
-
-# Or specify a port range:
-#
-#$find_free_port = '7000-8000';
-#
-# Or indicate to use a kludge to try to do everything through a SINGLE
-# port. To try to avoid contention on the port, simultaneous instances
-# of this script attempt to 'take turns' using it the single port.
-#
-#$find_free_port = 'fixed:5910';
-
-# This is the starting port for 7000 + uid and also $find_free_port = 1
-# autoselection:
-#
-my $starting_port = 7000;
-
-# Listen on AF_INET6 if IO::Socket::INET6 is available.
-#
-my $listen_on_ipv6 = 0;
-
-
-##########################################################################
-# Port redirection mode:
-#
-# This is to enable port redirection mode: username@host:port. If
-# username is valid, there will be a port redirection to internal machine
-# host:port. Presumably there is already an SSL enabled and password
-# protected VNC server running there. We don't start that VNC server.
-# (You might be able to figure out a way to do this yourself.)
-#
-# See the next setting for an allowed hosts file. The default for port
-# redirection is off.
-#
-my $enable_port_redirection = 0;
-
-# A file with allowed port redirections. The empty string '' (the
-# default) means all host:port redirections would be allowed.
-#
-# Format of the file: A list of 'user@host:port' or 'host:port'
-# entries, one per line. Port ranges, e.g. host:n-m are also accepted.
-#
-# Leading and trailing whitespace is trimmed off each line. Blank lines
-# and comment lines starting with '#' are skipped. A line consisting of
-# 'ALL' matches everything. If no match can be found or the file cannot
-# be opened the connection is dropped.
-#
-my $port_redirection_allowed_hosts = '';
-
-
-##########################################################################
-# Allowed users:
-#
-# To limit which users can use this service, set the following to a file
-# that contains the allowed user names one per line. Lines starting with
-# the '#' character are skipped.
-#
-my $allowed_users_file = '';
-
-
-##########################################################################
-# Denied users:
-#
-# As with $allowed_users_file, but to deny certain users. Applied after
-# any $allowed_users_file check and overrides the result.
-#
-my $denied_users_file = '';
-
-
-##########################################################################
-# trustUrlVncCert applet parameter:
-#
-# Set to 0 to have the java applet html set the parameter
-# trustUrlVncCert=no, i.e. the applet will not automatically accept
-# an SSL cert already accepted by an HTTPS URL. See $applet_html and
-# print_applet_html() below for more info.
-#
-my $trustUrlVncCert = 1;
-
-
-##########################################################################
-# One-time VNC password fifo:
-#
-# For extra security against local untrusted users a fifo is used
-# to copy the one-time VNC password to the user's VNC password file
-# ~user/x11vnc.pw. If that fifo transfer technique causes problems,
-# you can set this value to 1 to disable the security feature:
-#
-my $disable_vnc_passwd_fifo_safety = 0;
-
-
-##########################################################################
-# Comment this out if you don't want PATH modified:
-#
-$ENV{PATH} = "/usr/bin:/bin:$ENV{PATH}";
-
-
-##########################################################################
-# For the next two settings, note that most users will be confused that
-# geometry and session are ignored when they are returning to their
-# existing desktop session (x11vnc FINDDISPLAY action.)
-
-
-##########################################################################
-# Used below if user did not specify preferred geometry and color depth:
-#
-my $default_geometry = '1024x768x24';
-
-
-# Set this to the list of x11vnc -create sessions types to show a session
-# dropdown for the user to select from.
-#
-my $session_types = '';
-#
-# example:
-#$session_types = 'gnome kde xfce lxde wmaker enlightenment mwm twm failsafe';
-
-
-##########################################################################
-# Set this to 1 to enable user setting a unique tag for each one
-# of his desktops and so can have multiple ones simultaneously and
-# select which one he wants. For now we just hack this onto geometry
-# 1024x768x24:my_2nd_desktop but ultimately there should be a form entry
-# for it. Search for enable_unique_tags for more info:
-#
-my $enable_unique_tags = 0;
-my $unique_tag = '';
-
-
-##########################################################################
-# String of HTML for the login form:
-#
-# Feel free to customize to your taste, _USERNAME_ and _GEOMETRY_ are
-# expanded to that of the request.
-#
-my $login_str = <<"END";
-<title>x11vnc web access</title>
-<h3>x11vnc web access</h3>
-<form action="$ENV{REQUEST_URI}" method="post">
- <table border="0">
- <tr><td colspan=2><h2>Login</h2></td></tr>
- <tr><td>Username:</td><td>
- <input type="text" name="username" maxlength="40" value="_USERNAME_">
- </td></tr>
- <tr><td>Password:</td><td>
- <input type="password" name="password" maxlength="50">
- </td></tr>
- <tr><td>Geometry:</td><td>
- <input type="text" name="geometry" maxlength="40" value="_GEOMETRY_">
- </td></tr>
- <!-- session -->
- <tr><td colspan="2" align="right">
- <input type="submit" name="submit" value="Login">
- </td></tr>
- </table>
-</form>
-END
-
-
-##########################################################################
-# String of HTML returned to web browser to launch applet:
-#
-# Feel free to customize to your taste, _UID_, _VNC_PORT_, _WIDTH_,
-# _HEIGHT_, _PASS_, _TRUST_UVC_, _APPLET_JAR_, and _APPLET_CLASS_ are
-# expanded to the appropriate values before sending out to the browser.
-#
-my $applet_html = <<"END";
-<html>
-<TITLE>
-x11vnc desktop (_UID_/_VNC_PORT_)
-</TITLE>
-<APPLET CODE=_APPLET_CLASS_ ARCHIVE=_APPLET_JAR_ WIDTH=_WIDTH_ HEIGHT=_HEIGHT_>
-<param name=PORT value=_VNC_PORT_>
-<param name=VNCSERVERPORT value=_VNC_PORT_>
-<param name=PASSWORD value=_PASS_>
-<param name=trustUrlVncCert value=_TRUST_UVC_>
-<param name="Open New Window" value=yes>
-<param name="Offer Relogin" value=no>
-<param name="ignoreMSLogonCheck" value=yes>
-<param name="delayAuthPanel" value=yes>
-<!-- extra -->
-</APPLET>
-<br>
-<a href="$ENV{REQUEST_URI}">Login page</a><br>
-<a href=http://www.karlrunge.com/x11vnc>x11vnc website</a>
-</html>
-END
-
-
-##########################################################################
-# These java applet strings are expanded into the above $applet_html.
-# Note that $applet_jar is relative to your apache DocumentRoot (htdocs)
-# not the filesystem root.
-#
-my $applet_jar = '/UltraViewerSSL.jar';
-my $applet_class = 'VncViewer.class';
-
-# These make the applet panel smaller because we use 'Open New Window'
-# anyway (set to 'W' or 'H' to use actual session geometry values):
-#
-my $applet_width = '400';
-my $applet_height = '300';
-
-# To customize ALL of the HTML printed out you may need to redefine
-# the bye() subtroutine in your desktop.cgi.conf file.
-
-
-##########################################################################
-# Override any of the above settings by setting them in a file named
-# 'desktop.cgi.conf'. It is sourced here.
-#
-# You can override any variable set above by supplying perl code
-# in $0.conf that sets it to the desired value.
-#
-# Some examples you could put in $0.conf:
-#
-# $x11vnc = '/usr/local/bin/x11vnc';
-# $x11vnc_extra_opts = '-env FD_PROG=/usr/bin/xclock';
-# $x11vnc_extra_opts = '-ssl /usr/local/etc/dtcgi.pem';
-# $find_free_port = 'fixed:5999';
-# $enable_port_redirection = 1;
-# $allowed_users_file = '/usr/local/etc/dtcgi.allowed';
-#
-if (-f "$0.conf") {
- eval `cat "$0.conf"`;
-}
-
-
-##########################################################################
-# END OF MAIN USER SETTINGS.
-# Only power users should change anything below.
-##########################################################################
-
-# Print http header reply:
-#
-print STDOUT "Content-Type: text/html\r\n\r\n";
-
-
-# Require HTTPS so that unix and vnc passwords are not sent in clear text
-# (perhaps it is too late...) Disable HTTPS here at your own risk.
-#
-if ($ENV{HTTPS} !~ /^on$/i) {
- bye("HTTPS must be used (to encrypt passwords)");
-}
-
-
-# Read URL request:
-#
-my $request;
-if ($ENV{'REQUEST_METHOD'} eq "POST") {
- read(STDIN, $request, $ENV{'CONTENT_LENGTH'});
-} elsif ($ENV{'REQUEST_METHOD'} eq "GET" ) {
- $request = $ENV{'QUERY_STRING'};
-} else {
- $request = $ARGV[0];
-}
-
-my %request = url_decode(split(/[&=]/, $request));
-
-
-# Experiment for FD_TAG x11vnc feature for multiple desktops for a
-# single user:
-#
-# we hide it in geometry:tag for now:
-#
-if ($enable_unique_tags && $request{geometry} =~ /^(.*):(\w+)$/) {
- $request{geometry} = $1;
- $unique_tag = $2;
-}
-
-# Check/set geometry and session:
-#
-if (!exists $request{geometry} || $request{geometry} !~ /^[x\d]+$/) {
- # default geometry and depth:
- $request{geometry} = $default_geometry;
-}
-if (!exists $request{session} || $request{session} =~ /^\s*$/) {
- $request{session} = '';
-}
-
-
-# Expand _USERNAME_ and _GEOMETRY_ in the login string HTML:
-#
-$login_str =~ s/_USERNAME_/$request{username}/g;
-$login_str =~ s/_GEOMETRY_/$request{geometry}/g;
-
-
-# Check x11vnc version for installers of this script who do not know
-# how to read and follow instructions:
-#
-my $version = (split(' ', `$x11vnc -version`))[1];
-$version =~ s/\D*$//;
-
-my ($major, $minor, $micro) = split(/\./, $version);
-if ($major !~ /^\d+$/ || $minor !~ /^\d+$/) {
- bye("The x11vnc program is not installed correctly.");
-}
-$micro = 0 unless $micro;
-my $level = $major * 100 * 100 + $minor * 100 + $micro;
-my $needed = 0 * 100 * 100 + 9 * 100 + 10;
-if ($level < $needed) {
- bye("x11vnc version 0.9.10 or later is required. (Found version $version)");
-}
-
-
-# Set up user selected desktop session list, if enabled:
-#
-my %sessions;
-
-if ($session_types ne '') {
- my $str = "<tr><td>Session:</td><td>\n<select name=session>";
- $str .= "<option value=none>select</option>";
-
- foreach my $sess (split(' ', $session_types)) {
- next if $sess =~ /^\s*$/;
- next if $sess !~ /^\w+$/; # alphanumeric
- $sessions{$sess} = 1;
- $str .= "<option value=$sess>$sess</option>";
- }
- $str .= "</select>\n</td></tr>";
-
- # This forces $request{session} to be a valid one:
- #
- if (! exists $sessions{$request{session}}) {
- $request{session} = 'none';
- }
-
- # Insert into login_str:
- #
- my $r = $request{session};
- $str =~ s/option value=\Q$r\E/option selected value=$r/;
- $login_str =~ s/<!-- session -->/$str/;
-}
-
-
-# If no username or password, show login form:
-#
-if (!$request{username} && !$request{password}) {
- bye($login_str);
-} elsif (!$request{username}) {
- bye("No Username.<p>$login_str");
-} elsif (!$request{password}) {
- bye("No Password.<p>$login_str");
-}
-
-
-# Some shorthand names:
-#
-my $username = $request{username};
-my $password = $request{password};
-my $geometry = $request{geometry};
-my $session = $request{session};
-
-
-# If port redirection is enabled, split username@host:port
-#
-my $redirect_host = '';
-my $current_fh1 = '';
-my $current_fh2 = '';
-
-if ($enable_port_redirection) {
- ($username, $redirect_host) = split(/@/, $username, 2);
- if ($redirect_host ne '') {
- # will exit if the redirection is not allowed:
- check_redirect_host();
- }
-}
-
-# If there is an $allowed_users_file, check username against it:
-#
-if ($allowed_users_file ne '') {
- if (! open(USERS, "<$allowed_users_file")) {
- bye("Internal Error #0");
- }
- my $ok = 0;
- while (<USERS>) {
- chomp;
- $_ =~ s/^\s*//;
- $_ =~ s/\s*$//;
- next if /^#/;
- if ($username eq $_) {
- $ok = 1;
- }
- }
- close USERS;
- if (! $ok) {
- bye("Denied Username.<p>$login_str");
- }
-}
-
-# If there is a $denied_users_file, check username against it:
-#
-if ($denied_users_file ne '') {
- if (! open(USERS, "<$denied_users_file")) {
- bye("Internal Error #0");
- }
- my $ok = 1;
- while (<USERS>) {
- chomp;
- $_ =~ s/^\s*//;
- $_ =~ s/\s*$//;
- next if /^#/;
- if ($username eq $_) {
- $ok = 0;
- }
- }
- close USERS;
- if (! $ok) {
- bye("Denied Username.<p>$login_str");
- }
-}
-
-# Require username to be alphanumeric + '-' + '_':
-# (one may want to add '.' as well)
-#
-if ($username !~ /^\w[-\w]*$/) {
- bye("Invalid Username.<p>$login_str");
-}
-
-
-# Get the userid number, we may use it as his VNC display port; this
-# also checks if the username exists:
-#
-my $uid = `/usr/bin/id -u '$username'`;
-chomp $uid;
-if ($? != 0 || $uid !~ /^\d+$/) {
- bye("Invalid Username.<p>$login_str");
-}
-
-
-# Use x11vnc trick to check if the unix password is valid:
-# (requires x11vnc 0.9.10 or later.)
-#
-if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
- bye("Internal Error #1");
-}
-print X11VNC "$username:$password\n";
-
-if (!close X11VNC) {
- # x11vnc returns non-zero for invalid username+password:
- bye("Invalid Password.<p>$login_str");
-}
-
-
-# Initialize random number generator for use below:
-#
-initialize_random();
-
-
-# Set vnc port:
-#
-my $vnc_port = 0;
-my $fixed_port = 0;
-
-if (! $find_free_port) {
- # Fixed port based on userid (we assume it is free):
- #
- $vnc_port = $starting_port + $uid;
-
-} elsif ($find_free_port =~ /^fixed:(\d+)$/) {
- #
- # Enable the -loopbg method that tries to share a single port:
- #
- $vnc_port = $1;
- $fixed_port = 1;
-} else {
- # Autoselect a port, either default range (7000-8000) or a user
- # supplied range. (note that $find_free_port will now contain
- # a socket listening on the found port so that it is held.)
- #
- $vnc_port = auto_select_port();
-}
-
-# Check for crazy port value:
-#
-if ($vnc_port > 64000 || $vnc_port < 1) {
- bye("Internal Error #2 $vnc_port");
-}
-
-
-# If port redirection is enabled and the user selected it via
-# username@host:port, we do that right now and then exit.
-#
-if ($enable_port_redirection && $redirect_host ne '') {
- port_redir();
- exit 0;
-}
-
-
-# Make a random, onetime vnc password:
-#
-my $pass = '';
-my $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-my @abc = split(//, $chars);
-
-for (my $i = 0; $i < 8; $i++) {
- $pass .= $abc[ rand(scalar(@abc)) ];
-}
-
-# Use x11vnc trick to switch to user and store vnc pass in the passwdfile.
-# Result is $pass is placed in user's $HOME/x11vnc.pw
-#
-# (This is actually difficult to do without untrusted LOCAL users being
-# able to see the pass as well, see copy_password_to_user() for details
-# on how we try to avoid this.)
-#
-copy_password_to_user($pass);
-
-
-# Make a tmp file for x11vnc launcher script:
-#
-my $tmpfile = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
-chomp $tmpfile;
-
-# Check if the tmpfile is valid:
-#
-if (! -e $tmpfile || ! -o $tmpfile || -l $tmpfile) {
- unlink $tmpfile;
- bye("Internal Error #3");
-}
-if (!chmod 0644, $tmpfile) {
- unlink $tmpfile;
- bye("Internal Error #4");
-}
-if (!open(TMP, ">$tmpfile")) {
- unlink $tmpfile;
- bye("Internal Error #5");
-}
-
-
-# The x11vnc command. You adjust it to suit your needs.
-#
-# some ideas: -env FD_PROG=/usr/bin/gnome-session
-# -env FD_SESS=kde
-# -env FD_TAG=my_2nd_desktop
-# -ultrafilexfer
-#
-# Note that -timeout will cause it to exit if client does not connect
-# and -sslonly disables VeNCrypt SSL connections.
-
-# Some settings:
-# (change these if you encounter timing problems, etc.)
-#
-my $timeout = 75;
-my $extra = '';
-if ($fixed_port) {
- # settings for fixed port case:
- $timeout = 45;
- $extra .= " -loopbg100,1";
-}
-$timeout = $x11vnc_timeout if $x11vnc_timeout ne '';
-
-if ($session_types ne '') {
- # settings for session selection case:
- if (exists $sessions{$session}) {
- $extra .= " -env FD_SESS='$session'";
- }
-}
-if ($enable_unique_tags && $unique_tag ne '' && $unique_tag =~ /^\w+$/) {
- $extra .= " -env FD_TAG='$unique_tag'";
-}
-
-# This md5sum check of the vnc passwd is for extra safety (see
-# copy_password_to_user for details.)
-#
-my $md5sum = '';
-system("type md5sum > /dev/null");
-if ($? == 0) {
- my $md5 = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
- chomp $md5;
- # compute md5sum of password:
- if (-o $md5 && open(MD5, "| md5sum > $md5")) {
- print MD5 "$pass\n";
- close MD5;
- if (open(MD5, "<$md5")) {
- # read it:
- my $line = <MD5>;
- close MD5;
- my ($s, $t) = split(' ', $line);
- if (length($s) >= 32 && $s =~ /^\w+$/) {
- # shell code for user to check he has correct passwd:
- $md5sum = "if md5sum \$HOME/x11vnc.pw | grep '$s' > /dev/null; then true; else exit 1; fi";
- }
- }
- }
- unlink $md5;
-}
-
-# Write x11vnc command to the tmp file:
-#
-print TMP <<"END";
-#!/bin/sh
-export PATH=/usr/bin:/bin:\$PATH
-$md5sum
-$x11vnc -sigpipe ignore:HUP -nopw -rfbport $vnc_port \\
- -passwdfile \$HOME/x11vnc.pw -oa \$HOME/x11vnc.log \\
- -create -ssl SAVE -sslonly -env FD_GEOM=$geometry \\
- -timeout $timeout $extra $x11vnc_extra_opts \\
- >/dev/null 2>/dev/null </dev/null &
-sleep 2
-exit 0
-END
-
-close TMP;
-
-# Now launch x11vnc to switch to user and run the wrapper script:
-# (this requires x11vnc 0.9.10 or later.)
-#
-$ENV{UNIXPW_CMD} = "/bin/sh $tmpfile";
-
-# For the fixed port scheme we try to cooperate via lock file:
-# (disabled by default.)
-#
-my $rmlock = '';
-#
-if ($fixed_port) {
- # try to grab the fixed port for the next 90 secs removing stale
- # locks older than 60 secs:
- #
- $rmlock = lock_fixed_port(90, 60);
-}
-
-# Start the x11vnc cmd:
-#
-if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
- unlink $tmpfile;
- unlink $rmlock if $rmlock;
- bye("Internal Error #6");
-}
-
-select(X11VNC); $| = 1; select(STDOUT);
-
-# Close any port we held. There is still a gap of time between now
-# and when when x11vnc in $tmpfile reopens the port after the password
-# authentication. So another instance of this script could accidentally
-# think it is free...
-#
-sleep 1;
-close $find_free_port if $find_free_port;
-
-print X11VNC "$username:$password\n";
-close X11VNC; # note we ignore return value.
-unlink $tmpfile;
-
-if ($rmlock) {
- # let our x11vnc proceed a bit before removing lock.
- sleep 2;
- unlink $rmlock;
-}
-
-# Return html for the java applet to connect to x11vnc.
-#
-print_applet_html();
-
-exit 0;
-
-#################################################################
-# Subroutines:
-
-# print the message to client and exit with success.
-#
-sub bye {
- my $msg = shift;
- print STDOUT "<html>$msg</html>\n";
- exit 0;
-}
-
-# decode %xx to character:
-#
-sub url_decode {
- foreach (@_) {
- tr/+/ /;
- s/%(..)/pack("c",hex($1))/ge;
- }
- @_;
-}
-
-# seed random
-#
-sub initialize_random {
- my $rbytes = '';
- if (open(RAN, "</dev/urandom")) {
- read(RAN, $rbytes, 8);
- } elsif (open(RAN, "</dev/random")) {
- read(RAN, $rbytes, 8);
- } else {
- $rbytes = sprintf("%08d", $$);
- }
- close RAN;
-
- # set seed:
- #
- my $seed = join('', unpack("C8", $rbytes));
- $seed = substr($seed, -9);
- srand($seed);
-
- for (my $i = 0; $i < ($$ % 4096); $i++) {
- # Mix it up even a little bit more. There should be
- # over 1 billion possible vnc passwords now.
- rand();
- }
-}
-
-# Autoselect a port for vnc. Note that a socket for the found port
-# is kept open (and stored in $find_free_port) until we call x11vnc at
-# the end.
-#
-sub auto_select_port {
- my $pmin = $starting_port; # default range 7000-8000.
- my $pmax = $starting_port + 1000;
-
- if ($find_free_port =~ /^(\d+)-(\d+)$/) {
- # user supplied a range:
- $pmin = $1;
- $pmax = $2;
- if ($pmin > $pmax) {
- ($pmin, $pmax) = ($pmax, $pmin);
- }
- } elsif ($find_free_port > 1024) {
- # user supplied a starting port:
- $pmin = $find_free_port;
- $pmax = $pmin + 1000;
- }
-
- # Try to add a bit of randomness to the starting port so
- # simultaneous instances of this script won't be fooled by the gap
- # of time before x11vnc reopens the port (see near the bottom.)
- #
- my $dp = int(rand(1.0) * 0.25 * ($pmax - $pmin));
- if ($pmin + $dp < $pmax - 20) {
- $pmin = $pmin + $dp;
- }
-
- my $port = 0;
-
- # Now try to find a free one:
- #
- for (my $p = $pmin; $p <= $pmax; $p++) {
- my $sock = '';
- if ($have_inet6 && $listen_on_ipv6) {
- eval {$sock = IO::Socket::INET6->new(
- Listen => 1,
- LocalPort => $p,
- ReuseAddr => 1,
- Domain => AF_INET6,
- LocalAddr => "::",
- Proto => "tcp"
- );};
- } else {
- $sock = IO::Socket::INET->new(
- Listen => 1,
- LocalPort => $p,
- ReuseAddr => 1,
- Proto => "tcp"
- );
- }
- if ($sock) {
- # we will keep this open until we call x11vnc:
- $find_free_port = $sock;
- $port = $p;
- last;
- }
- }
- return $port;
-}
-
-# Since apache typically runs as user 'apache', 'nobody', etc, and not
-# as root it is tricky for us to copy the pass string to a file owned by
-# the user without some other untrusted local user being able to learn
-# the password (e.g. via reading a file or watching ps.) Note that with
-# the x11vnc -unixpw trick we unfortunately can't use a pipe because
-# the user command is run in its own tty.
-#
-# The best way would be a sudo action or a special setuid program for
-# copying. So consider doing that and thereby simplify this function.
-#
-# Short of a special program doing this, we use a fifo so ONLY ONE
-# process can read the password. If the untrusted local user reads it,
-# then the logging-in user's x11vnc won't get it. The login and x11vnc
-# will fail, but the untrusted user won't gain access to the logging-in
-# user's desktop.
-#
-# So here we start long, tedious work carefully managing the fifo.
-#
-sub copy_password_to_user {
-
- my $pass = shift;
-
- my $use_fifo = '';
-
- # Find a command to make a fifo:
- #
- system("type mkfifo > /dev/null");
- if ($? == 0) {
- $use_fifo = 'mkfifo %s';
- } else {
- system("type mknod > /dev/null");
- if ($? == 0) {
- $use_fifo = 'mknod %s p';
- }
- }
-
- # Create the filename for our fifo:
- #
- my $fifo = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
- chomp $fifo;
-
- if (! -e $fifo || ! -o $fifo || -l $fifo) {
- unlink $fifo;
- bye("Internal Error #7");
- }
-
- # disable fifo safety if requested:
- #
- if ($disable_vnc_passwd_fifo_safety) {
- $use_fifo = '';
- }
-
- # Make the fifo:
- #
- if ($use_fifo) {
- $use_fifo = sprintf($use_fifo, $fifo);
-
- # there is a small race here:
- system("umask 077; rm -f $fifo; $use_fifo; chmod 600 $fifo");
-
- if (!chmod 0600, $fifo) {
- # we chmod once more..
- unlink $fifo;
- bye("Internal Error #8");
- }
-
- if (! -o $fifo || ! -p $fifo || -l $fifo) {
- # but we get out if not owned by us anymore:
- unlink $fifo;
- bye("Internal Error #9");
- }
- }
-
- # Build cmd for user to read our fifo:
- #
- my $upw = '$HOME/x11vnc.pw';
- $ENV{UNIXPW_CMD} = "touch $upw; chmod 600 $upw; cat $fifo > $upw";
-
- # Start it:
- #
- if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
- unlink $fifo;
- bye("Internal Error #10");
- }
- select(X11VNC); $| = 1; select(STDOUT);
-
- if (! $use_fifo) {
- # regular file, we need to write it now.
- if (!open(FIFO, ">$fifo")) {
- close X11VNC;
- unlink $fifo;
- bye("Internal Error #11");
- }
- print FIFO "$pass\n";
- close FIFO;
- }
-
- # open fifo up for reading.
- # (this means the bad guy can read it too.)
- #
- if (!chmod 0644, $fifo) {
- unlink $fifo;
- bye("Internal Error #12");
- }
-
- # send the user's passwd now:
- #
- print X11VNC "$username:$password\n";
-
- if ($use_fifo) {
- # wait a bit for the cat $fifo to start, reader will block.
- sleep 1;
- if (!open(FIFO, ">$fifo")) {
- close X11VNC;
- unlink $fifo;
- bye("Internal Error #13");
- }
- # here it goes:
- print FIFO "$pass\n";
- close FIFO;
- }
- close X11VNC; # note we ignore return value.
- fsleep(0.5);
- unlink $fifo;
-
- # Done!
-}
-
-# For fixed, single port mode. Try to open and lock the port before
-# proceeding.
-#
-sub lock_fixed_port {
- my ($t_max, $t_age) = @_;
-
- # lock file name:
- #
- my $lock = '/tmp/desktop.cgi.lock';
- my $remove = '';
-
- my $t = 0;
- my $sock = '';
-
- while ($t < $t_max) {
- if (-e $lock) {
- # clean out stale locks if possible:
- if (! -l $lock) {
- unlink $lock;
- } else {
- my ($pid, $time) = split(/:/, readlink($lock));
- if (! -d "/proc/$pid") {
- unlink $lock;
- }
- if (time() > $time + $t_age) {
- unlink $lock;
- }
- }
- }
-
- my $reason = '';
-
- if (-l $lock) {
- # someone has locked it.
- $reason = 'locked';
- } else {
- # unlocked, try to listen on port:
- if ($have_inet6 && $listen_on_ipv6) {
- eval {$sock = IO::Socket::INET6->new(
- Listen => 1,
- LocalPort => $vnc_port,
- ReuseAddr => 1,
- Domain => AF_INET6,
- LocalAddr => "::",
- Proto => "tcp"
- );};
- } else {
- $sock = IO::Socket::INET->new(
- Listen => 1,
- LocalPort => $vnc_port,
- ReuseAddr => 1,
- Proto => "tcp"
- );
- }
- if ($sock) {
- # we got it, now try to lock:
- my $str = "$$:" . time();
- if (symlink($str, $lock)) {
- $remove = $lock;
- $find_free_port = $sock;
- last;
- }
- # wow, we didn't lock it...
- $reason = "symlink failed: $!";
- close $sock;
- } else {
- $reason = "listen failed: $!";
- }
- }
- # sleep a bit and then try again:
- #
- print STDERR "$$ failed to get fixed port $vnc_port for $username at $t ($reason)\n";
- $sock = '';
- $t += 5;
- sleep 5;
- }
- if (! $sock) {
- bye("Failed to lock fixed TCP port. Try again a bit later.<p>$login_str");
- }
- print STDERR "$$ got fixed port $vnc_port for $username at $t\n";
-
- # Return the file to remove, if any:
- #
- return $remove;
-}
-
-
-# Return html for the java applet to connect to x11vnc.
-#
-# N.B. Please examine the applet params, e.g. trustUrlVncCert=yes to
-# see if you agree with them. See x11vnc classes/ssl/README for all
-# parameters.
-#
-# Note how we do not take extreme care to authenticate the server to
-# the client applet (but note that trustUrlVncCert=yes is better than
-# trustAllVncCerts=yes) One can tighten all of this up at the expense
-# of extra certificate dialogs (assuming the user bothers to check...)
-#
-# This assumes /UltraViewerSSL.jar is at document root; you need to put
-# it there.
-#
-sub print_applet_html {
- my ($W, $H, $D) = split(/x/, $geometry);
-
- # make it smaller since we 'Open New Window' below anyway.
- if ($applet_width ne 'W') {
- $W = $applet_width;
- }
- if ($applet_height ne 'H') {
- $H = $applet_height;
- }
-
- my $tUVC = ($trustUrlVncCert ? 'yes' : 'no');
-
- # see $applet_html set in defaults section for more info:
- #
- my $str = $applet_html;
-
- $str =~ s/_UID_/$uid/g;
- $str =~ s/_VNC_PORT_/$vnc_port/g;
- $str =~ s/_WIDTH_/$W/g;
- $str =~ s/_HEIGHT_/$H/g;
- $str =~ s/_PASS_/$pass/g;
- $str =~ s/_APPLET_JAR_/$applet_jar/g;
- $str =~ s/_APPLET_CLASS_/$applet_class/g;
- $str =~ s/_TRUST_UVC_/$tUVC/g;
-
- if ($enable_port_redirection && $redirect_host ne '') {
- $str =~ s/name=PASSWORD value=.*>/name=NOT_USED value=yes>/i;
- #$str =~ s/<!-- extra -->/<!-- extra -->\n<param name="ignoreProxy" value=yes>/;
- }
-
- print $str;
-}
-
-##########################################################################
-# The following subroutines are for port redirection only, which is
-# disabled by default ($enable_port_redirection == 0)
-#
-sub port_redir {
- # To aid in avoiding zombies:
- #
- setpgrp(0, 0);
-
- # For the fixed port scheme we try to cooperate via lock file:
- #
- my $rmlock = '';
- #
- if ($fixed_port) {
- # try to grab the fixed port for the next 90 secs removing
- # stale locks older than 60 secs:
- #
- $rmlock = lock_fixed_port(90, 60);
-
- } elsif ($find_free_port eq '0') {
- if ($have_inet6 && $listen_on_ipv6) {
- eval {$find_free_port = IO::Socket::INET6->new(
- Listen => 1,
- LocalPort => $vnc_port,
- ReuseAddr => 1,
- Domain => AF_INET6,
- LocalAddr => "::",
- Proto => "tcp"
- );};
- } else {
- $find_free_port = IO::Socket::INET->new(
- Listen => 1,
- LocalPort => $vnc_port,
- ReuseAddr => 1,
- Proto => "tcp"
- );
- }
- }
- # In all cases, at this point $find_free_port is the listening
- # socket.
-
- # fork a helper process to do the port redir:
- #
- # Actually we need to spawn 4(!) of them in case the proxy check
- # /check.https.proxy.connection (it is by default) and the other
- # test connections. Spawn one for each expected connection, for
- # whatever applet parameter usage mode you set up.
- #
- for (my $n = 1; $n <= 4; $n++) {
- my $pid = fork();
- if (! defined $pid) {
- bye("Internal Error #14");
- } elsif ($pid) {
- wait;
- } else {
- if (fork) {
- exit 0;
- }
- setpgrp(0, 0);
- handle_conn();
- exit 0;
- }
- }
-
- # We now close the listening socket:
- #
- close $find_free_port;
-
- if ($rmlock) {
- # let our process proceed a bit before removing lock.
- sleep 1;
- unlink $rmlock;
- }
-
- # Now send html to the browser so it can connect:
- #
- print_applet_html();
-
- exit 0;
-}
-
-# This checks the validity of a username@host:port for the port
-# redirection mode. Finishes and exits if it is invalid.
-#
-sub check_redirect_host {
- # First check that the host:port string is valid:
- #
- if ($redirect_host !~ /^\w[-\w\.]*:\d+$/) {
- bye("Invalid Redirect Host:Port.<p>$login_str");
- }
- # Second, check if the allowed host file permits it:
- #
- if ($port_redirection_allowed_hosts ne '') {
- if (! open(ALLOWED, "<$port_redirection_allowed_hosts")) {
- bye("Internal Error #15");
- }
- my $ok = 0;
- while (my $line = <ALLOWED>) {
- chomp $line;
- # skip blank lines and '#' comments:
- next if $line =~ /^\s*$/;
- next if $line =~ /^\s*#/;
-
- # trim spaces from ends:
- $line =~ s/^\s*//;
- $line =~ s/\s*$//;
-
- # collect host:ports in case port range given:
- my @items;
- if ($line =~ /^(.*):(\d+)-(\d+)$/) {
- # port range:
- my $host = $1;
- my $pmin = $2;
- my $pmax = $3;
- for (my $p = $pmin; $p <= $pmax; $p++) {
- push @items, "$host:$p";
- }
- } else {
- push @items, $line;
- }
-
- # now check each item for a match:
- foreach my $item (@items) {
- if ($item eq 'ALL') {
- $ok = 1;
- last;
- } elsif ($item =~ /@/) {
- if ("$username\@$redirect_host" eq $item) {
- $ok = 1;
- last;
- }
- } elsif ($redirect_host eq $item) {
- $ok = 1;
- last;
- }
- }
- # got a match:
- last if $ok;
- }
- close ALLOWED;
-
- if (! $ok) {
- bye("Disallowed Redirect Host:Port.<p>$login_str");
- }
- }
-}
-
-# Much of this code is borrowed from 'connect_switch':
-#
-# (it only applies to the vnc redirector $enable_port_redirection mode
-# which is off by default.)
-#
-sub handle_conn {
- close STDIN;
- close STDOUT;
- close STDERR;
-
- $SIG{ALRM} = sub {close $find_free_port; exit 0};
-
- # We only wait 30 secs for the redir case, esp. since
- # we need to spawn so many helpers...
- #
- alarm(30);
-
- my ($client, $ip) = $find_free_port->accept();
-
- alarm(0);
-
- close $find_free_port;
-
- if (!$client) {
- exit 1;
- }
-
- my $host = '';
- my $port = '';
- if ($redirect_host =~ /^(.*):(\d+)$/) {
- ($host, $port) = ($1, $2);
- }
-
- my $sock = IO::Socket::INET->new(
- PeerAddr => $host,
- PeerPort => $port,
- Proto => "tcp"
- );
- if (! $sock && $have_inet6) {
- eval {$sock = IO::Socket::INET6->new(
- PeerAddr => $host,
- PeerPort => $port,
- Proto => "tcp"
- );};
- }
-
- if (! $sock) {
- close $client;
- exit 1;
- }
-
- $current_fh1 = $client;
- $current_fh2 = $sock;
-
- $SIG{TERM} = sub {close $current_fh1; close $current_fh2; exit 0};
-
- my $killpid = 1;
-
- my $parent = $$;
- if (my $child = fork()) {
- xfer($sock, $client, 'S->C');
- if ($killpid) {
- fsleep(0.5);
- kill 'TERM', $child;
- }
- } else {
- xfer($client, $sock, 'C->S');
- if ($killpid) {
- fsleep(0.75);
- kill 'TERM', $parent;
- }
- }
- exit 0;
-}
-
-# This does socket data transfer in one direction.
-#
-sub xfer {
- my($in, $out, $lab) = @_;
- my ($RIN, $WIN, $EIN, $ROUT);
- $RIN = $WIN = $EIN = "";
- $ROUT = "";
- vec($RIN, fileno($in), 1) = 1;
- vec($WIN, fileno($in), 1) = 1;
- $EIN = $RIN | $WIN;
- my $buf;
-
- while (1) {
- my $nf = 0;
- while (! $nf) {
- $nf = select($ROUT=$RIN, undef, undef, undef);
- }
- my $len = sysread($in, $buf, 8192);
- if (! defined($len)) {
- next if $! =~ /^Interrupted/;
- last;
- } elsif ($len == 0) {
- last;
- }
-
- my $offset = 0;
- my $quit = 0;
- while ($len) {
- my $written = syswrite($out, $buf, $len, $offset);
- if (! defined $written) {
- $quit = 1;
- last;
- }
- $len -= $written;
- $offset += $written;
- }
- last if $quit;
- }
- close($in);
- close($out);
-}
-
-# Sleep a small amount of time (float)
-#
-sub fsleep {
- my ($time) = @_;
- select(undef, undef, undef, $time) if $time;
-}