From 862fbd41d46c94a54226c10068cec5596b96d20f Mon Sep 17 00:00:00 2001
From: Alexey Golubev <Alexey.Golubev@onlyoffice.com>
Date: Mon, 13 Jan 2020 15:22:54 +0300
Subject: [PATCH] Add prof of concept none pivilage execution

  Use 'DS_PORT' env to use custom https port
  sudo docker run -e DS_PORT=1234 -itd -p80:1234  \
  onlyoffice/documentserver
---
 config/nginx/nginx                 | 196 +++++++++++++++++++++++++++++
 config/nginx/nginx.conf            |  63 ++++++++++
 config/supervisor/supervisor       |   8 +-
 config/supervisor/supervisord.conf |   6 +-
 run-document-server.sh             |  11 ++
 5 files changed, 277 insertions(+), 7 deletions(-)
 create mode 100644 config/nginx/nginx
 create mode 100644 config/nginx/nginx.conf

diff --git a/config/nginx/nginx b/config/nginx/nginx
new file mode 100644
index 0000000..1c68faf
--- /dev/null
+++ b/config/nginx/nginx
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides:       nginx
+# Required-Start:    $local_fs $remote_fs $network $syslog $named
+# Required-Stop:     $local_fs $remote_fs $network $syslog $named
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: starts the nginx web server
+# Description:       starts nginx using start-stop-daemon
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/nginx
+NAME=nginx
+DESC=nginx
+
+# Include nginx defaults if available
+if [ -r /etc/default/nginx ]; then
+        . /etc/default/nginx
+fi
+
+STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
+
+test -x $DAEMON || exit 0
+
+. /lib/init/vars.sh
+. /lib/lsb/init-functions
+
+# Try to extract nginx pidfile
+PID=$(cat /etc/nginx/nginx.conf | grep -Ev '^\s*#' | awk 'BEGIN { RS="[;{}]" } { if ($1 == "pid") print $2 }' | head -n1)
+if [ -z "$PID" ]; then
+        PID=/tmp/nginx.pid
+fi
+
+if [ -n "$ULIMIT" ]; then
+        # Set ulimit if it is set in /etc/default/nginx
+        ulimit $ULIMIT
+fi
+
+start_nginx() {
+        # Start the daemon/service
+        #
+        # Returns:
+        #   0 if daemon has been started
+        #   1 if daemon was already running
+        #   2 if daemon could not be started
+        start-stop-daemon --start --quiet --pidfile $PID --chuid www-data:www-data --exec $DAEMON --test > /dev/null \
+                || return 1
+        start-stop-daemon --start --quiet --pidfile $PID --chuid www-data:www-data --exec $DAEMON -- \
+                $DAEMON_OPTS 2>/dev/null \
+                || return 2
+}
+
+test_config() {
+        # Test the nginx configuration
+        $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
+}
+
+stop_nginx() {
+        # Stops the daemon/service
+        #
+        # Return
+        #   0 if daemon has been stopped
+        #   1 if daemon was already stopped
+        #   2 if daemon could not be stopped
+        #   other if a failure occurred
+        start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME
+        RETVAL="$?"
+        sleep 1
+        return "$RETVAL"
+}
+
+reload_nginx() {
+        # Function that sends a SIGHUP to the daemon/service
+        start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME
+        return 0
+}
+
+rotate_logs() {
+        # Rotate log files
+        start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME
+        return 0
+}
+
+upgrade_nginx() {
+        # Online upgrade nginx executable
+        # http://nginx.org/en/docs/control.html
+        #
+        # Return
+        #   0 if nginx has been successfully upgraded
+        #   1 if nginx is not running
+        #   2 if the pid files were not created on time
+        #   3 if the old master could not be killed
+        if start-stop-daemon --stop --signal USR2 --quiet --pidfile $PID --name $NAME; then
+                # Wait for both old and new master to write their pid file
+                while [ ! -s "${PID}.oldbin" ] || [ ! -s "${PID}" ]; do
+                        cnt=`expr $cnt + 1`
+                        if [ $cnt -gt 10 ]; then
+                                return 2
+                        fi
+                        sleep 1
+                done
+                # Everything is ready, gracefully stop the old master
+                if start-stop-daemon --stop --signal QUIT --quiet --pidfile "${PID}.oldbin" --name $NAME; then
+                        return 0
+                else
+                        return 3
+                fi
+        else
+                return 1
+        fi
+}
+
+case "$1" in
+        start)
+                log_daemon_msg "Starting $DESC" "$NAME"
+                start_nginx
+                case "$?" in
+                        0|1) log_end_msg 0 ;;
+                        2)   log_end_msg 1 ;;
+                esac
+                ;;
+        stop)
+                log_daemon_msg "Stopping $DESC" "$NAME"
+                stop_nginx
+                case "$?" in
+                        0|1) log_end_msg 0 ;;
+                        2)   log_end_msg 1 ;;
+                esac
+                ;;
+        restart)
+                log_daemon_msg "Restarting $DESC" "$NAME"
+
+                # Check configuration before stopping nginx
+                if ! test_config; then
+                        log_end_msg 1 # Configuration error
+                        exit $?
+                fi
+
+                stop_nginx
+                case "$?" in
+                        0|1)
+                                start_nginx
+                                case "$?" in
+                                        0) log_end_msg 0 ;;
+                                        1) log_end_msg 1 ;; # Old process is still running
+                                        *) log_end_msg 1 ;; # Failed to start
+                                esac
+                                ;;
+                        *)
+                                # Failed to stop
+                                log_end_msg 1
+                                ;;
+                esac
+                ;;
+        reload|force-reload)
+                log_daemon_msg "Reloading $DESC configuration" "$NAME"
+
+                # Check configuration before stopping nginx
+                #
+                # This is not entirely correct since the on-disk nginx binary
+                # may differ from the in-memory one, but that's not common.
+                # We prefer to check the configuration and return an error
+                # to the administrator.
+                if ! test_config; then
+                        log_end_msg 1 # Configuration error
+                        exit $?
+                fi
+
+                reload_nginx
+                log_end_msg $?
+                ;;
+        configtest|testconfig)
+                log_daemon_msg "Testing $DESC configuration"
+                test_config
+                log_end_msg $?
+                ;;
+        status)
+                status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
+                ;;
+        upgrade)
+                log_daemon_msg "Upgrading binary" "$NAME"
+                upgrade_nginx
+                log_end_msg $?
+                ;;
+        rotate)
+                log_daemon_msg "Re-opening $DESC log files" "$NAME"
+                rotate_logs
+                log_end_msg $?
+                ;;
+        *)
+                echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}" >&2
+                exit 3
+                ;;
+esac
\ No newline at end of file
diff --git a/config/nginx/nginx.conf b/config/nginx/nginx.conf
new file mode 100644
index 0000000..9af3b9e
--- /dev/null
+++ b/config/nginx/nginx.conf
@@ -0,0 +1,63 @@
+user www-data;
+worker_processes 1;
+pid /tmp/nginx.pid;
+
+events {
+        worker_connections 524288;
+        # multi_accept on;
+}
+
+http {
+
+        ##
+        # Basic Settings
+        ##
+
+        sendfile on;
+        tcp_nopush on;
+        tcp_nodelay on;
+        keepalive_timeout 65;
+        types_hash_max_size 2048;
+        # server_tokens off;
+
+        # server_names_hash_bucket_size 64;
+        # server_name_in_redirect off;
+
+        include /etc/nginx/mime.types;
+        default_type application/octet-stream;
+
+        ##
+        # SSL Settings
+        ##
+
+        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
+        ssl_prefer_server_ciphers on;
+
+        ##
+        # Logging Settings
+        ##
+
+        access_log off;
+        error_log /var/log/nginx/error.log;
+
+        ##
+        # Gzip Settings
+        ##
+
+        gzip on;
+        gzip_disable "msie6";
+
+        # gzip_vary on;
+        # gzip_proxied any;
+        # gzip_comp_level 6;
+        # gzip_buffers 16 8k;
+        # gzip_http_version 1.1;
+        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+        ##
+        # Virtual Host Configs
+        ##
+
+        include /etc/nginx/conf.d/*.conf;
+        include /etc/nginx/sites-enabled/*;
+}
\ No newline at end of file
diff --git a/config/supervisor/supervisor b/config/supervisor/supervisor
index 1e612e0..34046ea 100644
--- a/config/supervisor/supervisor
+++ b/config/supervisor/supervisor
@@ -30,8 +30,8 @@ DESC=supervisor
 
 test -x $DAEMON || exit 0
 
-LOGDIR=/var/log/supervisor
-PIDFILE=/var/run/$NAME.pid
+LOGDIR=/tmp
+PIDFILE=/tmp/$NAME.pid
 PS_COUNT=0
 DODTIME=5                   # Time to wait for the server to die, in seconds
                             # If this value is set too low you might not
@@ -101,7 +101,7 @@ case "$1" in
             rm -f "$PIDFILE"
         fi
 	echo -n "Starting $DESC: "
-	start-stop-daemon --start --quiet --pidfile $PIDFILE \
+	start-stop-daemon --start --quiet --chuid ds:ds --pidfile $PIDFILE \
 		--startas $DAEMON -- $DAEMON_OPTS
 	test -f $PIDFILE || sleep 1
         if running ; then
@@ -152,7 +152,7 @@ case "$1" in
     echo -n "Restarting $DESC: "
     start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
 	[ -n "$DODTIME" ] && sleep $DODTIME
-	start-stop-daemon --start --quiet --pidfile $PIDFILE \
+	start-stop-daemon --start --quiet --chuid ds:ds --pidfile $PIDFILE \
 		--startas $DAEMON -- $DAEMON_OPTS
 	echo "$NAME."
 	;;
diff --git a/config/supervisor/supervisord.conf b/config/supervisor/supervisord.conf
index 27ef634..d844de9 100644
--- a/config/supervisor/supervisord.conf
+++ b/config/supervisor/supervisord.conf
@@ -4,9 +4,9 @@
 port = 127.0.0.1:9001
 
 [supervisord]
-logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
-pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
-childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)
+logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+childlogdir=/tmp            ; ('AUTO' child log dir, default $TEMP)
 
 ; the below section must remain in the config file for RPC
 ; (supervisorctl/web interface) to work, additional interfaces may be
diff --git a/run-document-server.sh b/run-document-server.sh
index 67d26f4..37aa536 100755
--- a/run-document-server.sh
+++ b/run-document-server.sh
@@ -48,6 +48,8 @@ JSON="${JSON_BIN} -q -f ${ONLYOFFICE_DEFAULT_CONFIG}"
 JSON_LOG="${JSON_BIN} -q -f ${ONLYOFFICE_LOG4JS_CONFIG}"
 JSON_EXAMPLE="${JSON_BIN} -q -f ${ONLYOFFICE_EXAMPLE_CONFIG}"
 
+DS_PORT=${DS_PORT:-80}
+
 LOCAL_SERVICES=()
 
 PG_ROOT=/var/lib/postgresql
@@ -286,6 +288,8 @@ update_nginx_settings(){
     fi
   else
     ln -sf ${NGINX_ONLYOFFICE_PATH}/ds.conf.tmpl ${NGINX_ONLYOFFICE_CONF}
+    # set up default listening port
+    sed 's,\(listen.\+:\)\([0-9]\+\)\(.*;\),'"\1${DS_PORT}\3"',' -i ${NGINX_ONLYOFFICE_CONF}
   fi
 
   # check if ipv6 supported otherwise remove it from nginx config
@@ -303,6 +307,10 @@ update_supervisor_settings(){
   cp ${SYSCONF_TEMPLATES_DIR}/supervisor/supervisor /etc/init.d/
   # Copy modified supervisor config
   cp ${SYSCONF_TEMPLATES_DIR}/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
+  # Copy modified nginx start script
+  cp ${SYSCONF_TEMPLATES_DIR}/nginx/nginx /etc/init.d/
+  # Copy modified ngnix config
+  cp ${SYSCONF_TEMPLATES_DIR}/nginx/nginx.conf /etc/nginx/nginx.conf
 }
 
 update_log_settings(){
@@ -331,6 +339,9 @@ for i in ${LOG_DIR} ${LIB_DIR} ${DATA_DIR}; do
   chmod -R 755 "$i"
 done
 
+touch ${DS_LOG_DIR}/nginx.error.log
+chown www-data:www-data ${DS_LOG_DIR}/nginx.error.log
+
 if [ ${ONLYOFFICE_DATA_CONTAINER_HOST} = "localhost" ]; then
 
   read_setting