]> source.dussan.org Git - tigervnc.git/commitdiff
Start sessions via PAM
authorPierre Ossman <ossman@cendio.se>
Mon, 16 Jul 2018 13:58:06 +0000 (15:58 +0200)
committerPierre Ossman <ossman@cendio.se>
Thu, 12 Mar 2020 11:03:32 +0000 (12:03 +0100)
This sets up a more correct session as there are key tasks that
need to be performed by PAM. E.g. systemd will allocate cgroups
and start base services.

In order to easily handle this as a system service the mapping of
displays is now done via a configuration file.

25 files changed:
CMakeLists.txt
config.h.in
contrib/packages/deb/ubuntu-bionic/debian/rules
contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst [deleted file]
contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst.in [new file with mode: 0644]
contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.prerm
contrib/packages/deb/ubuntu-xenial/debian/rules
contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst [deleted file]
contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst.in [new file with mode: 0644]
contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.prerm
contrib/packages/rpm/el7/SOURCES/tigervnc-shebang.patch [deleted file]
contrib/packages/rpm/el7/SPECS/tigervnc.spec
unix/vncconfig/vncconfig.man
unix/vncpasswd/vncpasswd.man
unix/vncserver/CMakeLists.txt
unix/vncserver/tigervnc.pam [new file with mode: 0644]
unix/vncserver/vncserver.in
unix/vncserver/vncserver.man
unix/vncserver/vncserver.users [new file with mode: 0644]
unix/vncserver/vncserver@.service.in
unix/vncserver/vncsession-start.in [new file with mode: 0644]
unix/vncserver/vncsession.c [new file with mode: 0644]
unix/vncserver/vncsession.man [new file with mode: 0644]
unix/xserver/hw/vnc/Xvnc.man
vncviewer/vncviewer.man

index 5776a9fb0afb5e5c05bbd01dfd3e0b5209003233..540ef944571ad390e101b10bb19afcd87b0f8fe4 100644 (file)
@@ -29,7 +29,9 @@ set(RCVERSION 1,10,80,0)
 # Installation paths
 set(SYSCONF_DIR "${CMAKE_INSTALL_PREFIX}/etc")
 set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin")
+set(SBIN_DIR "${CMAKE_INSTALL_PREFIX}/sbin")
 set(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share")
+set(LIBEXEC_DIR "${CMAKE_INSTALL_PREFIX}/libexec")
 set(MAN_DIR "${DATA_DIR}/man")
 set(LOCALE_DIR "${DATA_DIR}/locale")
 set(DOC_DIR "${CMAKE_INSTALL_PREFIX}/share/doc/${CMAKE_PROJECT_NAME}-${VERSION}")
index b6a9fdffbd2f657d4f880e662c0778756fd98f83..ce594829cf2cd69bee1fd629a3a60fb40a430a8c 100644 (file)
@@ -5,6 +5,7 @@
 #cmakedefine HAVE_ACTIVE_DESKTOP_L
 #cmakedefine ENABLE_NLS 1
 
+#cmakedefine LIBEXEC_DIR "@LIBEXEC_DIR@"
 #cmakedefine DATA_DIR "@DATA_DIR@"
 #cmakedefine LOCALE_DIR "@LOCALE_DIR@"
 
index ff6ff18e512cb66e15153102b68f242d5078ed0f..57e8e0ae49713cd48661399e59b6e673a9774341 100644 (file)
@@ -58,6 +58,7 @@ config-stamp: xorg-source-stamp
                -DBUILD_STATIC=off \
                -DCMAKE_INSTALL_PREFIX:PATH=/usr \
                -DSYSCONF_DIR:PATH=/etc \
+               -DLIBEXEC_DIR:PATH=/usr/lib/$(DEB_HOST_MULTIARCH) \
                -DUNIT_DIR:PATH=/lib/systemd/system
        (cd unix/xserver; \
        export PIXMANINCDIR=/usr/include/pixman-1; \
@@ -172,20 +173,24 @@ install: build
                $(CURDIR)/debian/tigervncserver/usr/bin/tigervncconfig
        mv $(CURDIR)/debian/tigervncserver/usr/bin/vncpasswd \
                $(CURDIR)/debian/tigervncserver/usr/bin/tigervncpasswd
-       mv $(CURDIR)/debian/tigervncserver/usr/bin/vncserver \
-               $(CURDIR)/debian/tigervncserver/usr/bin/tigervncserver
        mv $(CURDIR)/debian/tigervncserver/usr/bin/x0vncserver \
                $(CURDIR)/debian/tigervncserver/usr/bin/x0tigervncserver
+       mv $(CURDIR)/debian/tigervncserver/usr/sbin/vncsession \
+               $(CURDIR)/debian/tigervncserver/usr/sbin/tigervncsession
+       mv $(CURDIR)/debian/tigervncserver/usr/lib/$(DEB_HOST_MULTIARCH)/vncserver \
+               $(CURDIR)/debian/tigervncserver/usr/lib/$(DEB_HOST_MULTIARCH)/tigervncserver
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncconfig.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncconfig.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncpasswd.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncpasswd.1
-       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncserver.1 \
-               $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncserver.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/x0vncserver.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/x0tigervncserver.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/Xvnc.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/Xtigervnc.1
+       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man8/vncsession.8 \
+               $(CURDIR)/debian/tigervncserver/usr/share/man/man8/tigervncsession.8
+       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man8/vncserver.8 \
+               $(CURDIR)/debian/tigervncserver/usr/share/man/man8/tigervncserver.8
        # delete development files
        rm -f $(CURDIR)/debian/tigervncserver/usr/lib/xorg/modules/extensions/libvnc.la
        # move viewer files to viewer package, rename on the fly
@@ -216,6 +221,8 @@ install: build
                $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervncserver/
        rm -rf $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/
 #      dh_movefiles
+       sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' \
+               debian/tigervncserver.postinst.in > debian/tigervncserver.postinst
 
 # Build architecture-independent files here.
 # Pass -i to all debhelper commands in this target to reduce clutter.
diff --git a/contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst b/contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst
deleted file mode 100644 (file)
index 32e7ea7..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "configure" ]; then
-    MAN=/usr/share/man/man1
-    BIN=/usr/bin
-    update-alternatives --install \
-       $BIN/vncserver       vncserver       $BIN/tigervncserver 64 \
-       --slave \
-       $MAN/vncserver.1.gz  vncserver.1.gz  $MAN/tigervncserver.1.gz
-    update-alternatives --install \
-       $BIN/Xvnc            Xvnc            $BIN/Xtigervnc 74 \
-       --slave \
-       $MAN/Xvnc.1.gz       Xvnc.1.gz       $MAN/Xtigervnc.1.gz
-    update-alternatives --install \
-       $BIN/x0vncserver     x0vncserver     $BIN/x0tigervncserver 74 \
-       --slave \
-       $MAN/x0vncserver.1.gz x0vncserver.1.gz $MAN/x0tigervncserver.1.gz
-    update-alternatives --install \
-       $BIN/vncpasswd        vncpasswd            $BIN/tigervncpasswd 74 \
-       --slave \
-       $MAN/vncpasswd.1.gz   vncpasswd.1.gz       $MAN/tigervncpasswd.1.gz
-    update-alternatives --install \
-       $BIN/vncconfig       vncconfig       $BIN/tigervncconfig 64 \
-       --slave \
-       $MAN/vncconfig.1.gz  vncconfig.1.gz  $MAN/tigervncconfig.1.gz
-fi
-
-#DEBHELPER#
-
-exit 0
diff --git a/contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst.in b/contrib/packages/deb/ubuntu-bionic/debian/tigervncserver.postinst.in
new file mode 100644 (file)
index 0000000..2491329
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+set -e
+
+if [ "$1" = "configure" ]; then
+    MAN=/usr/share/man
+    BIN=/usr/bin
+    SBIN=/usr/sbin
+    LIB=/usr/lib/@DEB_HOST_MULTIARCH@
+    update-alternatives --install \
+       $SBIN/vncsession          vncsession      $SBIN/tigervncsession 64 \
+       --slave \
+       $LIB/vncserver            vncserver       $LIB/tigervncserver \
+       --slave \
+       $MAN/man8/vncsession.8.gz vncsession.8.gz $MAN/man8/tigervncsession.8.gz \
+       --slave \
+       $MAN/man8/vncserver.8.gz  vncserver.8.gz  $MAN/man8/tigervncserver.8.gz
+    update-alternatives --install \
+       $BIN/Xvnc            Xvnc            $BIN/Xtigervnc 74 \
+       --slave \
+       $MAN/man1/Xvnc.1.gz  Xvnc.1.gz       $MAN/man1/Xtigervnc.1.gz
+    update-alternatives --install \
+       $BIN/x0vncserver           x0vncserver     $BIN/x0tigervncserver 74 \
+       --slave \
+       $MAN/man1/x0vncserver.1.gz x0vncserver.1.gz $MAN/man1/x0tigervncserver.1.gz
+    update-alternatives --install \
+       $BIN/vncpasswd           vncpasswd            $BIN/tigervncpasswd 74 \
+       --slave \
+       $MAN/man1/vncpasswd.1.gz vncpasswd.1.gz       $MAN/man1/tigervncpasswd.1.gz
+    update-alternatives --install \
+       $BIN/vncconfig           vncconfig       $BIN/tigervncconfig 64 \
+       --slave \
+       $MAN/man1/vncconfig.1.gz vncconfig.1.gz  $MAN/man1/tigervncconfig.1.gz
+fi
+
+#DEBHELPER#
+
+exit 0
index 26608e37b3d74c87054575c566a833d7c5c97f38..2e8e77c487634b19cec1e4e5d1ec0c7d8baf6e95 100644 (file)
@@ -4,8 +4,9 @@ set -e
 
 if [ "$1" = "remove" ] ; then
     BIN=/usr/bin
+    SBIN=/usr/sbin
     update-alternatives --remove \
-       vncserver $BIN/tigervncserver
+       vncsession $SBIN/tigervncsession
     update-alternatives --remove \
        Xvnc $BIN/Xtigervnc
     update-alternatives --remove \
index 35bc2d08203382b899497d67094f8b41ad7db442..28af8d1eba3fde4eed3e3c1a68cd979a76cad62a 100644 (file)
@@ -59,6 +59,7 @@ config-stamp: xorg-source-stamp
                -DBUILD_STATIC=off \
                -DCMAKE_INSTALL_PREFIX:PATH=/usr \
                -DSYSCONF_DIR:PATH=/etc \
+               -DLIBEXEC_DIR:PATH=/usr/lib/$(DEB_HOST_MULTIARCH) \
                -DUNIT_DIR:PATH=/lib/systemd/system
        (cd unix/xserver; \
        export PIXMANINCDIR=/usr/include/pixman-1; \
@@ -173,20 +174,24 @@ install: build
                $(CURDIR)/debian/tigervncserver/usr/bin/tigervncconfig
        mv $(CURDIR)/debian/tigervncserver/usr/bin/vncpasswd \
                $(CURDIR)/debian/tigervncserver/usr/bin/tigervncpasswd
-       mv $(CURDIR)/debian/tigervncserver/usr/bin/vncserver \
-               $(CURDIR)/debian/tigervncserver/usr/bin/tigervncserver
        mv $(CURDIR)/debian/tigervncserver/usr/bin/x0vncserver \
                $(CURDIR)/debian/tigervncserver/usr/bin/x0tigervncserver
+       mv $(CURDIR)/debian/tigervncserver/usr/sbin/vncsession \
+               $(CURDIR)/debian/tigervncserver/usr/sbin/tigervncsession
+       mv $(CURDIR)/debian/tigervncserver/usr/lib/$(DEB_HOST_MULTIARCH)/vncserver \
+               $(CURDIR)/debian/tigervncserver/usr/lib/$(DEB_HOST_MULTIARCH)/tigervncserver
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncconfig.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncconfig.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncpasswd.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncpasswd.1
-       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/vncserver.1 \
-               $(CURDIR)/debian/tigervncserver/usr/share/man/man1/tigervncserver.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/x0vncserver.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/x0tigervncserver.1
        mv $(CURDIR)/debian/tigervncserver/usr/share/man/man1/Xvnc.1 \
                $(CURDIR)/debian/tigervncserver/usr/share/man/man1/Xtigervnc.1
+       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man8/vncsession.8 \
+               $(CURDIR)/debian/tigervncserver/usr/share/man/man8/tigervncsession.8
+       mv $(CURDIR)/debian/tigervncserver/usr/share/man/man8/vncserver.8 \
+               $(CURDIR)/debian/tigervncserver/usr/share/man/man8/tigervncserver.8
        # delete development files
        rm -f $(CURDIR)/debian/tigervncserver/usr/lib/xorg/modules/extensions/libvnc.la
        # move viewer files to viewer package, rename on the fly
@@ -217,6 +222,8 @@ install: build
                $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervncserver/
        rm -rf $(CURDIR)/debian/tigervncserver/usr/share/doc/tigervnc-*/
 #      dh_movefiles
+       sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' \
+               debian/tigervncserver.postinst.in > debian/tigervncserver.postinst
 
 # Build architecture-independent files here.
 # Pass -i to all debhelper commands in this target to reduce clutter.
diff --git a/contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst b/contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst
deleted file mode 100644 (file)
index 32e7ea7..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "configure" ]; then
-    MAN=/usr/share/man/man1
-    BIN=/usr/bin
-    update-alternatives --install \
-       $BIN/vncserver       vncserver       $BIN/tigervncserver 64 \
-       --slave \
-       $MAN/vncserver.1.gz  vncserver.1.gz  $MAN/tigervncserver.1.gz
-    update-alternatives --install \
-       $BIN/Xvnc            Xvnc            $BIN/Xtigervnc 74 \
-       --slave \
-       $MAN/Xvnc.1.gz       Xvnc.1.gz       $MAN/Xtigervnc.1.gz
-    update-alternatives --install \
-       $BIN/x0vncserver     x0vncserver     $BIN/x0tigervncserver 74 \
-       --slave \
-       $MAN/x0vncserver.1.gz x0vncserver.1.gz $MAN/x0tigervncserver.1.gz
-    update-alternatives --install \
-       $BIN/vncpasswd        vncpasswd            $BIN/tigervncpasswd 74 \
-       --slave \
-       $MAN/vncpasswd.1.gz   vncpasswd.1.gz       $MAN/tigervncpasswd.1.gz
-    update-alternatives --install \
-       $BIN/vncconfig       vncconfig       $BIN/tigervncconfig 64 \
-       --slave \
-       $MAN/vncconfig.1.gz  vncconfig.1.gz  $MAN/tigervncconfig.1.gz
-fi
-
-#DEBHELPER#
-
-exit 0
diff --git a/contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst.in b/contrib/packages/deb/ubuntu-xenial/debian/tigervncserver.postinst.in
new file mode 100644 (file)
index 0000000..2491329
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+set -e
+
+if [ "$1" = "configure" ]; then
+    MAN=/usr/share/man
+    BIN=/usr/bin
+    SBIN=/usr/sbin
+    LIB=/usr/lib/@DEB_HOST_MULTIARCH@
+    update-alternatives --install \
+       $SBIN/vncsession          vncsession      $SBIN/tigervncsession 64 \
+       --slave \
+       $LIB/vncserver            vncserver       $LIB/tigervncserver \
+       --slave \
+       $MAN/man8/vncsession.8.gz vncsession.8.gz $MAN/man8/tigervncsession.8.gz \
+       --slave \
+       $MAN/man8/vncserver.8.gz  vncserver.8.gz  $MAN/man8/tigervncserver.8.gz
+    update-alternatives --install \
+       $BIN/Xvnc            Xvnc            $BIN/Xtigervnc 74 \
+       --slave \
+       $MAN/man1/Xvnc.1.gz  Xvnc.1.gz       $MAN/man1/Xtigervnc.1.gz
+    update-alternatives --install \
+       $BIN/x0vncserver           x0vncserver     $BIN/x0tigervncserver 74 \
+       --slave \
+       $MAN/man1/x0vncserver.1.gz x0vncserver.1.gz $MAN/man1/x0tigervncserver.1.gz
+    update-alternatives --install \
+       $BIN/vncpasswd           vncpasswd            $BIN/tigervncpasswd 74 \
+       --slave \
+       $MAN/man1/vncpasswd.1.gz vncpasswd.1.gz       $MAN/man1/tigervncpasswd.1.gz
+    update-alternatives --install \
+       $BIN/vncconfig           vncconfig       $BIN/tigervncconfig 64 \
+       --slave \
+       $MAN/man1/vncconfig.1.gz vncconfig.1.gz  $MAN/man1/tigervncconfig.1.gz
+fi
+
+#DEBHELPER#
+
+exit 0
index 26608e37b3d74c87054575c566a833d7c5c97f38..2e8e77c487634b19cec1e4e5d1ec0c7d8baf6e95 100644 (file)
@@ -4,8 +4,9 @@ set -e
 
 if [ "$1" = "remove" ] ; then
     BIN=/usr/bin
+    SBIN=/usr/sbin
     update-alternatives --remove \
-       vncserver $BIN/tigervncserver
+       vncsession $SBIN/tigervncsession
     update-alternatives --remove \
        Xvnc $BIN/Xtigervnc
     update-alternatives --remove \
diff --git a/contrib/packages/rpm/el7/SOURCES/tigervnc-shebang.patch b/contrib/packages/rpm/el7/SOURCES/tigervnc-shebang.patch
deleted file mode 100644 (file)
index f76af87..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-diff -up tigervnc-1.3.0/unix/vncserver.shebang tigervnc-1.3.0/unix/vncserver
---- tigervnc-1.3.0/unix/vncserver.shebang      2013-07-24 12:22:34.962158378 +0100
-+++ tigervnc-1.3.0/unix/vncserver      2013-07-24 12:22:41.593188190 +0100
-@@ -1,4 +1,4 @@
--#!/usr/bin/env perl
-+#!/usr/bin/perl
- #
- #  Copyright (C) 2009-2010 D. R. Commander.  All Rights Reserved.
- #  Copyright (C) 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
index 215d1daef310f65d75bd9109b382b93e24baed1c..5ae3b2f7ae7a4a76ffa1d2a86d0181a8e48f738c 100644 (file)
@@ -35,8 +35,6 @@ Obsoletes:      vnc < 4.1.3-2, vnc-libs < 4.1.3-2
 Provides:       tightvnc = 1.5.0-0.15.20090204svn3586
 Obsoletes:      tightvnc < 1.5.0-0.15.20090204svn3586
 
-Patch17:        tigervnc-shebang.patch
-
 %description
 Virtual Network Computing (VNC) is a remote display system which
 allows you to view a computing 'desktop' environment not only on the
@@ -129,9 +127,6 @@ done
 patch -p1 -b --suffix .vnc < ../xserver120.patch
 popd
 
-# Don't use shebang in vncserver script.
-%patch17 -p1 -b .shebang
-
 %build
 %ifarch sparcv9 sparc64 s390 s390x
 export CFLAGS="$RPM_OPT_FLAGS -fPIC"
@@ -222,13 +217,18 @@ fi
 
 %files server
 %defattr(-,root,root,-)
+%config(noreplace) %{_sysconfdir}/pam.d/tigervnc
 %config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults
 %config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory
+%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users
 %{_unitdir}/vncserver@.service
 %{_bindir}/x0vncserver
-%{_bindir}/vncserver
-%{_mandir}/man1/vncserver.1*
+%{_sbindir}/vncsession
+%{_libexecdir}/vncserver
+%{_libexecdir}/vncsession-start
 %{_mandir}/man1/x0vncserver.1*
+%{_mandir}/man8/vncserver.8*
+%{_mandir}/man8/vncsession.8*
 
 %files server-minimal
 %defattr(-,root,root,-)
index b685a4660f148f4c90217df827717aca8ac4ef5d..ed9ddda4b17026c5e111e0285bff759181023cdd 100644 (file)
@@ -111,8 +111,8 @@ When run as a "helper" app, make the window iconified at startup.
 .SH SEE ALSO
 .BR vncpasswd (1),
 .BR vncviewer (1),
-.BR vncserver (1),
-.BR Xvnc (1)
+.BR Xvnc (1),
+.BR vncsession (8)
 .br
 https://www.tigervnc.org
 
index 9e681815b98abdd84578178db172d489ecaada3f..c70a425a7d280097cb27e79797df9e219d783bc0 100644 (file)
@@ -43,9 +43,9 @@ Default location of the VNC password file.
 
 .SH SEE ALSO
 .BR vncviewer (1),
-.BR vncserver (1),
 .BR Xvnc (1)
 .BR vncconfig (1),
+.BR vncsession (8)
 .br
 https://www.tigervnc.org
 
index 9f085e0d410c784f03b3aab4a972d27bbc41b388..127c7a3e30d53d798d2f6bf981b99c1597f7804e 100644 (file)
@@ -1,10 +1,20 @@
+add_executable(vncsession vncsession.c)
+target_link_libraries(vncsession ${PAM_LIBS})
+
 configure_file(vncserver@.service.in vncserver@.service @ONLY)
+configure_file(vncsession-start.in vncsession-start @ONLY)
 configure_file(vncserver.in vncserver @ONLY)
 
-install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncserver DESTINATION ${BIN_DIR})
-install(FILES vncserver.man DESTINATION ${MAN_DIR}/man1 RENAME vncserver.1)
+install(TARGETS vncsession DESTINATION ${SBIN_DIR})
+install(FILES tigervnc.pam DESTINATION ${SYSCONF_DIR}/pam.d RENAME tigervnc)
+install(FILES vncsession.man DESTINATION ${MAN_DIR}/man8 RENAME vncsession.8)
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncserver DESTINATION ${LIBEXEC_DIR})
+install(FILES vncserver.man DESTINATION ${MAN_DIR}/man8 RENAME vncserver.8)
 install(FILES vncserver-config-defaults vncserver-config-mandatory DESTINATION ${SYSCONF_DIR}/tigervnc)
 
+install(FILES vncserver.users DESTINATION ${SYSCONF_DIR}/tigervnc)
+
 if(INSTALL_SYSTEMD_UNITS)
   install(FILES ${CMAKE_CURRENT_BINARY_DIR}/vncserver@.service DESTINATION ${UNIT_DIR})
+  install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vncsession-start DESTINATION ${LIBEXEC_DIR})
 endif()
diff --git a/unix/vncserver/tigervnc.pam b/unix/vncserver/tigervnc.pam
new file mode 100644 (file)
index 0000000..0f4cb3a
--- /dev/null
@@ -0,0 +1,11 @@
+#%PAM-1.0
+# pam_selinux.so close should be the first session rule
+-session   required     pam_selinux.so close
+session    required     pam_loginuid.so
+-session   required     pam_selinux.so open
+session    required     pam_namespace.so
+session    optional     pam_keyinit.so force revoke
+session    required     pam_limits.so
+-session   optional     pam_systemd.so
+session    required     pam_unix.so
+-session   optional     pam_reauthorize.so prepare
index 0b1e9a9ef87db8e64c0e2e2fc7d296a9dc0b8b1b..68a39af07c0d636851287079a3ceb056e783d59d 100755 (executable)
@@ -88,8 +88,6 @@ if ((@ARGV == 1) && ($ARGV[0] =~ /^:(\d+)$/)) {
     if (!&CheckDisplayNumber($displayNumber)) {
        die "A VNC server is already running as :$displayNumber\n";
     }
-} elsif (@ARGV == 0) {
-    $displayNumber = &GetDisplayNumber();
 } else {
     &Usage();
 }
@@ -127,8 +125,8 @@ LoadConfig($vncUserConfig);
 LoadConfig($vncSystemConfigMandatoryFile, 1);
 
 #
-# Check whether VNC authentication is enabled, and if so, prompt the user to
-# create a VNC password if they don't already have one.
+# Check whether VNC authentication is enabled, and if so, check that
+# a VNC password has been created.
 #
 
 $securityTypeArgSpecified = 0;
@@ -154,17 +152,10 @@ if ($config{'password'} ||
 if ((!$securityTypeArgSpecified || $vncAuthEnabled) && !$passwordArgSpecified) {
     ($z,$z,$mode) = stat("$vncUserDir/passwd");
     if (!(-e "$vncUserDir/passwd") || ($mode & 077)) {
-        warn "\nYou will require a password to access your desktops.\n\n";
-        system($exedir."vncpasswd -q $vncUserDir/passwd");
-        if (($? >> 8) != 0) {
-            exit 1;
-        }
+        die "VNC authentication enabled, but no password file created.\n";
     }
 }
 
-$desktopLog = "$vncUserDir/$host:$displayNumber.log";
-unlink($desktopLog);
-
 #
 # Find a desktop session to run
 #
@@ -264,11 +255,6 @@ warn "\nNew '$desktopName' desktop is $host:$displayNumber\n\n";
 
 warn "Starting desktop session $sessionname\n";
 
-warn "Log file is $desktopLog\n\n";
-
-open STDOUT, "> $desktopLog"
-open STDERR, ">&STDOUT"
-
 exec(@cmd);
 
 die "Failed to start session.\n";
@@ -314,24 +300,6 @@ sub LoadConfig {
 }
 
 
-#
-# GetDisplayNumber gets the lowest available display number.  A display number
-# n is taken if something is listening on the VNC server port (5900+n) or the
-# X server port (6000+n).
-#
-
-sub GetDisplayNumber
-{
-    foreach $n (1..99) {
-       if (&CheckDisplayNumber($n)) {
-           return $n+0; # Bruce Mah's workaround for bug in perl 5.005_02
-       }
-    }
-
-    die "$prog: no free display number on $host.\n";
-}
-
-
 #
 # Load a session desktop file
 #
@@ -439,7 +407,7 @@ sub CheckDisplayNumber
 
 sub Usage
 {
-    die("\nusage: $prog [:<number>]\n\n");
+    die("\nusage: $prog <display>\n\n");
 }
 
 
index 8398ed04231bb301eefe5962ed97e41ed507f51f..f1017be9d231e3a1e9d655075e44b9b42c940eeb 100644 (file)
@@ -1,85 +1 @@
-.TH vncserver 1 "" "TigerVNC" "Virtual Network Computing"
-.SH NAME
-vncserver \- start a VNC server
-.SH SYNOPSIS
-.B vncserver
-.RI [: display# ]
-.SH DESCRIPTION
-.B vncserver
-is used to start a VNC (Virtual Network Computing) desktop.
-.B vncserver
-is a Perl script which simplifies the process of starting an Xvnc server.  It
-runs Xvnc with appropriate options and starts a window manager on the VNC
-desktop.
-
-.B vncserver
-can be run with no options at all. In this case it will choose the first
-available display number (usually :1), start Xvnc with that display number,
-and start the default window manager in the Xvnc session.  You can also
-specify the display number, in which case vncserver will attempt to start
-Xvnc with that display number and exit if the display number is not
-available.  For example:
-
-.RS
-vncserver :13
-.RE
-
-vncserver will exit once the started session exits.
-
-.SH FILES
-Several VNC-related files are found in the directory $HOME/.vnc:
-.TP
-/etc/tigervnc/vncserver-config-defaults
-The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
-and defines options to be passed to Xvnc, they will be used as defaults for
-users. The user's $HOME/.vnc/config overrides settings configured in this file.
-The overall configuration file load order is: this file, $HOME/.vnc/config,
-and then /etc/tigervnc/vncserver-config-mandatory. None are required to exist.
-.TP
-/etc/tigervnc/vncserver-config-mandatory
-The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
-and defines options to be passed to Xvnc, they will override any of the same
-options defined in a user's $HOME/.vnc/config. This file offers a mechanism
-to establish some basic form of system-wide policy. WARNING! There is
-nothing stopping users from constructing their own vncserver-like script
-that calls Xvnc directly to bypass any options defined in
-/etc/tigervnc/vncserver-config-mandatory. The overall configuration file load
-order is: /etc/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then
-this file. None are required to exist.
-.TP
-$HOME/.vnc/config
-An optional server config file wherein options to be passed to Xvnc are listed
-to avoid hard-coding them to the physical invocation. List options in this file
-one per line. For those requiring an argument, simply separate the option from
-the argument with an equal sign, for example: "geometry=2000x1200" or
-"securitytypes=vncauth,tlsvnc". Options without an argument are simply listed
-as a single word, for example: "localhost" or "alwaysshared".
-
-The special option
-.B session
-can be used to control which session type will be started. This should match
-one of the files in \fI/usr/share/xsessions\fP. E.g. if there is a file called
-"gnome.desktop", then "session=gnome" would be set to use that session type.
-.TP
-$HOME/.vnc/passwd
-The VNC password file.
-.TP
-$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
-The log file for Xvnc and the session.
-
-.SH SEE ALSO
-.BR vncviewer (1),
-.BR vncpasswd (1),
-.BR vncconfig (1),
-.BR Xvnc (1)
-.br
-https://www.tigervnc.org
-
-.SH AUTHOR
-Tristan Richardson, RealVNC Ltd., D. R. Commander and others.
-
-VNC was originally developed by the RealVNC team while at Olivetti
-Research Ltd / AT&T Laboratories Cambridge.  TightVNC additions were
-implemented by Constantin Kaplinsky. Many other people have since
-participated in development, testing and support. This manual is part
-of the TigerVNC software suite.
+.so man8/vncsession.8
diff --git a/unix/vncserver/vncserver.users b/unix/vncserver/vncserver.users
new file mode 100644 (file)
index 0000000..0a63784
--- /dev/null
@@ -0,0 +1,8 @@
+# TigerVNC User assignment
+#
+# This file assigns users to specific VNC display numbers.
+# The syntax is <display>=<username>. E.g.:
+#
+# :2=andrew
+# :3=lisa
+
index d4ca9bf749dfc719300818e0621d78482b9deca2..36ad02d0828adf00a7ebd0604601e65ecd6fc7fd 100644 (file)
@@ -1,13 +1,11 @@
 # The vncserver service unit file
 #
 # Quick HowTo:
-# 1. Copy this file to /etc/systemd/system/vncserver@.service
-# 2. Switches for vncserver should be entered in ~/.vnc/config rather than
-#    hard-coded into this unit file. See the vncserver(1) manpage.
-# 3. Replace <USER> with the desired user
-#   ("runuser -l <USER> -c /usr/bin/vncserver %i")
-# 4. Run `systemctl daemon-reload`
-# 5. Run `systemctl enable vncserver@:<display>.service`
+# 1. Add a user mapping to /etc/tigervnc/vncserver.users.
+# 2. Adjust the global or user configuration. See the
+#    vncsession(8) manpage for details. (OPTIONAL)
+# 3. Run `systemctl enable vncserver@:<display>.service`
+# 4. Run `systemctl start vncserver@:<display>.service`
 #
 # DO NOT RUN THIS SERVICE if your local area network is
 # untrusted!  For a secure way of using VNC, you should
@@ -24,9 +22,9 @@
 # You can then point a VNC client on hostA at vncdisplay N of localhost and with
 # the help of ssh, you end up seeing what hostB makes available on port 590M
 #
-# Use "-nolisten tcp" to prevent X connections to your VNC server via TCP.
+# Use "nolisten=tcp" to prevent X connections to your VNC server via TCP.
 #
-# Use "-localhost" to prevent remote VNC clients connecting except when
+# Use "localhost" to prevent remote VNC clients connecting except when
 # doing so through a secure tunnel.  See the "-via" option in the
 # `man vncviewer' manual page.
 
@@ -37,11 +35,8 @@ After=syslog.target network.target
 
 [Service]
 Type=forking
-# Clean any existing files in /tmp/.X11-unix environment
-ExecStartPre=/bin/sh -c '@BIN_DIR@/vncserver -kill %i > /dev/null 2>&1 || :'
-ExecStart=/usr/sbin/runuser -l <USER> -c "@BIN_DIR@/vncserver %i"
-PIDFile=/home/<USER>/.vnc/%H%i.pid
-ExecStop=/bin/sh -c '@BIN_DIR@/vncserver -kill %i > /dev/null 2>&1 || :'
+ExecStart=/usr/libexec/vncsession-start %i
+PIDFile=/var/run/vncsession-%i.pid
 
 [Install]
 WantedBy=multi-user.target
diff --git a/unix/vncserver/vncsession-start.in b/unix/vncserver/vncsession-start.in
new file mode 100644 (file)
index 0000000..b4a6e00
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+#  Copyright 2019 Pierre Ossman for Cendio AB
+#
+#  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.
+#
+
+USERSFILE="@SYSCONF_DIR@/tigervnc/vncserver.users"
+
+if [ $# -ne 1 ]; then
+       echo "Syntax:" >&2
+       echo "    $0 <display>" >&2
+       exit 1
+fi
+
+if [ ! -f "${USERSFILE}" ]; then
+       echo "Users file ${USERSFILE} missing" >&2
+       exit 1
+fi
+
+DISPLAY="$1"
+
+USER=`grep "^${DISPLAY}=" "${USERSFILE}" 2>/dev/null | head -1 | cut -d = -f 2-`
+
+if [ -z "${USER}" ]; then
+       echo "No user configured for display ${DISPLAY}" >&2
+       exit 1
+fi
+
+exec "@SBIN_DIR@/vncsession" "${USER}" "${DISPLAY}"
diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c
new file mode 100644 (file)
index 0000000..d2d328e
--- /dev/null
@@ -0,0 +1,592 @@
+/* 
+ * Copyright 2018 Pierre Ossman for Cendio AB
+ *    
+ * 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.
+ */
+
+#include <config.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <security/pam_appl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+extern char **environ;
+
+// PAM service name
+const char *SERVICE_NAME = "tigervnc";
+
+// Main script PID
+volatile static pid_t script = -1;
+
+// Daemon completion pipe
+int daemon_pipe_fd = -1;
+
+static int
+begin_daemon(void)
+{
+    int devnull, fds[2];
+    pid_t pid;
+
+    /* Pipe to report startup success */
+    if (pipe(fds) < 0) {
+        perror("pipe");
+        return -1;
+    }
+
+    /* First fork */
+    pid = fork();
+    if (pid < 0) {
+        perror("fork");
+        return -1;
+    }
+
+    if (pid != 0) {
+        ssize_t len;
+        char buf[1];
+
+        close(fds[1]);
+
+        /* Wait for child to finish startup */
+        len = read(fds[0], buf, 1);
+        if (len != 1) {
+            fprintf(stderr, "Failure daemonizing\n");
+            _exit(EX_OSERR);
+        }
+
+        _exit(0);
+    }
+
+    close(fds[0]);
+    daemon_pipe_fd = fds[1];
+
+    /* Detach from terminal */
+    if (setsid() < 0) {
+        perror("setsid");
+        return -1;
+    }
+
+    /* Another fork required to fully detach */
+    pid = fork();
+    if (pid < 0) {
+        perror("fork");
+        return -1;
+    }
+
+    if (pid == 0)
+        _exit(0);
+
+    /* Send all stdio to /dev/null */
+    devnull = open("/dev/null", O_RDWR);
+    if (devnull < 0) {
+        fprintf(stderr, "Failed to open /dev/null: %s\n", strerror(errno));
+        return -1;
+    }
+    if ((dup2(devnull, 0) < 0) ||
+        (dup2(devnull, 1) < 0) ||
+        (dup2(devnull, 2) < 0)) {
+        perror("dup2");
+        return -1;
+    }
+    if (devnull > 2)
+        close(devnull);
+
+    /* Full control of access bits */
+    umask(0);
+
+    /* A safe working directory */
+    if (chdir("/") < 0) {
+        perror("chdir");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void
+finish_daemon(void)
+{
+    write(daemon_pipe_fd, "+", 1);
+    close(daemon_pipe_fd);
+    daemon_pipe_fd = -1;
+}
+
+static void
+sighandler(int sig)
+{
+    if (script > 0) {
+        kill(script, SIGTERM);
+    }
+}
+
+static void
+setup_signals(void)
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = sighandler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+
+    sigaction(SIGHUP, &act, NULL);
+    sigaction(SIGINT, &act, NULL);
+    sigaction(SIGTERM, &act, NULL);
+    sigaction(SIGQUIT, &act, NULL);
+    sigaction(SIGPIPE, &act, NULL);
+}
+
+static int
+conv(int num_msg,
+     const struct pam_message **msg,
+     struct pam_response **resp, void *appdata_ptr)
+{
+    /* Opening a session should not require a conversation */
+    return PAM_CONV_ERR;
+}
+
+static pam_handle_t *
+run_pam(int *pamret, const char *username, const char *display)
+{
+    pam_handle_t *pamh;
+
+    /* Say hello to PAM */
+    struct pam_conv pconv;
+    pconv.conv = conv;
+    pconv.appdata_ptr = NULL;
+    *pamret = pam_start(SERVICE_NAME, username, &pconv, &pamh);
+    if (*pamret != PAM_SUCCESS) {
+        /* pam_strerror requires a pamh argument, but if pam_start
+           fails, pamh is invalid. In practice, at least the Linux
+           implementation of pam_strerror does not use the pamh
+           argument, but let's take care - avoid pam_strerror here. */
+        syslog(LOG_CRIT, "pam_start failed: %d", *pamret);
+        return NULL;
+    }
+
+    /* ConsoleKit and systemd (and possibly others) uses this to
+       determine if the session is local or not. It needs to be set to
+       something that can't be interpreted as localhost. We don't know
+       what the client's address is though, and that might change on
+       reconnects. We also don't want to set it to some text string as
+       that results in a DNS lookup with e.g. libaudit. Let's use a
+       fake IPv4 address from the documentation range. */
+    /* FIXME: This might throw an error on a IPv6-only host */
+    *pamret = pam_set_item(pamh, PAM_RHOST, "203.0.113.20");
+    if (*pamret != PAM_SUCCESS) {
+        syslog(LOG_CRIT, "pam_set_item(PAM_RHOST) failed: %d (%s)",
+               *pamret, pam_strerror(pamh, *pamret));
+        return pamh;
+    }
+
+#ifdef PAM_XDISPLAY
+    /* Let PAM modules use this to tag the session as a graphical one */
+    *pamret = pam_set_item(pamh, PAM_XDISPLAY, display);
+    /* Note: PAM_XDISPLAY is only supported by modern versions of PAM */
+    if (*pamret != PAM_BAD_ITEM && *pamret != PAM_SUCCESS) {
+        syslog(LOG_CRIT, "pam_set_item(PAM_XDISPLAY) failed: %d (%s)",
+               *pamret, pam_strerror(pamh, *pamret));
+        return pamh;
+    }
+#endif
+
+    /* Open session */
+    *pamret = pam_open_session(pamh, PAM_SILENT);
+    if (*pamret != PAM_SUCCESS) {
+        syslog(LOG_CRIT, "pam_open_session failed: %d (%s)",
+               *pamret, pam_strerror(pamh, *pamret));
+        return pamh;
+    }
+
+    return pamh;
+}
+
+static int
+stop_pam(pam_handle_t * pamh, int pamret)
+{
+    /* Close session */
+    if (pamret == PAM_SUCCESS) {
+        pamret = pam_close_session(pamh, PAM_SILENT);
+        if (pamret != PAM_SUCCESS) {
+            syslog(LOG_ERR, "pam_close_session failed: %d (%s)",
+                   pamret, pam_strerror(pamh, pamret));
+        }
+    }
+
+    /* If PAM was OK and we are running on a SELinux system, new
+       processes images will be executed in the root context. */
+
+    /* Say goodbye */
+    pamret = pam_end(pamh, pamret);
+    if (pamret != PAM_SUCCESS) {
+        /* avoid pam_strerror - we have no pamh. */
+        syslog(LOG_ERR, "pam_end failed: %d", pamret);
+        return EX_OSERR;
+    }
+    return pamret;
+}
+
+static char **
+prepare_environ(pam_handle_t * pamh)
+{
+    char **pam_env, **child_env, **entry;
+    int orig_count, pam_count;
+
+    /* This function merges the normal environment with PAM's changes */
+
+    pam_env = pam_getenvlist(pamh);
+    if (pam_env == NULL)
+        return NULL;
+
+    /*
+     * Worst case scenario is that PAM only adds variables, so allocate
+     * based on that assumption.
+     */
+    orig_count = 0;
+    for (entry = environ; *entry != NULL; entry++)
+        orig_count++;
+    pam_count = 0;
+    for (entry = pam_env; *entry != NULL; entry++)
+        pam_count++;
+
+    child_env = calloc(orig_count + pam_count + 1, sizeof(char *));
+    if (child_env == NULL)
+        return NULL;
+
+    memcpy(child_env, environ, sizeof(char *) * orig_count);
+    for (entry = child_env; *entry != NULL; entry++) {
+        *entry = strdup(*entry);
+        if (*entry == NULL)     // FIXME: cleanup
+            return NULL;
+    }
+
+    for (entry = pam_env; *entry != NULL; entry++) {
+        size_t varlen;
+        char **orig_entry;
+
+        varlen = strcspn(*entry, "=") + 1;
+
+        /* Check for overwrite */
+        for (orig_entry = child_env; *orig_entry != NULL; orig_entry++) {
+            if (strncmp(*entry, *orig_entry, varlen) != 0)
+                continue;
+
+            free(*orig_entry);
+            *orig_entry = *entry;
+            break;
+        }
+
+        /* New variable? */
+        if (*orig_entry == NULL) {
+            /*
+             * orig_entry will be pointing at the terminating entry,
+             * so we can just tack it on here. The new NULL was already
+             * prepared by calloc().
+             */
+            *orig_entry = *entry;
+        }
+    }
+
+    return child_env;
+}
+
+static void
+switch_user(const char *username, uid_t uid, gid_t gid)
+{
+    // We must change group stuff first, because only root can do that.
+    if (setgid(gid) < 0) {
+        perror(": setgid");
+        _exit(EX_OSERR);
+    }
+
+    // Supplementary groups.
+    if (initgroups(username, gid) < 0) {
+        perror("initgroups");
+        _exit(EX_OSERR);
+    }
+
+    // Set euid, ruid and suid
+    if (setuid(uid) < 0) {
+        perror("setuid");
+        _exit(EX_OSERR);
+    }
+}
+
+static void
+redir_stdio(const char *homedir, const char *display)
+{
+    int fd;
+    char hostname[HOST_NAME_MAX+1];
+    char logfile[PATH_MAX];
+
+    fd = open("/dev/null", O_RDONLY);
+    if (fd == -1) {
+        perror("open");
+        _exit(EX_OSERR);
+    }
+    if (dup2(fd, 0) == -1) {
+        perror("dup2");
+        _exit(EX_OSERR);
+    }
+    close(fd);
+
+    snprintf(logfile, sizeof(logfile), "%s/.vnc", homedir);
+    if (mkdir(logfile, 0755) == -1) {
+        if (errno != EEXIST) {
+            perror("mkdir");
+            _exit(EX_OSERR);
+        }
+    }
+
+    if (gethostname(hostname, sizeof(hostname)) == -1) {
+        perror("gethostname");
+        _exit(EX_OSERR);
+    }
+
+    snprintf(logfile, sizeof(logfile), "%s/.vnc/%s%s.log",
+             homedir, hostname, display);
+    fd = open(logfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+    if (fd == -1) {
+        perror("open");
+        _exit(EX_OSERR);
+    }
+    if ((dup2(fd, 1) == -1) || (dup2(fd, 2) == -1)) {
+        perror("dup2");
+        _exit(EX_OSERR);
+    }
+    close(fd);
+}
+
+static void
+close_fds(void)
+{
+    DIR *dir;
+    struct dirent *entry;
+
+    dir = opendir("/proc/self/fd");
+    if (dir == NULL) {
+        perror("opendir");
+        _exit(EX_OSERR);
+    }
+
+    while ((entry = readdir(dir)) != NULL) {
+        int fd;
+        fd = atoi(entry->d_name);
+        if (fd < 3)
+            continue;
+        close(fd);
+    }
+
+    closedir(dir);
+}
+
+static pid_t
+run_script(const char *username, const char *display, char **envp)
+{
+    struct passwd *pwent;
+    pid_t pid;
+    const char *child_argv[3];
+
+    pwent = getpwnam(username);
+    if (pwent == NULL) {
+        syslog(LOG_CRIT, "getpwnam: %s", strerror(errno));
+        return -1;
+    }
+
+    pid = fork();
+    if (pid < 0) {
+        syslog(LOG_CRIT, "fork: %s", strerror(errno));
+        return pid;
+    }
+
+    /* two processes now */
+
+    if (pid > 0)
+        return pid;
+
+    /* child */
+
+    switch_user(pwent->pw_name, pwent->pw_uid, pwent->pw_gid);
+
+    close_fds();
+
+    redir_stdio(pwent->pw_dir, display);
+
+    // execvpe() is not POSIX and is missing from older glibc
+    // First clear out everything
+    while ((environ != NULL) && (*environ != NULL)) {
+        char *var, *eq;
+        var = strdup(*environ);
+        eq = strchr(var, '=');
+        if (eq)
+            *eq = '\0';
+        unsetenv(var);
+        free(var);
+    }
+
+    // Then copy over the desired environment
+    for (; *envp != NULL; envp++)
+        putenv(*envp);
+
+    // Set up some basic environment for the script
+    setenv("HOME", pwent->pw_dir, 1);
+    setenv("SHELL", pwent->pw_shell, 1);
+    setenv("LOGNAME", pwent->pw_name, 1);
+    setenv("USER", pwent->pw_name, 1);
+    setenv("USERNAME", pwent->pw_name, 1);
+
+    child_argv[0] = LIBEXEC_DIR "/vncserver";
+    child_argv[1] = display;
+    child_argv[2] = NULL;
+
+    execvp(child_argv[0], (char*const*)child_argv);
+
+    // execvp failed
+    perror("execvp");
+
+    _exit(EX_OSERR);
+}
+
+int
+main(int argc, char **argv)
+{
+    char pid_file[PATH_MAX];
+    FILE *f;
+
+    const char *username, *display;
+
+    if ((argc != 3) || (argv[2][0] != ':')) {
+        fprintf(stderr, "Syntax:\n");
+        fprintf(stderr, "    %s <username> <display>\n", argv[0]);
+        return EX_USAGE;
+    }
+
+    username = argv[1];
+    display = argv[2];
+
+    if (geteuid() != 0) {
+        fprintf(stderr, "This program needs to be run as root!\n");
+        return EX_USAGE;
+    }
+
+    if (getpwnam(username) == NULL) {
+        if (errno == 0)
+          fprintf(stderr, "User \"%s\" does not exist\n", username);
+        else
+          fprintf(stderr, "Cannot look up user \"%s\": %s\n",
+                  username, strerror(errno));
+        return EX_OSERR;
+    }
+
+    if (begin_daemon() == -1)
+        return EX_OSERR;
+
+    openlog("vncsession", LOG_PID, LOG_AUTH);
+
+    /* Indicate that this is a graphical user session. We need to do
+       this here before PAM as pam_systemd.so looks at these. */
+    if ((putenv("XDG_SESSION_CLASS=user") < 0) ||
+        (putenv("XDG_SESSION_TYPE=x11") < 0)) {
+        syslog(LOG_CRIT, "putenv: %s", strerror(errno));
+        return EX_OSERR;
+    }
+
+    /* Init PAM */
+    int pamret;
+    pam_handle_t *pamh = run_pam(&pamret, username, display);
+    if (!pamh) {
+        return EX_OSERR;
+    }
+    if (pamret != PAM_SUCCESS) {
+        stop_pam(pamh, pamret);
+        return EX_OSERR;
+    }
+
+    char **child_env;
+    child_env = prepare_environ(pamh);
+    if (child_env == NULL) {
+        syslog(LOG_CRIT, "Failure creating child process environment");
+        stop_pam(pamh, pamret);
+        return EX_OSERR;
+    }
+
+    setup_signals();
+
+    script = run_script(username, display, child_env);
+    if (script == -1) {
+        syslog(LOG_CRIT, "Failure starting vncserver script");
+        stop_pam(pamh, pamret);
+        return EX_OSERR;
+    }
+
+    snprintf(pid_file, sizeof(pid_file),
+             "/var/run/vncsession-%s.pid", display);
+    f = fopen(pid_file, "w");
+    if (f == NULL) {
+        syslog(LOG_ERR, "Failure creating pid file \"%s\": %s",
+               pid_file, strerror(errno));
+    } else {
+        fprintf(f, "%ld\n", (long)getpid());
+        fclose(f);
+    }
+
+    finish_daemon();
+
+    while (1) {
+        int status;
+        pid_t gotpid = waitpid(script, &status, 0);
+        if (gotpid < 0) {
+            if (errno != EINTR) {
+                syslog(LOG_CRIT, "waitpid: %s", strerror(errno));
+                exit(EXIT_FAILURE);
+            }
+            continue;
+        }
+        if (WIFEXITED(status)) {
+            if (WEXITSTATUS(status) != 0) {
+                syslog(LOG_WARNING,
+                        "vncsession: vncserver exited with status=%d",
+                        WEXITSTATUS(status));
+            }
+            break;
+        }
+        else if (WIFSIGNALED(status)) {
+            syslog(LOG_WARNING,
+                    "vncsession: vncserver was terminated by signal %d",
+                    WTERMSIG(status));
+            break;
+        }
+    }
+
+    unlink(pid_file);
+
+    stop_pam(pamh, pamret);
+
+    return 0;
+}
diff --git a/unix/vncserver/vncsession.man b/unix/vncserver/vncsession.man
new file mode 100644 (file)
index 0000000..2138209
--- /dev/null
@@ -0,0 +1,75 @@
+.TH vncsession 8 "" "TigerVNC" "Virtual Network Computing"
+.SH NAME
+vncsession \- start a VNC server
+.SH SYNOPSIS
+.B vncsession
+.RI < username >
+.RI <: display# >
+.SH DESCRIPTION
+.B vncsession
+is used to start a VNC (Virtual Network Computing) desktop.
+.B vncsession
+performs all the necessary steps to create a new user session, run Xvnc with
+appropriate options and starts a window manager on the VNC desktop.
+
+.B vncsession
+is rarely called directly and is normally started by the system service
+manager.
+
+.SH FILES
+Several VNC-related files are found in the directory $HOME/.vnc:
+.TP
+/etc/tigervnc/vncserver-config-defaults
+The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
+and defines options to be passed to Xvnc, they will be used as defaults for
+users. The user's $HOME/.vnc/config overrides settings configured in this file.
+The overall configuration file load order is: this file, $HOME/.vnc/config,
+and then /etc/tigervnc/vncserver-config-mandatory. None are required to exist.
+.TP
+/etc/tigervnc/vncserver-config-mandatory
+The optional system-wide equivalent of $HOME/.vnc/config. If this file exists
+and defines options to be passed to Xvnc, they will override any of the same
+options defined in a user's $HOME/.vnc/config. This file offers a mechanism
+to establish some basic form of system-wide policy. WARNING! There is
+nothing stopping users from constructing their own vncsession-like script
+that calls Xvnc directly to bypass any options defined in
+/etc/tigervnc/vncserver-config-mandatory. The overall configuration file load
+order is: /etc/tigervnc/vncserver-config-defaults, $HOME/.vnc/config, and then
+this file. None are required to exist.
+.TP
+$HOME/.vnc/config
+An optional server config file wherein options to be passed to Xvnc are listed
+to avoid hard-coding them to the physical invocation. List options in this file
+one per line. For those requiring an argument, simply separate the option from
+the argument with an equal sign, for example: "geometry=2000x1200" or
+"securitytypes=vncauth,tlsvnc". Options without an argument are simply listed
+as a single word, for example: "localhost" or "alwaysshared".
+
+The special option
+.B session
+can be used to control which session type will be started. This should match
+one of the files in \fI/usr/share/xsessions\fP. E.g. if there is a file called
+"gnome.desktop", then "session=gnome" would be set to use that session type.
+.TP
+$HOME/.vnc/passwd
+The VNC password file.
+.TP
+$HOME/.vnc/\fIhost\fP:\fIdisplay#\fP.log
+The log file for Xvnc and the session.
+
+.SH SEE ALSO
+.BR vncviewer (1),
+.BR vncpasswd (1),
+.BR vncconfig (1),
+.BR Xvnc (1)
+.br
+https://www.tigervnc.org
+
+.SH AUTHOR
+Tristan Richardson, RealVNC Ltd., D. R. Commander and others.
+
+VNC was originally developed by the RealVNC team while at Olivetti
+Research Ltd / AT&T Laboratories Cambridge.  TightVNC additions were
+implemented by Constantin Kaplinsky. Many other people have since
+participated in development, testing and support. This manual is part
+of the TigerVNC software suite.
index 9c8a8891458435751c8589213e09aa882e593a40..955917953b9f64a45995d9cf0a9b265375db080f 100644 (file)
@@ -18,9 +18,9 @@ that the VNC server display number will be the same as the X server display
 number, which means you can use eg. snoopy:2 to refer to display 2 on machine
 "snoopy" in both the X world and the VNC world.
 
-The best way of starting \fBXvnc\fP is via the \fBvncserver\fP script.  This
-sets up the environment appropriately and runs some X applications to get you
-going.  See the manual page for \fBvncserver\fP(1) for more information.
+The best way of starting \fBXvnc\fP is via \fBvncsession\fP.  This sets up the
+environment appropriately and starts a desktop environment. See the manual
+page for \fBvncsession\fP(8) for more information.
 
 .SH OPTIONS
 .B Xvnc
@@ -383,8 +383,8 @@ created automatically the next time he connects.
 .SH SEE ALSO
 .BR vncconfig (1),
 .BR vncpasswd (1),
-.BR vncserver (1),
 .BR vncviewer (1),
+.BR vncsession (8),
 .BR Xserver (1),
 .BR inetd (1)
 .br
index 9e81f7e25aedf22feb9ea27a2774c32afb9b4245..64f0b08cd6e18f71919953921cc92d6960d05eab 100644 (file)
@@ -333,7 +333,7 @@ Default certificate revocation list.
 .BR Xvnc (1),
 .BR vncpasswd (1),
 .BR vncconfig (1),
-.BR vncserver (1)
+.BR vncsession (8)
 .br
 https://www.tigervnc.org