summaryrefslogtreecommitdiffstats
path: root/x11vnc/misc/blockdpy.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/misc/blockdpy.c')
-rw-r--r--x11vnc/misc/blockdpy.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/x11vnc/misc/blockdpy.c b/x11vnc/misc/blockdpy.c
new file mode 100644
index 0000000..f3b428e
--- /dev/null
+++ b/x11vnc/misc/blockdpy.c
@@ -0,0 +1,352 @@
+/*
+ * blockdpy.c
+ *
+ * Copyright (c) 2004 Karl J. Runge <runge@karlrunge.com>
+ * All rights reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ *-----------------------------------------------------------------------
+ *
+ * This tool is intended for use with x11vnc. It is a kludge to try to
+ * "block" access via the physical display while x11vnc is running.
+ *
+ * The expected application is that of a user who screen-locks his
+ * workstation before leaving and then later unlocks it remotely via
+ * x11vnc. The user is concerned people with physical access to the
+ * machine will be watching, etc.
+ *
+ * Of course if people have physical access to the machine there are
+ * much larger potential security problems, but the idea here is to put
+ * up a larger barrier than simply turning on the monitor and tapping
+ * the mouse (i.e. to wake up the monitor from DPMS and then observe
+ * the x11vnc activity).
+ *
+ * This program requires DPMS support in the video card and monitor,
+ * and the DPMS extension in the X server and the corresponding
+ * library with the DPMS API (libXext).
+ *
+ * It starts off by forcing the state to be DPMSModeOff (lowest power).
+ * Then it periodically (a few times a second) checks if the system is
+ * still in that state. If it discovers it to be in another state, it
+ * immediately runs, as a separate command, a screen-lock program, "xlock"
+ * by default. The environment variable XLOCK_CMD or -lock option can
+ * override this default. "xscreensaver-command" might be another choice.
+ *
+ * It is up to the user to make sure the screen-lock command works
+ * and PATH is set up correctly, etc. The command can do anything,
+ * it doesn't have to lock the screen. It could make the sound of a
+ * dog barking, for example :-)
+ *
+ * The option '-grab' causes the program to additionally call
+ * XGrabServer() to try to prevent physical mouse or keyboard input to get
+ * to any applications on the screen. NOTE: do NOT use, not working yet!
+ * Freezes everything.
+ *
+ * The options: -display and -auth can be used to set the DISPLAY and
+ * XAUTHORITY environment variables via the command line.
+ *
+ * The options -standby and -suspend change the desired DPMS level
+ * to be DPMSModeStandby and DPMSModeSuspend, respectively.
+ *
+ * The option '-f flagfile' indicates a flag file to watch for to cause
+ * the program to clean up and exit once it exists. No screen locking is
+ * done when the file appears: it is an 'all clear' flag. Presumably the
+ * x11vnc user has relocked the screen before the flagfile is created.
+ * See below for coupling this behavior with the -gone command.
+ *
+ * The option '-bg' causes the program to fork into the background and
+ * return 0 if everything looks ok. If there was an error up to that
+ * point the return value would be 1.
+ *
+ * Option '-v' prints more info out, useful for testing and debugging.
+ *
+ *
+ * These options allow this sort of x11vnc usage:
+ *
+ * x11vnc ... -accept "blockdpy -bg -f $HOME/.bdpy" -gone "touch $HOME/.bdpy"
+ *
+ * (this may also work for gone: -gone "killall blockdpy")
+ *
+ * In the above, once a client connects this program starts up in the
+ * background and monitors the DPMS level. When the client disconnects
+ * (he relocked the screen before doing so) the flag file is created and
+ * so this program exits normally. On the other hand, if the physical
+ * mouse or keyboard was used during the session, this program would
+ * have locked the screen as soon as it noticed the DPMS change.
+ *
+ * One could create shell scripts for -accept and -gone that do much
+ * more sophisticated things. This would be needed if more than one
+ * client connects at a time.
+ *
+ * It is important to remember once this program locks the screen
+ * it *exits*, so nothing will be watching the screen at that point.
+ * Don't immediately unlock the screen from in x11vnc!! Best to think
+ * about what might have happened, disconnect the VNC viewer, and then
+ * restart x11vnc (thereby having this monitoring program started again).
+ *
+ *
+ * To compile on Linux or Solaris:
+
+ cc -o blockdpy blockdpy.c -L /usr/X11R6/lib -L /usr/openwin/lib -lX11 -lXext
+
+ * (may also need -I /usr/.../include on older machines).
+ *
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/dpms.h>
+
+Display *dpy = NULL;
+CARD16 standby, suspend, off;
+int grab = 0;
+int verbose = 0;
+int bg = 0;
+
+/* for sleeping some number of millisecs */
+struct timeval _mysleep;
+#define msleep(x) \
+ _mysleep.tv_sec = ((x)*1000) / 1000000; \
+ _mysleep.tv_usec = ((x)*1000) % 1000000; \
+ select(0, NULL, NULL, NULL, &_mysleep);
+
+/* called on signal or if DPMS changed, or other problem */
+void reset(int sig) {
+ if (grab) {
+ if (verbose) {
+ fprintf(stderr, "calling XUngrabServer()\n");
+ }
+ XUngrabServer(dpy);
+ }
+ if (verbose) {
+ fprintf(stderr, "resetting original DPMS values.\n");
+ }
+ fprintf(stderr, "blockdpy: reset sig=%d called\n", sig);
+ DPMSEnable(dpy);
+ DPMSSetTimeouts(dpy, standby, suspend, off);
+ XFlush(dpy);
+ if (sig) {
+ XCloseDisplay(dpy);
+ exit(0);
+ }
+}
+
+int main(int argc, char** argv) {
+
+ int verbose = 0, bg = 0;
+ int i, ev, er;
+ char *lock_cmd = "xlock";
+ char *flag_file = NULL;
+ char estr[100], cmd[500];
+ struct stat sbuf;
+ CARD16 power;
+ CARD16 desired = DPMSModeOff;
+ BOOL state;
+
+
+ /* setup the lock command. it may be reset by -lock below. */
+ if (getenv("XLOCK_CMD")) {
+ lock_cmd = (char *) getenv("XLOCK_CMD");
+ }
+
+ /* process cmd line: */
+ for (i=1; i<argc; i++) {
+ if (!strcmp(argv[i], "-display")) {
+ sprintf(estr, "DISPLAY=%s", argv[++i]);
+ putenv(strdup(estr));
+ } else if (!strcmp(argv[i], "-auth")) {
+ sprintf(estr, "XAUTHORITY=%s", argv[++i]);
+ putenv(strdup(estr));
+ } else if (!strcmp(argv[i], "-lock")) {
+ lock_cmd = argv[++i];
+ } else if (!strcmp(argv[i], "-f")) {
+ flag_file = argv[++i];
+ unlink(flag_file);
+ } else if (!strcmp(argv[i], "-grab")) {
+ grab = 1;
+ } else if (!strcmp(argv[i], "-bg")) {
+ bg = 1;
+ } else if (!strcmp(argv[i], "-v")) {
+ verbose = 1;
+ } else if (!strcmp(argv[i], "-standby")) {
+ desired = DPMSModeStandby;
+ } else if (!strcmp(argv[i], "-suspend")) {
+ desired = DPMSModeSuspend;
+ } else if (!strcmp(argv[i], "-off")) {
+ desired = DPMSModeOff;
+ }
+ }
+
+ /* we want it to go into background to avoid blocking, so add '&'. */
+ strcpy(cmd, lock_cmd);
+ strcat(cmd, " &");
+ lock_cmd = cmd;
+
+ /* close any file descriptors we may have inherited (e.g. port 5900) */
+ for (i=3; i<=100; i++) {
+ close(i);
+ }
+
+ /* open DISPLAY */
+ dpy = XOpenDisplay(NULL);
+ if (! dpy) {
+ fprintf(stderr, "XOpenDisplay failed.\n");
+ exit(1);
+ }
+
+ /* check for DPMS extension */
+ if (! DPMSQueryExtension(dpy, &ev, &er)) {
+ fprintf(stderr, "DPMSQueryExtension failed.\n");
+ exit(1);
+ }
+ if (! DPMSCapable(dpy)) {
+ fprintf(stderr, "DPMSCapable failed.\n");
+ exit(1);
+ }
+ /* make sure DPMS is enabled */
+ if (! DPMSEnable(dpy)) {
+ fprintf(stderr, "DPMSEnable failed.\n");
+ exit(1);
+ }
+
+ /* retrieve the timeouts for later resetting */
+ if (! DPMSGetTimeouts(dpy, &standby, &suspend, &off)) {
+ fprintf(stderr, "DPMSGetTimeouts failed.\n");
+ exit(1);
+ }
+ if (! standby || ! suspend || ! off) {
+ /* if none, set to some reasonable values */
+ standby = 900;
+ suspend = 1200;
+ off = 1800;
+ }
+ if (verbose) {
+ fprintf(stderr, "DPMS timeouts: %d %d %d\n", standby,
+ suspend, off);
+ }
+
+ /* now set them to very small values */
+ if (desired == DPMSModeOff) {
+ if (! DPMSSetTimeouts(dpy, 1, 1, 1)) {
+ fprintf(stderr, "DPMSSetTimeouts failed.\n");
+ exit(1);
+ }
+ } else if (desired == DPMSModeSuspend) {
+ if (! DPMSSetTimeouts(dpy, 1, 1, 0)) {
+ fprintf(stderr, "DPMSSetTimeouts failed.\n");
+ exit(1);
+ }
+ } else if (desired == DPMSModeStandby) {
+ if (! DPMSSetTimeouts(dpy, 1, 0, 0)) {
+ fprintf(stderr, "DPMSSetTimeouts failed.\n");
+ exit(1);
+ }
+ }
+ XFlush(dpy);
+
+ /* set handlers for clean up in case we terminate via signal */
+ signal(SIGHUP, reset);
+ signal(SIGINT, reset);
+ signal(SIGQUIT, reset);
+ signal(SIGABRT, reset);
+ signal(SIGTERM, reset);
+
+ /* force state into DPMS Off (lowest power) mode */
+ if (! DPMSForceLevel(dpy, desired)) {
+ fprintf(stderr, "DPMSForceLevel failed.\n");
+ exit(1);
+ }
+ XFlush(dpy);
+
+ /* read state */
+ msleep(500);
+ if (! DPMSInfo(dpy, &power, &state)) {
+ fprintf(stderr, "DPMSInfo failed.\n");
+ exit(1);
+ }
+ fprintf(stderr, "power: %d state: %d\n", power, state);
+
+ /* grab display if desired. NOT WORKING */
+ if (grab) {
+ if (verbose) {
+ fprintf(stderr, "calling XGrabServer()\n");
+ }
+ XGrabServer(dpy);
+ }
+
+ /* go into background if desired. */
+ if (bg) {
+ pid_t p;
+ if ((p = fork()) != 0) {
+ if (p < 0) {
+ fprintf(stderr, "problem forking.\n");
+ exit(1);
+ } else {
+ /* XXX no fd closing */
+ exit(0);
+ }
+ }
+ }
+
+ /* main loop: */
+ while (1) {
+ /* reassert DPMSModeOff (desired) */
+ if (verbose) fprintf(stderr, "reasserting desired DPMSMode\n");
+ DPMSForceLevel(dpy, desired);
+ XFlush(dpy);
+
+ /* wait a bit */
+ msleep(200);
+
+ /* check for flag file appearence */
+ if (flag_file && stat(flag_file, &sbuf) == 0) {
+ if (verbose) {
+ fprintf(stderr, "flag found: %s\n", flag_file);
+ }
+ unlink(flag_file);
+ reset(0);
+ exit(0);
+ }
+
+ /* check state and power level */
+ if (! DPMSInfo(dpy, &power, &state)) {
+ fprintf(stderr, "DPMSInfo failed.\n");
+ reset(0);
+ exit(1);
+ }
+ if (verbose) {
+ fprintf(stderr, "power: %d state: %d\n", power, state);
+ }
+ if (!state || power != desired) {
+ /* Someone (or maybe a cat) is evidently watching... */
+ fprintf(stderr, "DPMS CHANGE: power: %d state: %d\n",
+ power, state);
+ break;
+ }
+ }
+ reset(0);
+ fprintf(stderr, "locking screen with command: \"%s\"\n", lock_cmd);
+ system(lock_cmd);
+ exit(0);
+}