diff options
Diffstat (limited to 'x11vnc/misc/Xdummy')
-rwxr-xr-x | x11vnc/misc/Xdummy | 646 |
1 files changed, 507 insertions, 139 deletions
diff --git a/x11vnc/misc/Xdummy b/x11vnc/misc/Xdummy index 77617e4..84e77a3 100755 --- a/x11vnc/misc/Xdummy +++ b/x11vnc/misc/Xdummy @@ -1,15 +1,16 @@ #!/bin/sh # -# Xdummy: an LD_PRELOAD hack to run a stock XFree86(1) or Xorg(1) server +# Xdummy: an LD_PRELOAD hack to run a stock Xorg(1) or XFree86(1) server # with the "dummy" video driver to make it avoid Linux VT switching, etc. # # Run "Xdummy -help" for more info. # xserver="" geom="" +geom="" install="" uninstall="" -root=1 +root="" debug="" strace="" runit=1 @@ -24,31 +25,42 @@ program=`basename "$0"` help () { ${PAGER:-more} << END -$program: a hack to run a stock XFree86(1) or Xorg(1) server with the +$program: a hack to run a stock Xorg(1) or XFree86(1) X server with the "dummy" video driver such that it AVOIDS the Linux VT switching, keyboard mouse conflicts, etc associated with normal use of "dummy". -In other words, try to make XFree86/Xorg with the Device "dummy" driver +In other words, try to make Xorg/XFree86 with the Device "dummy" driver act more like Xvfb(1). To achieve this, while running the real Xserver $program intercepts system and library calls via the LD_PRELOAD method and modifies the behavior to make it work correctly (i.e. avoid the VT stuff). LD_PRELOAD tricks -are usually "clever hacks" and so might not work in all circumstances. +are usually "clever hacks" and so might not work in all situations or +break when something changes. The primary motivation for the Xdummy script is to provide a virtual X server for x11vnc but with more features than Xvfb (or Xvnc), however it could be used for other reasons (e.g. better automated testing than -with Xvfb). +with Xvfb). A nice by-product is the dummy server supports RANDR dynamic +resizing while Xvfb does not. So, for example x11vnc+Xdummy terminal +services are a little better than x11vnc+Xvfb. -Currently this program needs to be run as root, since it is too difficult -to trick it otherwise. Hopefully this will be relaxed at a later date -if the needed tricks are discovered. +This program does not need to be run as root as of 12/2009. However, +if there are problems for certain situations it may perform better +if run as root (-root option.) Also, gcc/cc is required to compile the LD_PRELOAD shared object. See -install and -uninstall described below. +Your Linux distribution may not install the dummy driver by default, e.g: + + /usr/lib/xorg/modules/drivers/dummy_drv.so + +some have it in a package named xserver-xorg-video-dummy you need +to install. + + Usage: $program <${program}-args> [--] <Xserver-args> @@ -66,8 +78,8 @@ startx example: startx -e bash -- $program :2 -depth 16 - (startx needs to be run as root, you can su(1) to a normal user - in the bash shell and then launch ~/.xinitrc or ~/.xsession, + (if startx needs to be run as root, you can su(1) to a normal + user in the bash shell and then launch ~/.xinitrc or ~/.xsession, gnome-session, startkde, startxfce4, etc.) xdm example: @@ -89,9 +101,12 @@ gdm/kdm example: Root permission and x11vnc: - This program needs to be run as root. One could run x11vnc as - root with -unixpw (it switches to the user that logs in) and - that may be OK, some other ideas: + Update: as of 12/2009 this program no longer must be run as root. + + However, in some circumstances program may need to be run as + root. If so, one could run x11vnc as root with -unixpw (it + switches to the user that logs in) and that may be OK, some + other ideas: - add this to sudo via visudo: @@ -147,6 +162,8 @@ Options: :N The DISPLAY can be the first $program argument. It is passed to the real X server. This is to aid use with startx(1), xinit(1), xdm(1), etc. + If one is not provided it tries to choose one + automatically. -geom geom1[,geom2...] Take the geometry (e.g. 1024x768) or list of geometries and insert them into the @@ -156,10 +173,13 @@ Options: -tmpdir dir Specify a temporary directory, owned by you and only writable by you. This is used in place of - /tmp/Xdummy.\$USER/ to placed the $program.so + /tmp/Xdummy.\$USER/.. to place the $program.so shared object, tweaked config files, etc. - -nonroot Try to run in non-root mode (XXX NOT yet working). + -nonroot Run in non-root mode (working 12/2009, now default) + + -root Run as root (may still be needed in some + environments.) -nosudo Do not try to use sudo(1) when re-running as root, use su(1) instead. @@ -188,14 +208,14 @@ Options: -debug Extra debugging output. - -strace strace(1) the Xserver process (for debugging). + -strace strace(1) the Xserver process (for troubleshooting). -h, -help Print out this help. Xserver-args: - Most of the XFree86 and Xorg options will work. Important ones + Most of the Xorg and XFree86 options will work. Important ones that may be supplied if missing: :N X Display number for server to use. @@ -212,8 +232,9 @@ Options: Notes: - The XFree86/Xorg "dummy" driver is currently undocmented. It works - well in this mode, but it is evidently not intended for end users. + The Xorg/XFree86 "dummy" driver is currently undocumented. It works + well in this mode, but it is evidently not intended for end-users. + So it could be removed or broken at any time. If the display Xserver-arg (e.g. :1) is not given, or ":" or ":9999" is given that indicates $program should try to find a free one. @@ -221,10 +242,10 @@ Notes: If the display virtual terminal, VT, (e.g. vt9) is not given that indicates $program should try to find a free one (or guess a high one). - This program is not completely secure WRT files in /tmp (but it - tries to some degree). Better is to use the -tmpdir option to supply a - directory only writable by you. Even better is to get rid of users on - the local machine you do not trust :-) + This program is not completely secure WRT files in /tmp (but it tries + to a good degree). Better is to use the -tmpdir option to supply a + directory only writable by you. Even better is to get rid of users + on the local machine you do not trust :-) END } @@ -232,7 +253,10 @@ END warn() { echo "$*" 1>&2 } -#set -xv + +if [ "X$XDUMMY_SET_XV" != "X" ]; then + set -xv +fi if [ "X$XDUMMY_UID" = "X" ]; then XDUMMY_UID=`id -u` @@ -245,20 +269,34 @@ if [ "X$XDUMMY_UID" = "X0" ]; then fi fi -#warn "id: `id -u`" -# See if it needs to be run as root: -if [ "X$XDUMMY_SU_EXEC" = "X" -a "X`id -u`" != "X0" ]; then - dosu=1 - nosudo="" +# check if root=1 first: +# +if [ "X$XDUMMY_RUN_AS_ROOT" = "X1" ]; then + root=1 +fi +for arg in $* +do + if [ "X$arg" = "X-nonroot" ]; then + root="" + elif [ "X$arg" = "X-root" ]; then + root=1 + fi +done + +# See if it really needs to be run as root: +# +if [ "X$XDUMMY_SU_EXEC" = "X" -a "X$root" = "X1" -a "X`id -u`" != "X0" ]; then + # this is to prevent infinite loop in case su/sudo doesn't work: XDUMMY_SU_EXEC=1 export XDUMMY_SU_EXEC + + dosu=1 + nosudo="" + for arg in $* do - #echo "arg=$arg" if [ "X$arg" = "X-nonroot" ]; then dosu="" - elif [ "X$arg" = "X-noroot" ]; then - dosu="" elif [ "X$arg" = "X-nosudo" ]; then nosudo="1" elif [ "X$arg" = "X-help" ]; then @@ -278,7 +316,7 @@ if [ "X$XDUMMY_SU_EXEC" = "X" -a "X`id -u`" != "X0" ]; then fi done if [ $dosu ]; then - warn "$program: currently needs to be run as root to work." + # we need to restart it with su/sudo: if type sudo > /dev/null 2>&1; then : else @@ -303,9 +341,13 @@ if [ "X$XDUMMY_SU_EXEC" = "X" -a "X`id -u`" != "X0" ]; then fi fi -#warn "args: $*" +# This will hold the X display, e.g. :20 +# disp="" +args="" + # Process Xdummy args: +# while [ "X$1" != "X" ] do case $1 in @@ -315,9 +357,19 @@ do ;; "-uninstall") uninstall=1 ;; + "-n") runit="" + ;; + "-no") runit="" + ;; + "-norun") runit="" + ;; + "-prconf") prconf=1 + ;; + "-noconf") noconf=1 + ;; "-nonroot") root="" ;; - "-noroot") root="" + "-root") root=1 ;; "-nosudo") nosudo=1 ;; @@ -328,15 +380,9 @@ do ;; "-geom"*) geom="$2"; shift ;; - "-tmpdir") XDUMMY_TMPDIR="$2"; shift - ;; - "-n") runit="" - ;; - "-no") runit="" - ;; - "-prconf") prconf=1 + "-depth") depth="$2"; shift ;; - "-noconf") noconf=1 + "-tmpdir") XDUMMY_TMPDIR="$2"; shift ;; "-debug") debug=1 ;; @@ -348,13 +394,14 @@ do ;; "--") shift; break ;; - *) break + *) args="$args $1" ;; esac shift done # Try to get a username for use in our tmp directory, etc. +# user="" if [ X`id -u` = "X0" ]; then user=root # this will also be used below for id=0 @@ -363,7 +410,9 @@ elif [ "X$USER" != "X" ]; then elif [ "X$LOGNAME" != "X" ]; then user=$LOGNAME fi -# keep trying... + +# Keep trying... +# if [ "X$user" = "X" ]; then user=`whoami 2>/dev/null` fi @@ -374,14 +423,15 @@ if [ "X$user" = "X" -o "X$user" = "X." ]; then user="u$$" fi -if [ "X$debug" = "X1" ]; then +if [ "X$debug" = "X1" -a "X$runit" != "X" ]; then echo "" echo "/usr/bin/env:" - env + env | egrep -v '^(LS_COLORS|TERMCAP)' | sort echo "" fi # Function to compile the LD_PRELOAD shared object: +# make_so() { # extract code embedded in this script into a tmp C file: @@ -396,7 +446,6 @@ make_so() { warn "$tmp still exists." exit 1 fi - #tail +$n1 $0 | head -$dn > $tmp tail -n +$n1 $0 | head -n $dn > $tmp # compile it to Xdummy.so: @@ -404,7 +453,7 @@ make_so() { touch $SO if [ ! -f $SO ]; then SO=$tdir/Xdummy.$user.so - warn "warning switch LD_PRELOAD shared object to: $SO" + warn "warning switching LD_PRELOAD shared object to: $SO" fi rm -f $SO @@ -417,7 +466,7 @@ make_so() { exit 1 fi if [ "X$debug" != "X" -o "X$install" != "X" ]; then - warn "$program: created $SO" + warn "$program: created $SO" ls -l "$SO" fi } @@ -434,11 +483,10 @@ fi SO=$0.so if [ "X$install" != "X" -o "X$uninstall" != "X" ]; then if [ -e $SO -o -h $SO ]; then - warn "removing $SO" + warn "$program: removing $SO" fi rm -f $SO if [ -e $SO -o -h $SO ]; then - # not good... warn "warning: $SO still exists." exit 1 fi @@ -452,12 +500,31 @@ if [ "X$install" != "X" -o "X$uninstall" != "X" ]; then fi # We need a tmp directory for the .so, tweaked config file, and for -# redirecting filenames we cannot create (under -nonroot, not yet -# working). +# redirecting filenames we cannot create (under -nonroot) # +tack="" if [ "X$XDUMMY_TMPDIR" = "X" ]; then XDUMMY_TMPDIR="/tmp/Xdummy.$user" + + # try to tack on a unique subdir (display number or pid) + # to allow multiple instances + # + if [ "X$disp" != "X" ]; then + t0=$disp + else + t0=$1 + fi + tack=`echo "$t0" | sed -e 's/^.*://'` + if echo "$tack" | grep '^[0-9][0-9]*$' > /dev/null; then + : + else + tack=$$ + fi + if [ "X$tack" != "X" ]; then + XDUMMY_TMPDIR="$XDUMMY_TMPDIR/$tack" + fi fi + tmp=$XDUMMY_TMPDIR if echo "$tmp" | grep '^/tmp' > /dev/null; then if [ "X$tmp" != "X/tmp" -a "X$tmp" != "X/tmp/" ]; then @@ -472,8 +539,12 @@ fi mkdir -p $XDUMMY_TMPDIR chmod 700 $XDUMMY_TMPDIR +if [ "X$tack" != "X" ]; then + chmod 700 `dirname "$XDUMMY_TMPDIR"` 2>/dev/null +fi -# see if we can write something there: +# See if we can write something there: +# tfile="$XDUMMY_TMPDIR/test.file" touch $tfile if [ ! -f $tfile ]; then @@ -486,52 +557,100 @@ rm -f $tfile export XDUMMY_TMPDIR -# compile the LD_PRELOAD shared object if needed: +# Compile the LD_PRELOAD shared object if needed (needs XDUMMY_TMPDIR) +# if [ ! -f $SO ]; then SO="$XDUMMY_TMPDIR/Xdummy.so" make_so fi -# decide which X server to use: +# Decide which X server to use: +# if [ "X$xserver" = "X" ]; then if type Xorg >/dev/null 2>&1; then xserver="Xorg" elif type XFree86 >/dev/null 2>&1; then xserver="XFree86" - elif -x /usr/X11R6/bin/Xorg; then - xserver="/usr/X11R6/bin/Xorg" elif -x /usr/bin/Xorg; then xserver="/usr/bin/Xorg" + elif -x /usr/X11R6/bin/Xorg; then + xserver="/usr/X11R6/bin/Xorg" elif -x /usr/X11R6/bin/XFree86; then xserver="/usr/X11R6/bin/XFree86" fi if [ "X$xserver" = "X" ]; then # just let it fail below. - xserver="/usr/X11R6/bin/Xorg" + xserver="/usr/bin/Xorg" warn "$program: cannot locate a stock Xserver... assuming $xserver" fi fi -# see if the binary is suid or not readable under -nonroot (XXX not yet useful): -xserver_path=`type -p $xserver 2>/dev/null` +# See if the binary is suid or not readable under -nonroot mode: +# +if [ "X$BASH_VERSION" != "X" ]; then + xserver_path=`type -p $xserver 2>/dev/null` +else + xserver_path=`type $xserver 2>/dev/null | awk '{print $NF}'` +fi if [ -e "$xserver_path" -a "X$root" = "X" -a "X$runit" != "X" ]; then - if [ ! -r $xserver_path -o -u $xserver_path ]; then + if [ ! -r $xserver_path -o -u $xserver_path -o -g $xserver_path ]; then # XXX not quite correct with rm -rf $XDUMMY_TMPDIR ... + # we keep on a filesystem we know root can write to. base=`basename "$xserver_path"` - #new="$tdir/$base.$user" - new="/tmp/$base.$user" - if [ ! -e $new ]; then - warn "NEED TO COPY UNREADABLE $xserver_path to $new as root:" - warn "" - ls -l $xserver_path 1>&2 - warn "" - warn "This only needs to be done once." - warn "Please supply root passwd to 'su -c'" + new="/tmp/$base.$user.bin" + if [ -e $new ]; then + snew=`ls -l $new | awk '{print $5}' | grep '^[0-9][0-9]*$'` + sold=`ls -l $xserver_path | awk '{print $5}' | grep '^[0-9][0-9]*$'` + if [ "X$snew" != "X" -a "X$sold" != "X" -a "X$sold" != "X$snew" ]; then + warn "removing different sized copy:" + ls -l $new $xserver_path + rm -f $new + fi + fi + if [ ! -e $new -o ! -s $new ]; then + rm -f $new touch $new || exit 1 chmod 700 $new || exit 1 - su -c "cat $xserver_path > $new" + if [ ! -r $xserver_path ]; then + warn "" + warn "NEED TO COPY UNREADABLE $xserver_path to $new as root:" + warn "" + ls -l $xserver_path 1>&2 + warn "" + warn "This only needs to be done once:" + warn " cat $xserver_path > $new" + warn "" + nos=$nosudo + if type sudo > /dev/null 2>&1; then + : + else + nos=1 + fi + if [ "X$nos" = "X1" ]; then + warn "Please supply root passwd to 'su -c'" + su -c "cat $xserver_path > $new" + else + warn "Please supply the sudo passwd if asked:" + sudo /bin/sh -c "cat $xserver_path > $new" + fi + else + warn "" + warn "COPYING SETUID $xserver_path to $new" + warn "" + ls -l $xserver_path 1>&2 + warn "" + cat $xserver_path > $new + fi ls -l $new - warn "Please restart." + if [ -s $new ]; then + : + else + rm -f $new + ls -l $new + exit 1 + fi + warn "" + warn "Please restart Xdummy now." exit 0 elif [ ! -O $new ]; then warn "file \"$new\" not owned by us!" @@ -542,7 +661,8 @@ if [ -e "$xserver_path" -a "X$root" = "X" -a "X$runit" != "X" ]; then fi fi -# work out display: +# Work out display: +# if [ "X$disp" != "X" ]; then : elif [ "X$1" != "X" ]; then @@ -556,6 +676,7 @@ elif [ "X$1" != "X" ]; then fi if [ "X$disp" = "X" -o "X$disp" = "X:" ]; then # try to find an open display port: + # (tcp outdated...) ports=`netstat -ant | grep LISTEN | awk '{print $4}' | sed -e 's/^.*://'` n=0 while [ $n -le 20 ] @@ -572,7 +693,8 @@ if [ "X$disp" = "X" -o "X$disp" = "X:" ]; then done fi -# work out which vt to use, try to find an open one if necessary. +# Work out which vt to use, try to find/guess an open one if necessary. +# vt="" for arg in $* do @@ -604,13 +726,14 @@ if [ "X$vt" = "X" ]; then if [ "X$vt" = "X" ]; then # take a wild guess... vt=vt16 - warn "$program: selected VT $vt" + warn "$program: selected fallback VT $vt" fi else vt="" fi -# decide flavor of Xserver: +# Decide flavor of Xserver: +# stype=`basename "$xserver"` if echo "$stype" | grep -i xorg > /dev/null; then stype=xorg @@ -618,7 +741,8 @@ else stype=xfree86 fi -# work out config file and tweak it. +# Work out config file and tweak it. +# next="" config="" got_config="" @@ -630,29 +754,39 @@ do break fi if [ "X$arg" = "X-xf86config" ]; then - stype="xfree86" + if [ "X$stype" = "X" ]; then + stype="xfree86" + fi next=1 elif [ "X$arg" = "X-config" ]; then - stype="xorg" + if [ "X$stype" = "X" ]; then + stype="xorg" + fi next=1 fi done tweak_config() { in="$1" - config2="$XDUMMY_TMPDIR/xconfig" + config2="$XDUMMY_TMPDIR/xdummy_modified_xconfig.conf" if [ "X$disp" != "X" ]; then - d=`echo "$disp" | sed -e 's,/,,g' -e 's/:/_:/g'` + d=`echo "$disp" | sed -e 's,/,,g' -e 's/:/_/g'` config2="$config2$d" fi # perl script to tweak the config file... add/delete options, etc. - XDUMMY_GEOM=$geom; export XDUMMY_GEOM - perl > $config2 < $in -e ' + # + env XDUMMY_GEOM=$geom \ + XDUMMY_DEPTH=$depth \ + perl > $config2 < $in -e ' $n = 0; - $geom = $ENV{XDUMMY_GEOM}; + $geom = $ENV{XDUMMY_GEOM}; + $depth = $ENV{XDUMMY_DEPTH}; + $videoram = "24000"; + $HorizSync = "30.0 - 130.0"; + $VertRefresh = "50.0 - 250.0"; if ($geom ne "") { - $tmp = ""; + my $tmp = ""; foreach $g (split(/,/, $geom)) { $tmp .= "\"$g\" "; } @@ -675,7 +809,7 @@ tweak_config() { print; next; } - if (/^\s*EndSection/) { + if (/^\s*EndSection/i) { # end of Section if ($sect eq "serverflags") { if (!$got_DontVTSwitch) { @@ -697,13 +831,63 @@ tweak_config() { } if (!$got_VideoRam) { print " ##Xdummy:##\n"; - print " VideoRam 16000\n"; + print " VideoRam $videoram\n"; + } + } elsif ($sect eq "screen") { + if ($depth ne "" && !got_DefaultDepth) { + print " ##Xdummy:##\n"; + print " DefaultDepth $depth\n"; + } + if ($got_Monitor eq "") { + print " ##Xdummy:##\n"; + print " Monitor \"Monitor0\"\n"; + } + } elsif ($sect eq "monitor") { + if (!got_HorizSync) { + print " ##Xdummy:##\n"; + print " HorizSync $HorizSync\n"; + } + if (!got_VertRefresh) { + print " ##Xdummy:##\n"; + print " VertRefresh $VertRefresh\n"; } } $sect = ""; print; next; } + + if (/^\s*SubSection\s+(\S+)/i) { + # start of Section + $subsect = $1; + $subsect =~ s/\W//g; + $subsect =~ y/A-Z/a-z/; + $subsects{$subsect} = 1; + if ($sect eq "screen" && $subsect eq "display") { + $got_Mode = 0; + } + print; + next; + } + if (/^\s*EndSubSection/i) { + # end of SubSection + if ($sect eq "screen") { + if ($subsect eq "display") { + if ($depth ne "" && !$set_Depth) { + print " ##Xdummy:##\n"; + print " Depth\t$depth\n"; + } + if ($geom ne "" && ! $got_Mode) { + print " ##Xdummy:##\n"; + print " Modes\t$geom\n"; + } + } + } + $subsect = ""; + print; + next; + } + $l = $_; $l =~ s/#.*$//; if ($sect eq "serverflags") { @@ -725,6 +909,14 @@ tweak_config() { $_ = "##Xdummy## $_"; } } + if ($sect eq "monitor") { + if ($l =~ /^\s*HorizSync/i) { + $got_HorizSync = 1; + } + if ($l =~ /^\s*VertRefresh/i) { + $got_VertRefresh = 1; + } + } if ($sect eq "device") { if ($l =~ /^(\s*Driver)\b/i) { $_ = "$1 \"dummy\"\n"; @@ -741,11 +933,34 @@ tweak_config() { } } if ($sect eq "screen") { - if ($geom ne "") { - if ($l =~ /^(\s*Modes)\b/i) { - $_ = "$1 $geom\n"; + if ($l =~ /^\s*DefaultDepth\s+(\d+)/i) { + if ($depth ne "") { print " ##Xdummy:##\n"; - $got_Modes = 1; + $_ = " DefaultDepth\t$depth\n"; + } + $got_DefaultDepth = 1; + } + if ($l =~ /^\s*Monitor\s+(\S+)/i) { + $got_Monitor = $1; + $got_Monitor =~ s/"//g; + } + if ($subsect eq "display") { + if ($geom ne "") { + if ($l =~ /^(\s*Modes)\b/i) { + print " ##Xdummy:##\n"; + $_ = "$1 $geom\n"; + $got_Modes = 1; + } + } + if ($l =~ /^\s*Depth\s+(\d+)/i) { + my $d = $1; + if (!$set_Depth && $depth ne "") { + $set_Depth = 1; + if ($depth != $d) { + print " ##Xdummy:##\n"; + $_ = " Depth\t$depth\n"; + } + } } } } @@ -765,15 +980,15 @@ tweak_config() { print "Section \"Device\"\n"; print " Identifier \"Videocard0\"\n"; print " Driver \"dummy\"\n"; - print " VideoRam 16000\n"; + print " VideoRam $videoram\n"; print "EndSection\n"; } if (! exists($sects{monitor})) { print "\n##Xdummy:##\n"; print "Section \"Monitor\"\n"; print " Identifier \"Monitor0\"\n"; - print " HorizSync 30.0 - 130.0\n"; - print " VertRefresh 50.0 - 250.0\n"; + print " HorizSync $HorizSync\n"; + print " VertRefresh $VertRefresh\n"; print "EndSection\n"; } if (! exists($sects{screen})) { @@ -781,19 +996,30 @@ tweak_config() { print "Section \"Screen\"\n"; print " Identifier \"Screen0\"\n"; print " Device \"Videocard0\"\n"; - print " Monitor \"Monitor0\"\n"; - print " DefaultDepth 16\n"; + if ($got_Monitor ne "") { + print " Monitor \"$got_Monitor\"\n"; + } else { + print " Monitor \"Monitor0\"\n"; + } + if ($depth ne "") { + print " DefaultDepth $depth\n"; + } else { + print " DefaultDepth 24\n"; + } print " SubSection \"Display\"\n"; print " Viewport 0 0\n"; - print " Depth 16\n"; - print " Modes \"1024x768\" \"800x600\" \"640x480\"\n"; + print " Depth 24\n"; + if ($geom ne "") { + print " Modes $geom\n"; + } else { + print " Modes \"1280x1024\" \"1024x768\" \"800x600\"\n"; + } print " EndSubSection\n"; print "EndSection\n"; } '; } -args="$*" if [ ! $noconf ]; then # tweaked config will be put in $config2: config2="" @@ -823,13 +1049,77 @@ if [ ! $noconf ]; then fi fi + if [ ! -f $config ]; then + config="$XDUMMY_TMPDIR/xorg.conf" + cat > $config <<END + +Section "ServerLayout" + Identifier "Layout0" + Screen 0 "Screen0" + InputDevice "Keyboard0" "CoreKeyboard" + InputDevice "Mouse0" "CorePointer" +EndSection + +Section "Files" +EndSection + +Section "Module" + Load "dbe" + Load "extmod" + Load "freetype" + Load "glx" +EndSection + +Section "InputDevice" + Identifier "Mouse0" + Driver "mouse" + Option "Protocol" "auto" + Option "Device" "/dev/psaux" + Option "Emulate3Buttons" "no" + Option "ZAxisMapping" "4 5" +EndSection + +Section "InputDevice" + Identifier "Keyboard0" + Driver "kbd" +EndSection + +Section "Monitor" + Identifier "Monitor0" + VendorName "Unknown" + ModelName "Unknown" + HorizSync 30.0 - 130.0 + VertRefresh 50.0 - 250.0 + Option "DPMS" +EndSection + +Section "Device" + Identifier "Device0" + Driver "foovideo" + VendorName "foovideo Corporation" +EndSection + +Section "Screen" + Identifier "Screen0" + Device "Device0" + Monitor "Monitor0" + DefaultDepth 24 + SubSection "Display" + Depth 24 + Modes "1280x1024" + EndSubSection +EndSection + +END + fi + if [ -f $config ]; then tweak_config $config fi # now we need to get our tweaked config file onto the command line: if [ ! $got_config ]; then - # append: + # append to cmdline (FUBAR will be substituted below.) if [ "X$stype" = "Xxorg" ]; then args="$args -config FUBAR" else @@ -838,9 +1128,14 @@ if [ ! $noconf ]; then fi if [ "X$config2" != "X" ]; then # or modify $args: + c2=$config2 + if [ "X$root" = "X" ]; then + # ordinary user cannot use absolute path. + c2=`basename $config2` + fi args=`echo "$args" | sed \ - -e "s,-config *[^ ][^ ]*,-config $config2,g" \ - -e "s,-xf86config *[^ ][^ ]*,-xf86config $config2,g"` + -e "s,-config *[^ ][^ ]*,-config $c2,g" \ + -e "s,-xf86config *[^ ][^ ]*,-xf86config $c2,g"` fi fi @@ -850,10 +1145,11 @@ if [ $prconf ]; then warn "" if [ "X$config2" = "X" ]; then warn "NO CONFIG GENERATED." + exit 1 else cat "$config2" fi - exit + exit 0 fi if [ $debug ]; then @@ -865,8 +1161,18 @@ if [ $root ]; then export XDUMMY_ROOT fi -# finally, run it: +# Finally, run it: +# if [ "X$debug" != "X" -o "X$runit" = "X" ]; then + if [ ! $runit ]; then + echo "" + echo "/usr/bin/env:" + env | egrep -v '^(LS_COLORS|TERMCAP)' | sort + echo "" + echo "XDUMMY*:" + env | grep '^XDUMMY' | sort + echo "" + fi warn "" warn "The command to run is:" warn "" @@ -886,6 +1192,7 @@ if [ "X$debug" != "X" -o "X$runit" = "X" ]; then exit 0 fi fi + if [ $strace ]; then strace -f env LD_PRELOAD=$SO $xserver $disp $args $vt else @@ -893,6 +1200,7 @@ else fi exit $? + ######################################################################### code() { @@ -923,19 +1231,17 @@ code() { #define __USE_GNU #include <dlfcn.h> -static char tmpdir[1024]; -static char str1[1024]; -static char str2[1024]; +static char tmpdir[4096]; +static char str1[4096]; +static char str2[4096]; static char devs[256][1024]; static int debug = -1; static int root = -1; static int changed_uid = 0; static int saw_fonts = 0; +static int saw_lib_modules = 0; -#if 0 -typedef long time_t; -#endif static time_t start = 0; void check_debug(void) { @@ -945,11 +1251,13 @@ void check_debug(void) { } else { debug = 0; } + /* prevent other processes using the preload: */ putenv("LD_PRELOAD="); } } void check_root(void) { if (root < 0) { + /* script tells us if we are root */ if (getenv("XDUMMY_ROOT") != NULL) { root = 1; } else { @@ -961,14 +1269,15 @@ void check_root(void) { void check_uid(void) { if (start == 0) { start = time(NULL); - if (debug) fprintf(stderr, "START: %d\n", start); + if (debug) fprintf(stderr, "START: %u\n", (unsigned int) start); return; } else if (changed_uid == 0) { if (saw_fonts || time(NULL) > start + 20) { if (getenv("XDUMMY_UID")) { int uid = atoi(getenv("XDUMMY_UID")); - if (debug) fprintf(stderr, "SETREUID: %d\n", uid); + if (debug) fprintf(stderr, "SETREUID: %d saw_fonts=%d\n", uid, saw_fonts); if (uid >= 0) { + /* this will simply fail in -nonroot mode: */ setreuid(uid, -1); } } @@ -1024,15 +1333,23 @@ int open(const char *pathname, int flags, unsigned short mode) { dlsym(RTLD_NEXT, "open"); } - if (! root) { - if (!strcmp(pathname, "/dev/mem")) { - ; - } else if (!strcmp(pathname, "/dev/tty")) { - ; - } else if (strstr(pathname, "/dev") == pathname) { + if (strstr(pathname, "lib/modules/")) { + /* not currently used. */ + saw_lib_modules = 1; + } + + if (!root) { + if (strstr(pathname, "/dev/") == pathname) { store_dev = strdup(pathname); + } + if (strstr(pathname, "/dev/tty") == pathname && strcmp(pathname, "/dev/tty")) { pathname = tmpdir_path(pathname); - if (debug) fprintf(stderr, "OPEN: -> %s\n", pathname); + if (debug) fprintf(stderr, "OPEN: %s -> %s (as FIFO)\n", store_dev, pathname); + /* we make it a FIFO so ioctl on it does not fail */ + unlink(pathname); + mkfifo(pathname, 0666); + } else if (0) { + /* we used to handle more /dev files ... */ fd = real_open(pathname, O_WRONLY|O_CREAT, 0777); close(fd); } @@ -1040,11 +1357,10 @@ int open(const char *pathname, int flags, unsigned short mode) { fd = real_open(pathname, flags, mode); - if (debug) fprintf(stderr, "OPEN: %s %d %d fd=%d\n", - pathname, flags, mode, fd); + if (debug) fprintf(stderr, "OPEN: %s %d %d fd=%d\n", pathname, flags, mode, fd); if (! root) { - if (store_dev && fd < 256) { + if (store_dev) { if (fd < 256) { strcpy(devs[fd], store_dev); } @@ -1065,6 +1381,28 @@ int open64(const char *pathname, int flags, unsigned short mode) { return(fd); } +int rename(const char *oldpath, const char *newpath) { + static int (*real_rename)(const char *, const char *) = NULL; + + CHECKIT + if (! real_rename) { + real_rename = (int (*)(const char *, const char *)) + dlsym(RTLD_NEXT, "rename"); + } + + if (debug) fprintf(stderr, "RENAME: %s %s\n", oldpath, newpath); + + if (root) { + return(real_rename(oldpath, newpath)); + } + + if (strstr(oldpath, "/var/log") == oldpath) { + if (debug) fprintf(stderr, "RENAME: returning 0\n"); + return 0; + } + return(real_rename(oldpath, newpath)); +} + FILE *fopen(const char *pathname, const char *mode) { static FILE* (*real_fopen)(const char *, const char *) = NULL; char *str; @@ -1084,8 +1422,20 @@ FILE *fopen(const char *pathname, const char *mode) { real_fopen = (FILE* (*)(const char *, const char *)) dlsym(RTLD_NEXT, "fopen"); } + if (debug) fprintf(stderr, "FOPEN: %s %s\n", pathname, mode); + if (strstr(pathname, "xdummy_modified_xconfig.conf")) { + /* make our config appear to be in /etc/X11, etc. */ + char *q = strrchr(pathname, '/'); + if (q != NULL && getenv("XDUMMY_TMPDIR") != NULL) { + strcpy(str1, getenv("XDUMMY_TMPDIR")); + strcat(str1, q); + if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str1); + pathname = str1; + } + } + if (root) { return(real_fopen(pathname, mode)); } @@ -1093,9 +1443,9 @@ FILE *fopen(const char *pathname, const char *mode) { str = (char *) pathname; if (strstr(pathname, "/var/log") == pathname) { str = tmpdir_path(pathname); - if (debug) fprintf(stderr, "FOPEN: -> %s\n", str); + if (debug) fprintf(stderr, "FOPEN: %s -> %s\n", pathname, str); } - + return(real_fopen(str, mode)); } @@ -1134,6 +1484,8 @@ int ioctl(int fd, int req, void *ptr) { RETURN0 } else if (req == KDGKBMODE) { RETURN0 + } else if (req == KDSKBMODE) { + RETURN0 } else if (req == VT_ACTIVATE) { RETURN0 } else if (req == VT_WAITACTIVE) { @@ -1181,7 +1533,7 @@ int close(int fd) { } if (debug) fprintf(stderr, "CLOSE: %d\n", fd); - if (! root) { + if (!root) { if (fd < 256) { devs[fd][0] = '\0'; } @@ -1221,11 +1573,6 @@ int stat64(const char *path, struct stat *buf) { return(real_stat64(path, buf)); } -/* - * Note: the following just call the real function if root is - * true. They will be used if -nonroot is ever figured out. - */ - int chown(const char *path, uid_t owner, gid_t group) { static int (*real_chown)(const char *, uid_t, gid_t) = NULL; @@ -1252,11 +1599,13 @@ int chown(const char *path, uid_t owner, gid_t group) { int ioperm(unsigned long from, unsigned long num, int turn_on) { static int (*real_ioperm)(unsigned long, unsigned long, int) = NULL; + CHECKIT if (! real_ioperm) { real_ioperm = (int (*)(unsigned long, unsigned long, int)) dlsym(RTLD_NEXT, "ioperm"); } + if (debug) fprintf(stderr, "IOPERM: %d %d %d\n", (int) from, (int) num, turn_on); if (root) { return(real_ioperm(from, num, turn_on)); } @@ -1265,16 +1614,25 @@ int ioperm(unsigned long from, unsigned long num, int turn_on) { int iopl(int level) { static int (*real_iopl)(int) = NULL; + CHECKIT if (! real_iopl) { real_iopl = (int (*)(int)) dlsym(RTLD_NEXT, "iopl"); } + if (debug) fprintf(stderr, "IOPL: %d\n", level); if (root) { return(real_iopl(level)); } return 0; } +#if 0 + +/* + * we got things to work w/o pretending to be root. + * so we no longer interpose getuid(), etc. + */ + uid_t getuid(void) { static uid_t (*real_getuid)(void) = NULL; CHECKIT @@ -1299,6 +1657,21 @@ uid_t geteuid(void) { if (debug) fprintf(stderr, "GETEUID: 0\n"); return 0; } +uid_t geteuid_kludge1(void) { + static uid_t (*real_geteuid)(void) = NULL; + CHECKIT + if (! real_geteuid) { + real_geteuid = (uid_t (*)(void)) dlsym(RTLD_NEXT, "geteuid"); + } + if (debug) fprintf(stderr, "GETEUID: 0 saw_libmodules=%d\n", saw_lib_modules); + if (root && !saw_lib_modules) { + return(real_geteuid()); + } else { + saw_lib_modules = 0; + return 0; + } +} + uid_t getuid32(void) { static uid_t (*real_getuid32)(void) = NULL; CHECKIT @@ -1372,15 +1745,10 @@ gid_t getegid32(void) { if (debug) fprintf(stderr, "GETEGID32: 0\n"); return 0; } - -#if 0 -int xf86PathIsSafe(char *path) { - fprintf(stderr, "xf86pathIsSafe: %s\n", path); - return 1; -} #endif #if 0 +/* maybe we need to interpose on strcmp someday... here is the template */ int strcmp(const char *s1, const char *s2) { static int (*real_strcmp)(const char *, const char *) = NULL; CHECKIT |