diff --git a/ChangeLog.md b/ChangeLog.md index f3dca2dee..8c893b67c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -59,6 +59,13 @@ deprecated and replaced with a new advanced parameter (`ExtSSHTemplate`.) 1. Added a new Xvnc command-line option (`-noserverkeymap`) that can be used to disable the server-side key mapping feature introduced in 3.1 beta1[4]. +2. Added a new Xvnc command-line option (`-syslog`) that can be used to +redirect all TurboVNC Server and X.org errors, warnings, and messages to the +system log. + +3. Fixed a regression introduced by 2.2 beta1[7] that prevented the TurboVNC +Server from being used as an inetd service. + 3.1.2 ===== diff --git a/common/rfb/rfbproto.h b/common/rfb/rfbproto.h index f984c0201..0c9f87943 100644 --- a/common/rfb/rfbproto.h +++ b/common/rfb/rfbproto.h @@ -1,5 +1,5 @@ -/* Copyright (C) 2009-2010, 2012-2013, 2015, 2022 D. R. Commander. - * All Rights Reserved. +/* Copyright (C) 2009-2010, 2012-2013, 2015, 2022, 2024 D. R. Commander. + * All Rights Reserved. * Copyright (C) 2009 Vic Lee. All Rights Reserved. * Copyright (C) 2004-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright (C) 2000-2006 Constantin Kaplinsky. All Rights Reserved. @@ -534,53 +534,53 @@ typedef struct _rfbInteractionCapsMsg { #define rfbEncodingExtendedClipboard 0xC0A1E5CE -#define rfbEncodingSubsamp1X 0xFFFFFD00 -#define rfbEncodingSubsamp4X 0xFFFFFD01 -#define rfbEncodingSubsamp2X 0xFFFFFD02 -#define rfbEncodingSubsampGray 0xFFFFFD03 -#define rfbEncodingSubsamp8X 0xFFFFFD04 -#define rfbEncodingSubsamp16X 0xFFFFFD05 -#define rfbEncodingFineQualityLevel0 0xFFFFFE00 -#define rfbEncodingFineQualityLevel100 0xFFFFFE64 - -#define rfbEncodingContinuousUpdates 0xFFFFFEC7 -#define rfbEncodingFence 0xFFFFFEC8 - -#define rfbEncodingExtendedDesktopSize 0xFFFFFECC - -#define rfbEncodingGII 0xFFFFFECF - -#define rfbEncodingQEMULEDState 0xFFFFFEFB -#define rfbEncodingQEMUExtendedKeyEvent 0xFFFFFEFE - -#define rfbEncodingCompressLevel0 0xFFFFFF00 -#define rfbEncodingCompressLevel1 0xFFFFFF01 -#define rfbEncodingCompressLevel2 0xFFFFFF02 -#define rfbEncodingCompressLevel3 0xFFFFFF03 -#define rfbEncodingCompressLevel4 0xFFFFFF04 -#define rfbEncodingCompressLevel5 0xFFFFFF05 -#define rfbEncodingCompressLevel6 0xFFFFFF06 -#define rfbEncodingCompressLevel7 0xFFFFFF07 -#define rfbEncodingCompressLevel8 0xFFFFFF08 -#define rfbEncodingCompressLevel9 0xFFFFFF09 - -#define rfbEncodingXCursor 0xFFFFFF10 -#define rfbEncodingRichCursor 0xFFFFFF11 -#define rfbEncodingPointerPos 0xFFFFFF18 - -#define rfbEncodingLastRect 0xFFFFFF20 -#define rfbEncodingNewFBSize 0xFFFFFF21 - -#define rfbEncodingQualityLevel0 0xFFFFFFE0 -#define rfbEncodingQualityLevel1 0xFFFFFFE1 -#define rfbEncodingQualityLevel2 0xFFFFFFE2 -#define rfbEncodingQualityLevel3 0xFFFFFFE3 -#define rfbEncodingQualityLevel4 0xFFFFFFE4 -#define rfbEncodingQualityLevel5 0xFFFFFFE5 -#define rfbEncodingQualityLevel6 0xFFFFFFE6 -#define rfbEncodingQualityLevel7 0xFFFFFFE7 -#define rfbEncodingQualityLevel8 0xFFFFFFE8 -#define rfbEncodingQualityLevel9 0xFFFFFFE9 +#define rfbEncodingSubsamp1X 0xFFFFFD00 /* -768 */ +#define rfbEncodingSubsamp4X 0xFFFFFD01 /* -767 */ +#define rfbEncodingSubsamp2X 0xFFFFFD02 /* -766 */ +#define rfbEncodingSubsampGray 0xFFFFFD03 /* -765 */ +#define rfbEncodingSubsamp8X 0xFFFFFD04 /* -764 */ +#define rfbEncodingSubsamp16X 0xFFFFFD05 /* -763 */ +#define rfbEncodingFineQualityLevel0 0xFFFFFE00 /* -512 */ +#define rfbEncodingFineQualityLevel100 0xFFFFFE64 /* -412 */ + +#define rfbEncodingContinuousUpdates 0xFFFFFEC7 /* -313 */ +#define rfbEncodingFence 0xFFFFFEC8 /* -312 */ + +#define rfbEncodingExtendedDesktopSize 0xFFFFFECC /* -308 */ + +#define rfbEncodingGII 0xFFFFFECF /* -305 */ + +#define rfbEncodingQEMULEDState 0xFFFFFEFB /* -261 */ +#define rfbEncodingQEMUExtendedKeyEvent 0xFFFFFEFE /* -258 */ + +#define rfbEncodingCompressLevel0 0xFFFFFF00 /* -256 */ +#define rfbEncodingCompressLevel1 0xFFFFFF01 /* -255 */ +#define rfbEncodingCompressLevel2 0xFFFFFF02 /* -254 */ +#define rfbEncodingCompressLevel3 0xFFFFFF03 /* -253 */ +#define rfbEncodingCompressLevel4 0xFFFFFF04 /* -252 */ +#define rfbEncodingCompressLevel5 0xFFFFFF05 /* -251 */ +#define rfbEncodingCompressLevel6 0xFFFFFF06 /* -250 */ +#define rfbEncodingCompressLevel7 0xFFFFFF07 /* -249 */ +#define rfbEncodingCompressLevel8 0xFFFFFF08 /* -248 */ +#define rfbEncodingCompressLevel9 0xFFFFFF09 /* -247 */ + +#define rfbEncodingXCursor 0xFFFFFF10 /* -240 */ +#define rfbEncodingRichCursor 0xFFFFFF11 /* -239 */ +#define rfbEncodingPointerPos 0xFFFFFF18 /* -232 */ + +#define rfbEncodingLastRect 0xFFFFFF20 /* -224 */ +#define rfbEncodingNewFBSize 0xFFFFFF21 /* -223 */ + +#define rfbEncodingQualityLevel0 0xFFFFFFE0 /* -32 */ +#define rfbEncodingQualityLevel1 0xFFFFFFE1 /* -31 */ +#define rfbEncodingQualityLevel2 0xFFFFFFE2 /* -30 */ +#define rfbEncodingQualityLevel3 0xFFFFFFE3 /* -29 */ +#define rfbEncodingQualityLevel4 0xFFFFFFE4 /* -28 */ +#define rfbEncodingQualityLevel5 0xFFFFFFE5 /* -27 */ +#define rfbEncodingQualityLevel6 0xFFFFFFE6 /* -26 */ +#define rfbEncodingQualityLevel7 0xFFFFFFE7 /* -25 */ +#define rfbEncodingQualityLevel8 0xFFFFFFE8 /* -24 */ +#define rfbEncodingQualityLevel9 0xFFFFFFE9 /* -23 */ /* signatures for "fake" encoding types */ #define sig_rfbEncodingCompressLevel0 "COMPRLVL" @@ -1041,7 +1041,7 @@ typedef struct { #define rfbLEDScrollLock (1 << 0) #define rfbLEDNumLock (1 << 1) #define rfbLEDCapsLock (1 << 2) -#define rfbLEDUnknown 0xFFFFFFFF +#define rfbLEDUnknown 0xFFFFFFFF /* -1 */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/unix/Xvnc/programs/Xserver/CMakeLists.txt b/unix/Xvnc/programs/Xserver/CMakeLists.txt index a0d52fdce..769d7371a 100644 --- a/unix/Xvnc/programs/Xserver/CMakeLists.txt +++ b/unix/Xvnc/programs/Xserver/CMakeLists.txt @@ -58,6 +58,11 @@ foreach(typeof typeof __typeof__) break() endif() endforeach() +check_symbol_exists(syslog syslog.h HAVE_SYSLOG) +check_symbol_exists(vsyslog syslog.h HAVE_VSYSLOG) +if(HAVE_SYSLOG AND HAVE_VSYSLOG) + add_definitions(-DDDXOSVERRORF) +endif() set(CMAKE_REQUIRED_LIBRARIES rt) check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) if(HAVE_CLOCK_GETTIME) diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/init.c b/unix/Xvnc/programs/Xserver/hw/vnc/init.c index c4370ec4e..c42e7ce60 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/init.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/init.c @@ -65,6 +65,10 @@ from the X Consortium. #include #include #include +#include +#ifdef DDXOSVERRORF +#include +#endif #include #include #include @@ -116,6 +120,9 @@ static Bool noCursor = FALSE; char *desktopName = DEFAULT_DESKTOP_NAME; int traceLevel = 0; int rfbLEDState = (int)rfbLEDUnknown; +#ifdef DDXOSVERRORF +static Bool sysLog = FALSE; +#endif char rfbThisHost[256]; @@ -259,7 +266,8 @@ int ddxProcessArgument(int argc, char *argv[], int i) } if (strcasecmp(argv[i], "-inetd") == 0) { /* -inetd */ - int n; + int n, nullFD; + for (n = 1; n < 100; n++) { if (CheckDisplayNumber(n)) break; @@ -271,14 +279,26 @@ int ddxProcessArgument(int argc, char *argv[], int i) snprintf(inetdDisplayNumStr, 10, "%d", n); display = inetdDisplayNumStr; - /* fds 0, 1 and 2 (stdin, out and err) are all the same socket to the - RFB client. OsInit() closes stdout and stdin, and we don't want - stderr to go to the RFB client, so make the client socket 3 and - close stderr. OsInit() will redirect stderr logging to an - appropriate log file or /dev/null if that doesn't work. */ - dup2(0, 3); - inetdSock = 3; - close(2); + /* FDs 0, 1, and 2 (stdin, stdout, and stderr) are all redirected to the + same socket, which is connected to the RFB client. OsInit() closes + stdin and stdout, so we obtain a new file descriptor for the socket by + duplicating stdin. */ + if ((inetdSock = dup(0)) == -1) + FatalError("-inetd: couldn't allocate a new file descriptor: %s", + strerror(errno)); + + /* We don't want stderr to be redirected to the RFB client, since stderr is + used for logging. (NOTE: The -syslog option redirects most of the + logging to the system log, but it isn't foolproof.) We explicitly + redirect stderr (FD 2) to /dev/null rather than simply closing it. + Otherwise, OsInit() (more specifically ospoll_create()) will obtain the + first free file descriptor (2) to use for polling, then it will check + whether FD 2 (which it assumes is still stderr) is writable. Since + polling file descriptors aren't writable, OsInit() will redirect FD 2 to + /dev/null, thus breaking the polling subsystem. */ + nullFD = open("/dev/null", O_WRONLY); + dup2(nullFD, 2); + close(nullFD); return 1; } @@ -714,6 +734,13 @@ int ddxProcessArgument(int argc, char *argv[], int i) } #endif +#ifdef DDXOSVERRORF + if (strcasecmp(argv[i], "-syslog") == 0) { + sysLog = TRUE; + return 1; + } +#endif + if (strcasecmp(argv[i], "-verbose") == 0) { LogSetParameter(XLOG_VERBOSITY, X_DEBUG); return 1; @@ -1169,6 +1196,7 @@ rfbDevInfo virtualTabletPad = void InitInput(int argc, char *argv[]) { DeviceIntPtr p, k; + static Bool inetdInitDone = FALSE; if (AllocDevicePair(serverClient, "TurboVNC", &p, &k, rfbMouseProc, rfbKeybdProc, FALSE) != Success) @@ -1194,6 +1222,11 @@ void InitInput(int argc, char *argv[]) if (!AddExtInputDevice(&virtualTabletPad)) FatalError("Could not create TurboVNC virtual tablet pad device"); } + + if (!inetdInitDone && inetdSock != -1) { + rfbNewClientConnection(inetdSock); + inetdInitDone = TRUE; + } } @@ -1491,12 +1524,6 @@ Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) void ProcessInputEvents(void) { - static Bool inetdInitDone = FALSE; - - if (!inetdInitDone && inetdSock != -1) { - rfbNewClientConnection(inetdSock); - inetdInitDone = TRUE; - } mieqProcessInputEvents(); } @@ -1702,6 +1729,15 @@ void DDXRingBell(int percent, int pitch, int duration) } +#ifdef DDXOSVERRORF +static void OsVendorVErrorF(const char *f, va_list args) +{ + if (sysLog) + vsyslog(LOG_ERR, f, args); +} +#endif + + void OsVendorInit(void) { InitRFB(); @@ -1736,11 +1772,21 @@ void OsVendorInit(void) rfbAuthPAMSession = FALSE; } #endif +#ifdef DDXOSVERRORF + if (!OsVendorVErrorFProc && sysLog) + OsVendorVErrorFProc = OsVendorVErrorF; +#endif } void OsVendorFatalError(const char *f, va_list args) { +#ifdef DDXOSVERRORF + if (sysLog) { + syslog(LOG_ERR, "Fatal server error:"); + vsyslog(LOG_ERR, f, args); + } +#endif } @@ -1883,6 +1929,9 @@ void ddxUseMsg(void) ErrorF("==============================\n"); #ifndef TURBOVNC_STATIC_XORG_PATHS ErrorF("-registrydir dir specify directory containing protocol.txt\n"); +#endif +#ifdef DDXOSVERRORF + ErrorF("-syslog redirect all errors/warnings/messages to the system log\n"); #endif ErrorF("-verbose print all X.org errors, warnings, and messages\n"); ErrorF("-version report Xvnc version on stderr\n\n"); @@ -1890,7 +1939,8 @@ void ddxUseMsg(void) /* - * rfbLog prints a time-stamped message to the log file (stderr.) + * rfbLog prints a time-stamped message to the log file (stderr or the system + * log.) */ void rfbLog(char *format, ...) @@ -1902,14 +1952,22 @@ void rfbLog(char *format, ...) va_start(args, format); - time(&clock); - strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock)); - for (i = 0; i < traceLevel; i++) - snprintf(&buf[strlen(buf)], 256 - strlen(buf), " "); - fputs(buf, stderr); +#ifdef DDXOSVERRORF + if (sysLog) + /* NOTE: System log entries already have a timestamp. */ + vsyslog(LOG_INFO, format, args); + else +#endif + { + time(&clock); + strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock)); + for (i = 0; i < traceLevel; i++) + snprintf(&buf[strlen(buf)], 256 - strlen(buf), " "); + fputs(buf, stderr); - vfprintf(stderr, format, args); - fflush(stderr); + vfprintf(stderr, format, args); + fflush(stderr); + } va_end(args); } @@ -1917,8 +1975,18 @@ void rfbLog(char *format, ...) void rfbLogPerror(char *str) { - rfbLog(""); - perror(str); +#ifdef DDXOSVERRORF + if (sysLog) { + if (str && strlen(str) > 0) + syslog(LOG_ERR, "%s: %s\n", str, strerror(errno)); + else + syslog(LOG_ERR, "%s\n", strerror(errno)); + } else +#endif + { + rfbLog(""); + perror(str); + } } diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h b/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h index 7300aeb0d..75e7542e9 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h +++ b/unix/Xvnc/programs/Xserver/hw/vnc/rfb.h @@ -699,7 +699,7 @@ extern int traceLevel; /* * Print a time-stamped message, prefixed by the client ID, to the log file - * (stderr.) + * (stderr or the system log.) */ #define RFBLOGID(format, ...) rfbLog("[%u] " format, cl->id, ##__VA_ARGS__) diff --git a/unix/Xvnc/programs/Xserver/hw/vnc/rfbssl_openssl.c b/unix/Xvnc/programs/Xserver/hw/vnc/rfbssl_openssl.c index c2672cb38..2505d4e14 100644 --- a/unix/Xvnc/programs/Xserver/hw/vnc/rfbssl_openssl.c +++ b/unix/Xvnc/programs/Xserver/hw/vnc/rfbssl_openssl.c @@ -335,7 +335,7 @@ static void rfbErr(const char *format, ...) static void rfbssl_error(const char *function) { - char buf[1024]; + char buf[BUFSIZE]; unsigned long e = crypto.ERR_get_error(); while (e) { @@ -354,6 +354,7 @@ rfbSslCtx *rfbssl_init(rfbClientPtr cl, Bool anon) DSA *dsa = NULL; int flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3, priority = 0; const char *list = NULL; + char buf[BUFSIZE]; #ifdef DLOPENSSL if (loadFunctions() == -1) @@ -443,14 +444,15 @@ rfbSslCtx *rfbssl_init(rfbClientPtr cl, Bool anon) rfbssl_error("SSL_new()"); goto bailout; } - RFBLOGID("Available cipher suites: "); + snprintf(buf, BUFSIZE, "Available cipher suites: "); list = ssl.SSL_get_cipher_list(ctx->ssl, priority++); while (list) { - fprintf(stderr, "%s", list); + snprintf(&buf[strlen(buf)], BUFSIZE - strlen(buf), "%s", list); list = ssl.SSL_get_cipher_list(ctx->ssl, priority++); - if (list) fprintf(stderr, ":"); + if (list) snprintf(&buf[strlen(buf)], BUFSIZE - strlen(buf), ":"); } - fprintf(stderr, "\n"); + snprintf(&buf[strlen(buf)], BUFSIZE - strlen(buf), "\n"); + RFBLOGID("%s", buf); if (!(ssl.SSL_set_fd(ctx->ssl, cl->sock))) { rfbssl_error("SSL_set_fd()"); goto bailout;