#!/bin/sh

#
# Method script to start x11vnc daemon connected to an X11 display
# and represents the system desktop session (or another display)
# for persistent remote access. Starts as root and changes to the
# currently appropriate account, selected as implemented below.
#
# The X11VNC program must run as the same account which runs the
# X11 server at the moment, to use the same magic cookies etc.,
# e.g. "lightdm" when waiting for login and as the "real user" if
# reconnecting after someone has logged in there. A VNC client
# disconnection as well as a session logout stops the daemon (and
# SMF then restarts it, connecting to the existing X11 session).
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source.  A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
# Copyright 2022 Jim Klimov

. /lib/svc/share/smf_include.sh

SMF_FMRI_BASENAME="`echo "${SMF_FMRI}" | sed 's,:[^:]*$,,'`"
SMF_FMRI_INSTANCE="`echo "${SMF_FMRI}" | sed 's,^.*:\([^:]*\)$,\1,'`"

getpropInst() {
    OUT="`svcprop -p "$1" "$2" 2>/dev/null`" || return
    if [ x"${OUT}" = x'""' ]; then OUT=""; fi
    echo "$OUT"
}

getprop() {
    getpropInst "$1" "$SMF_FMRI" \
    || getpropInst "$1" "$SMF_FMRI_BASENAME"
}

getpropNumPositive() {
    NUM="`getpropInst "$1" "$SMF_FMRI"`" \
    && [ -n "${NUM}" ] && [ "${NUM}" -gt 0 ] \
    && { echo "$NUM" ; return 0; }

    NUM="`getpropInst "$1" "$SMF_FMRI_BASENAME"`" \
    && [ -n "${NUM}" ] && [ "${NUM}" -gt 0 ] \
    && { echo "$NUM" ; return 0; }

    return 1
}

getpropStringNotEmpty() {
    STR="`getpropInst "$1" "$SMF_FMRI"`" \
    && [ -n "${STR}" ] \
    && { echo "$STR" ; return 0; }

    STR="`getpropInst "$1" "$SMF_FMRI_BASENAME"`" \
    && [ -n "${STR}" ] \
    && { echo "$STR" ; return 0; }

    return 1
}

# Currently we support one way of determining the needed account,
# but just in case anticipate extensibility:
PERMISSION_MODEL="`getpropStringNotEmpty x11vnc/PERMISSION_MODEL`" \
&& [ -n "${PERMISSION_MODEL}" ] \
|| PERMISSION_MODEL="lightdm"

# Default a display number from settings or SMF instance name:
DISPLAY_NUMBER="`getpropInst x11vnc/DISPLAY_NUMBER $SMF_FMRI`" \
&& [ -n "${DISPLAY_NUMBER}" ] && [ "${DISPLAY_NUMBER}" -gt 0 ] \
|| { DISPLAY_NUMBER="`echo "${SMF_FMRI_INSTANCE}" | sed 's,^display-\([0-9]*\)$,\1,'`" \
     && [ -n "${DISPLAY_NUMBER}" ] && [ "${DISPLAY_NUMBER}" -gt 0 ] \
     || DISPLAY_NUMBER="0"
   }

# Note: while port 5900 is standard for VNC on DISPLAY=":0" it may
# conflict with other enabled VNC server implementations (including
# an inetd-style listener) so we let it be configured:
BASE_PORT="`getpropNumPositive x11vnc/BASE_PORT`" \
|| BASE_PORT="5900"

PORT="`getpropInst x11vnc/PORT $SMF_FMRI`" \
&& [ -n "${PORT}" ] && [ "${PORT}" -gt 0 ] \
|| PORT="`expr $BASE_PORT + $DISPLAY_NUMBER`"

ARGS="`getpropStringNotEmpty x11vnc/ARGS`" \
|| ARGS=""

getUser() {
    # Echo back the user name to run as:
    case "${PERMISSION_MODEL}" in
        lightdm)
            if [ -s "/var/run/lightdm/root/:${DISPLAY_NUMBER}" ]; then
                ls -la "/var/run/lightdm/root/:${DISPLAY_NUMBER}" \
                | awk '{print $3}' \
                && return 0
            fi
            echo "Could not determine current lightdm/X11 user account for DISPLAY=:${DISPLAY_NUMBER}" >&2
            ;;
        *)  echo "Unsupported x11vnc/PERMISSION_MODEL: ${PERMISSION_MODEL}" >&2
            # TODO: Hardcode? Define in SMF? Look for running Xorg processes?
            # echo "root"
            ;;
    esac
    return 1
}

X11USER="`getUser`" || X11USER=""
if [ -n "${X11USER}" ] ; then
    X11USER_HOME="`getent passwd "${X11USER}" | awk -F: '{print \$6}'`"
else
    X11USER_HOME="`getent passwd \"\`id -u\`\" | awk -F: '{print \$6}'`"
fi

case "$1" in
    start)
        # Password file may be created by `vncpasswd` executed by the user,
        # or by the server binary like this:
        #   x11vnc -storepasswd yourVNCpasswordHERE ~/.vnc/passwd
        case "${ARGS}" in
            *rfbauth*|*storepasswd*) ;;
            *)  if [ -s "${X11USER_HOME}/.vnc/passwd" ] ; then
                    ARGS="$ARGS -rfbauth '${X11USER_HOME}/.vnc/passwd'"
                fi
                ;;
        esac

        # set -x
        if [ -n "${X11USER}" ] ; then
            exec su - "${X11USER}" -c "/usr/bin/x11vnc -display ':${DISPLAY_NUMBER}' -rfbport '${PORT}' $ARGS"
        else
            exec /usr/bin/x11vnc -display ":${DISPLAY_NUMBER}" -rfbport "${PORT}" $ARGS
        fi
        ;;
esac