diff -urNb vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/auth.c vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/auth.c
--- vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/auth.c	2002-09-01 17:58:21.000000000 +0200
+++ vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/auth.c	2007-06-11 19:22:04.000000000 +0200
@@ -36,12 +36,18 @@
 					      over MAX_AUTH_TRIES */
 
 static int rfbAuthFailure();
+static int rfbReadOnlyAuthFailure();
 static CARD32 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg);
+static CARD32 rfbReadOnlyAuthReenable(OsTimerPtr timerReadOnly, CARD32 now, pointer arg);
 
 char *rfbAuthPasswdFile = NULL;
+char *rfbReadOnlyAuthPasswdFile = NULL;
 int rfbAuthTries = 0;
+int rfbReadOnlyAuthTries = 0;
 Bool rfbAuthTooManyTries = FALSE;
+Bool rfbReadOnlyAuthTooManyTries = FALSE;
 static OsTimerPtr timer = NULL;
+static OsTimerPtr timerReadOnly = NULL;
 
 
 /*
@@ -85,6 +91,45 @@
     }
 }
 
+/* rfbAuthNewReadOnlyClient is called when we reach the point of authenticating
+ * a new read only client.  As authentication isn't being used we simply send
+ * rfbNoAuth.
+ */
+
+void
+rfbAuthNewReadOnlyClient(cl)
+	rfbClientPtr cl;
+{	
+	char buf[4 + CHALLENGESIZE];
+	int len;
+    
+	cl->state = RFB_AUTHENTICATION;
+
+	if (rfbReadOnlyAuthPasswdFile && !cl->reverseConnection) {
+
+		if (rfbReadOnlyAuthTooManyTries) {
+			rfbClientConnFailed(cl, "Too many authentication failures on read only port");
+			return;
+		}
+    	
+		*(CARD32 *)buf = Swap32IfLE(rfbVncAuth);
+		vncRandomBytes(cl->authChallenge);
+		memcpy(&buf[4], (char *)cl->authChallenge, CHALLENGESIZE);
+		len = 4 + CHALLENGESIZE;
+    	
+	} else {
+    
+		*(CARD32 *)buf = Swap32IfLE(rfbNoAuth);
+		len = 4;
+		cl->state = RFB_INITIALISATION;
+	}
+    
+	if (WriteExact(cl->sock, buf, len) < 0) {
+		rfbLogPerror("rfbAuthNewReadOnlyClient: write");
+		rfbCloseSock(cl->sock);
+		return;
+	}
+}
 
 /*
  * rfbAuthProcessClientMessage is called when the client sends its
@@ -107,16 +152,20 @@
             rfbLog("rfbAuthProcessClientMessage: read failed\n");
         else
 	    rfbLogPerror("rfbAuthProcessClientMessage: read");
-        rfbAuthFailure();
+    	if(!cl->readOnly) rfbAuthFailure();
+    	else rfbReadOnlyAuthFailure();
 	rfbCloseSock(cl->sock);
 	return;
     }
 
-    passwd = vncDecryptPasswdFromFile(rfbAuthPasswdFile);
+    if (!cl->readOnly) passwd = vncDecryptPasswdFromFile(rfbAuthPasswdFile);
+    else passwd = vncDecryptPasswdFromFile(rfbReadOnlyAuthPasswdFile);
 
     if (passwd == NULL) {
-	rfbLog("rfbAuthProcessClientMessage: could not get password from %s\n",
+    	if (!cl->readOnly) rfbLog("rfbAuthProcessClientMessage: could not get password from %s\n",
 	       rfbAuthPasswdFile);
+    	else rfbLog("rfbAuthProcessClientMessage: could not get (read-only) password from %s\n",
+    			rfbReadOnlyAuthPasswdFile);
 
 	authResult = Swap32IfLE(rfbVncAuthFailed);
 
@@ -140,7 +189,8 @@
 	rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
 	       cl->host);
 
-        authResult = rfbAuthFailure();
+        if (!cl->readOnly) authResult = rfbAuthFailure();
+        else authResult = rfbReadOnlyAuthFailure();
         authResult = Swap32IfLE(authResult);
 
 	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
@@ -150,7 +200,8 @@
 	return;
     }
 
-    rfbAuthTries = 0;
+    if (!cl->readOnly) rfbAuthTries = 0;
+    else rfbReadOnlyAuthTries = 0;
 
     authResult = Swap32IfLE(rfbVncAuthOK);
 
@@ -184,6 +235,25 @@
   return rfbVncAuthFailed;
 }
 
+static int rfbReadOnlyAuthFailure()
+{
+  int i;
+
+  rfbReadOnlyAuthTries++;
+
+  if (rfbReadOnlyAuthTries >= MAX_AUTH_TRIES) {
+
+    CARD32 delay = AUTH_TOO_MANY_BASE_DELAY;
+    for (i = MAX_AUTH_TRIES; i < rfbReadOnlyAuthTries; i++)
+      delay *= 2;
+    timerReadOnly = TimerSet(timerReadOnly, 0, delay, rfbReadOnlyAuthReenable, NULL);
+
+    rfbReadOnlyAuthTooManyTries = TRUE;
+    return rfbVncAuthTooMany;
+  }
+
+  return rfbVncAuthFailed;
+}
 
 static CARD32
 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg)
@@ -191,3 +261,10 @@
     rfbAuthTooManyTries = FALSE;
     return 0;
 }
+
+static CARD32
+rfbReadOnlyAuthReenable(OsTimerPtr timerReadOnly, CARD32 now, pointer arg)
+{
+    rfbReadOnlyAuthTooManyTries = FALSE;
+    return 0;
+}
diff -urNb vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/init.c vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/init.c
--- vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/init.c	2003-02-28 19:47:10.000000000 +0100
+++ vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/init.c	2007-06-11 19:25:10.000000000 +0200
@@ -213,6 +213,19 @@
 	return 2;
     }
 
+    if (strcasecmp(argv[i], "-readonlyport") == 0) {	/* -readonlyport port */
+    	if (i + 1 >= argc) UseMsg();
+    	readOnlyPort = atoi(argv[i+1]);
+    	rfbAlwaysShared = TRUE;
+    	return 2;
+    }
+    
+    if (strcasecmp(argv[i], "-readonlymsg") == 0) {	/* -readonlymsg msg */
+    	if (i + 1 >= argc) UseMsg();
+    	readOnlyMsg = argv[i+1];
+    	return 2;
+    }
+    
     if (strcasecmp(argv[i], "-rfbport") == 0) {	/* -rfbport port */
 	if (i + 1 >= argc) UseMsg();
 	rfbPort = atoi(argv[i+1]);
@@ -236,6 +249,12 @@
 	return 2;
     }
 
+    if (strcasecmp(argv[i], "-readonlyauth") == 0) {	/* -readonlyauth passwd-file */
+    	if (i + 1 >= argc) UseMsg();
+    	rfbReadOnlyAuthPasswdFile = argv[i+1];
+    	return 2;
+    }
+
     if (strcasecmp(argv[i], "-httpd") == 0) {
 	if (i + 1 >= argc) UseMsg();
 	httpDir = argv[i+1];
@@ -874,6 +893,12 @@
     ErrorF("-nocursor              don't put up a cursor\n");
     ErrorF("-rfbauth passwd-file   use authentication on RFB protocol\n");
     ErrorF("-httpd dir             serve files via HTTP from here\n");
+    ErrorF("-readonlyport port     port for read-only RFB\n");
+    ErrorF("-readonlymsg msg       message to alert authenticated user that\n"
+           "                       the readonly port is active.\n");
+    ErrorF("-readonlyauth passwd-file use authentication on RFB protocol\n"
+    		"						for the read-only port\n");
+
     ErrorF("-httpport port         port for HTTP\n");
     ErrorF("-deferupdate time      time in ms to defer updates "
 							     "(default 40)\n");
diff -urNb vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/rfb.h vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/rfb.h
--- vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/rfb.h	2003-02-28 19:47:10.000000000 +0100
+++ vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/rfb.h	2007-06-11 19:22:04.000000000 +0200
@@ -133,6 +133,8 @@
 	RFB_NORMAL		/* normal protocol messages */
     } state;
 
+    Bool readOnly;
+    
     Bool reverseConnection;
 
     Bool readyForSetColourMapEntries;
@@ -293,6 +295,10 @@
 
 extern int rfbMaxClientWait;
 
+extern int readOnlyPort;
+extern int readOnlyListenSock;
+extern char *readOnlyMsg;
+
 extern int rfbPort;
 extern int rfbListenSock;
 extern Bool rfbLocalhostOnly;
@@ -418,9 +424,11 @@
 /* auth.c */
 
 extern char *rfbAuthPasswdFile;
+extern char *rfbReadOnlyAuthPasswdFile;
 extern Bool rfbAuthenticating;
 
 extern void rfbAuthNewClient(rfbClientPtr cl);
+extern void rfbAuthNewReadOnlyClient(rfbClientPtr cl);
 extern void rfbAuthProcessClientMessage(rfbClientPtr cl);
 
 
diff -urNb vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/rfbserver.c vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/rfbserver.c
--- vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/rfbserver.c	2003-02-28 19:47:10.000000000 +0100
+++ vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/rfbserver.c	2007-06-11 19:22:04.000000000 +0200
@@ -53,6 +53,8 @@
 Bool rfbDontDisconnect = FALSE;
 int rfbMaxRects = 50;
 
+char *readOnlyMsg = "READONLY PORT ACTIVIATED";
+
 static rfbClientPtr rfbNewClient(int sock);
 static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
 static void rfbProcessClientNormalMessage(rfbClientPtr cl);
@@ -72,6 +74,27 @@
     rfbClientPtr cl;
 
     cl = rfbNewClient(sock);
+    cl->readOnly = 0;
+
+#ifdef CORBA
+    if (cl != NULL)
+    newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+}
+
+/*  
+ * rfbNewReadOnlyClientConnection is called from sockets.c when a new
+ * read-only connection comes in.
+ */
+
+void
+rfbNewReadOnlyClientConnection(sock)
+	int sock;
+{
+	rfbClientPtr cl;
+
+	cl = rfbNewClient(sock);
+	cl->readOnly = 1;
 
 #ifdef CORBA
     if (cl != NULL)
@@ -324,8 +347,8 @@
 	/* Minor version mismatch - warn but try to continue */
 	rfbLog("Ignoring minor version mismatch\n");
     }
-
-    rfbAuthNewClient(cl);
+    if (cl->readOnly) rfbAuthNewReadOnlyClient(cl);
+    else rfbAuthNewClient(cl);
 }
 
 
@@ -364,11 +387,12 @@
     rfbClientPtr cl;
 {
     rfbClientInitMsg ci;
-    char buf[256];
-    rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
+    char *buf;
+    rfbServerInitMsg *si;
     struct passwd *user;
     int len, n;
     rfbClientPtr otherCl, nextCl;
+    char *format, *msg;
 
     if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
 	if (n == 0)
@@ -379,34 +403,62 @@
 	return;
     }
 
-    si->framebufferWidth = Swap16IfLE(rfbScreen.width);
-    si->framebufferHeight = Swap16IfLE(rfbScreen.height);
-    si->format = rfbServerFormat;
-    si->format.redMax = Swap16IfLE(si->format.redMax);
-    si->format.greenMax = Swap16IfLE(si->format.greenMax);
-    si->format.blueMax = Swap16IfLE(si->format.blueMax);
-
     user = getpwuid(getuid());
 
     if (strlen(desktopName) > 128)	/* sanity check on desktop name len */
 	desktopName[128] = 0;
 
+    #define FORMAT1 "%s's %s desktop (%s:%s) %s"
+    #define FORMAT2 "%s desktop (%s:%s) %s"
+    
+    if (!cl->readOnly && readOnlyMsg != NULL && readOnlyListenSock >= 0)
+    {
+    	msg = readOnlyMsg;
+    }
+    else msg = "";
+
+    if (user) format = FORMAT1;
+    else format = FORMAT2;
+
+    len = sz_rfbServerInitMsg + strlen(format) +
+    strlen(user->pw_name) + strlen(desktopName) +
+    strlen(rfbThisHost) + strlen(display) +
+    strlen(msg);
+
+    buf = (char *)malloc(len + 100); /* mmmm paranoid */
+
     if (user) {
-	sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
-		user->pw_name, desktopName, rfbThisHost, display);
+	sprintf(buf + sz_rfbServerInitMsg, FORMAT1,
+		user->pw_name, desktopName, rfbThisHost, display, msg);
     } else {
-	sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
-		desktopName, rfbThisHost, display);
+	sprintf(buf + sz_rfbServerInitMsg, FORMAT2,
+		desktopName, rfbThisHost, display, msg);
     }
+    
+    si = (rfbServerInitMsg *)buf;
+    
     len = strlen(buf + sz_rfbServerInitMsg);
     si->nameLength = Swap32IfLE(len);
 
+    si->framebufferWidth = Swap16IfLE(rfbScreen.width);
+    si->framebufferHeight = Swap16IfLE(rfbScreen.height);
+    si->format = rfbServerFormat;
+    si->format.redMax = Swap16IfLE(si->format.redMax);
+    si->format.greenMax = Swap16IfLE(si->format.greenMax);
+    si->format.blueMax = Swap16IfLE(si->format.blueMax);
+
+
     if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
 	rfbLogPerror("rfbProcessClientInitMessage: write");
 	rfbCloseSock(cl->sock);
+	free(buf);
 	return;
     }
 
+    free(buf);
+    buf = NULL;
+    si = NULL;
+    
     cl->state = RFB_NORMAL;
 
     if (!cl->reverseConnection &&
@@ -650,6 +702,7 @@
 	if (!isKeyboardEnabled(cl))
 	    return;
 #endif
+	if (!cl->readOnly)
 	KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
 	return;
 
@@ -681,6 +734,7 @@
 	else
 	    pointerClient = cl;
 
+	if (!cl->readOnly)
 	PtrAddEvent(msg.pe.buttonMask,
 		    Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
 	return;
@@ -708,6 +762,7 @@
 	    return;
 	}
 
+	if (!cl->readOnly)
 	rfbSetXCutText(str, msg.cct.length);
 
 	xfree(str);
diff -urNb vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/sockets.c vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/sockets.c
--- vnc-3.3.7/Xvnc/programs/Xserver/hw/vnc/sockets.c	2007-06-09 22:27:05.000000000 +0200
+++ vnc-3.3.7.readonly/Xvnc/programs/Xserver/hw/vnc/sockets.c	2007-06-11 19:22:04.000000000 +0200
@@ -61,6 +61,9 @@
 int rfbListenSock = -1;
 Bool rfbLocalhostOnly = FALSE;
 
+int readOnlyPort = 0;
+int readOnlyListenSock = -1;
+
 static fd_set allFds;
 static int maxFd = 0;
 
@@ -117,6 +120,17 @@
     FD_ZERO(&allFds);
     FD_SET(rfbListenSock, &allFds);
     maxFd = rfbListenSock;
+    
+    if (readOnlyPort != 0) {
+    	rfbLog("rfbInitSockets: listening for readonly connections on %d\n",readOnlyPort);
+    	if ((readOnlyListenSock = ListenOnTCPPort(readOnlyPort)) < 0) {
+    		rfbLogPerror("ListenOnTCPPort(read-only)");
+    		exit(1);
+    	}
+    	AddEnabledDevice(readOnlyListenSock);
+    	FD_SET(readOnlyListenSock, &allFds);
+    	maxFd = max(readOnlyListenSock,maxFd);
+    }
 }
 
 
@@ -143,7 +157,6 @@
 	rfbNewClientConnection(inetdSock); 
 	inetdInitDone = TRUE;
     }
-
     memcpy((char *)&fds, (char *)&allFds, sizeof(fd_set));
     tv.tv_sec = 0;
     tv.tv_usec = 0;
@@ -155,21 +168,17 @@
 	rfbLogPerror("rfbCheckFds: select");
 	return;
     }
-
     if (rfbListenSock != -1 && FD_ISSET(rfbListenSock, &fds)) {
-
 	if ((sock = accept(rfbListenSock,
 			   (struct sockaddr *)&addr, &addrlen)) < 0) {
 	    rfbLogPerror("rfbCheckFds: accept");
 	    return;
 	}
-
 	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
 	    rfbLogPerror("rfbCheckFds: fcntl");
 	    close(sock);
 	    return;
 	}
-
 	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
 		       (char *)&one, sizeof(one)) < 0) {
 	    rfbLogPerror("rfbCheckFds: setsockopt");
@@ -191,6 +200,41 @@
 	    return;
     }
 
+    if ((readOnlyListenSock != -1) && FD_ISSET(readOnlyListenSock, &fds)) {
+    	if ((sock = accept(readOnlyListenSock,
+    			(struct sockaddr *)&addr, &addrlen)) < 0) {
+    		rfbLogPerror("rfbCheckFds: accept");
+    		return;
+    	}
+	
+    	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+    		rfbLogPerror("rfbCheckFds: fcntl");
+    		close(sock);
+    		return;
+    	}
+    		
+    	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+    			(char *)&one, sizeof(one)) < 0) {
+    		rfbLogPerror("rfbCheckFds: setsockopt");
+    		close(sock);
+    		return;
+    	}
+	
+    	fprintf(stderr,"\n");
+    	rfbLog("Got read-only connection from client %s\n",
+    			inet_ntoa(addr.sin_addr));
+
+    	AddEnabledDevice(sock);
+    	FD_SET(sock, &allFds);
+    	maxFd = max(sock,maxFd);
+	
+    	rfbNewReadOnlyClientConnection(sock);
+	
+    	FD_CLR(rfbListenSock, &fds);
+    	if (--nfds == 0)
+    		return;
+    }
+    
     for (sock = 0; sock <= maxFd; sock++) {
 	if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &allFds)) {
 	    rfbProcessClientMessage(sock);
