<?php

 #  remote X11 app innovocation module for nanoweb
 #  ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
 #  A client may indirectly execute an X11 executable on the server,
 #  which of course will be displayed on the remote host, if a
 #  connection can be established.
 #  If there's no X11 support on client side an error will be printed.

 #  this module is an SECURITY RISK !!
 #                    ŻŻŻŻŻŻŻŻŻŻŻŻŻ
 #  - you shouldn't map your docroot to /usr/bin!
 #  - choose carefully which programs to make available for remote control
 #  - you're encouraged to set LD_PRELOAD to insert some security
 #    library wrapping around the system calls
 #  - you should try to chown your programs "nobody" and make them suid
 #  - you should time-limit the executed programs ("timeout", "stopafter")

 #  X11env = LD_LIBRARY_PATH=/lib:/usr/lib/:/usr/local/lib
 #  X11env = LD_PRELOAD=restrict.so
 #  X11env = PATH=/usr/local/bin
 #  X11prepend =  nohup  stopafter 600 SIGKILL



class mod_X11 {

	function mod_X11() {

		$this->modtype = "core_after_decode";
                $this->modname = "X11 app starting support";

	}

	function main() {

		global $conf, $vhost, $htreq_headers, $http_uri, $add_errmsg, $rq_err, $pri_err, $lf;

		$prog = realpath($conf[$vhost]["documentroot"][0] . "/" . $http_uri);
		if (is_executable($prog)) {

			// check for "ELF", "MZ"
			if ($f = fopen($prog, "r")) {
				$d = fread($f, 4);
				fclose($f);
				if ((substr($d, 1, 3) != "ELF") && (substr($d, 0, 2) != "MZ")) {
					return;
				}
			}

			// don't start anything that root owns
			if ((!fileowner($prog)) && ((fileperms($prog) & 0x7fff) > 0755)) {
				$add_errmsg = "Starting of X11 program not allowed.<br><br>";
				return($pri_err = 403);
			}

			// name of remote display
			$nsv = nw_server_vars();
			foreach (array("HTTP_X_FORWARDED_FOR", "X_FORWARDED_FOR", "REMOTE_HOST", "REMOTE_ADDR") as $HTTP_VAR) {
				if (($REMOTE = $nsv[$HTTP_VAR]) || ($REMOTE = $htreq_headers[$HTTP_VAR])) {
					break;
				}
			}
			$DISPLAY = $REMOTE . ":0";

			chdir($HOME = dirname($prog));
			$prog = basename($prog);

			// try to guess if X11 is running on remote host
			$x11tests = 0;
			if ($htreq_headers["X_FORWARDED_FOR"]) $x11tests++;
			if (strpos($htreq_headers["USER-AGENT"], "X11")!==false) $x11tests++;
			if ($s = fsockopen($REMOTE, 6000, $errno, $errstr, 12)) { $x11tests++; fclose($s); }

			if ($x11tests) {
				// put some vars into environment
				putenv("HOME=".$HOME);
				putenv("DISPLAY=".$DISPLAY);
				if ($l = $htreq_headers["ACCEPT-LANGUAGE"]) {
					$langs = array();
					foreach (explode(",", $l) as $l) {
						list($l) = explode(";", $l, 2);
						$langs[] = trim($l);
					}
					putenv("LANG=".$langs[0]);
					putenv("LANGUAGE=".implode(":",$langs));
				}
				foreach (access_query("x11env") as $setenv) {
					putenv($setenv);
				}

				// security
				$PREPEND = access_query("x11prepend", 0);

				// FINALLY run the app
				system($PREPEND . " ./" . $prog . " >/dev/null 2>&1 &");

				// clean up environment
				putenv("DISPLAY=");
				putenv("LANGUAGE=");
				putenv("LANG=");
				putenv("HOME=");
				foreach ($_ENV as $e_key => $e_val) {
					putenv($e_key . "=" . $e_val);
				}

				// "no response"
				$pri_err = 204;

			}
			else {
				$pri_err = 503;
				$add_errmsg = "Your X11 server didn't allow us to connet. Please make sure that it listens on TCP (see /etc/X11/xinitrc/...) and that access will be granted (<tt><b>xhost +</b></tt>).<br><br>Please note that the 'X Window System Version 11' network layer is commonly not available in Microsoft Windows; you need to install an appropriate extension to use this service.<br><br>";
			}


			
		}

	}

}

?>