Skip to content

Commit

Permalink
Server: Fix inetd service issues
Browse files Browse the repository at this point in the history
... introduced when we migrated to the xorg-server 1.19.x code base
in TurboVNC 2.2 (a661ed1).

- Use dup() to obtain a free file descriptor for the inetd socket rather
  than statically assigning FD 3.  Otherwise, if Xvnc calls a function
  (such as getpwuid()) that invokes libnss_sss prior to calling
  ddxProcessArgument(), then libnss_sss will obtain the first free file
  descriptor (3) for its own purposes, ddxProcessArgument() will clobber
  that file descriptor, and hilarity will ensue.  TurboVNC doesn't
  currently make an early call to a function that invokes libnss_sss,
  but referring to TigerVNC/tigervnc#1709,
  TigerVNC does.  It is possible that we will do so in the future.

  Based on:
  TigerVNC/tigervnc@7a9773a

- 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.
  (Symptomatically, that caused the TurboVNC Server, when used with the
  -inetd option, to do nothing when a VNC viewer connected.)

  Based on:
  TigerVNC/tigervnc@712cf86

- Move the inetd RFB connection code from ProcessInputEvents() to the
  end of InitInput(), since ProcessInputEvents() isn't usually called
  until/unless a window manager is started.  (Symptomatically, that also
  caused the TurboVNC Server, when used with the -inetd option, to do
  nothing when a VNC viewer connected.)

Probably fixes #303
  • Loading branch information
dcommander committed Sep 17, 2024
1 parent 5eb457c commit c7349fe
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 15 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ disable the server-side key mapping feature introduced in 3.1 beta1[4].
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
=====
Expand Down
43 changes: 28 additions & 15 deletions unix/Xvnc/programs/Xserver/hw/vnc/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,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;
Expand All @@ -278,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;
}
Expand Down Expand Up @@ -1144,6 +1157,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)
Expand All @@ -1169,6 +1183,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;
}
}


Expand Down Expand Up @@ -1466,12 +1485,6 @@ Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)

void ProcessInputEvents(void)
{
static Bool inetdInitDone = FALSE;

if (!inetdInitDone && inetdSock != -1) {
rfbNewClientConnection(inetdSock);
inetdInitDone = TRUE;
}
mieqProcessInputEvents();
}

Expand Down

0 comments on commit c7349fe

Please sign in to comment.