#!/bin/bash
##CageFS proxyexec wrapper - ver 18

if [[ $EUID -eq 0 ]]; then
    echo 'Cannot be run as root'
    exit 1
fi

# POSIX single-quote escaping for values embedded in the ssh remote
# command. Unlike `printf %q`, single-quoted output re-parses correctly
# under any POSIX shell (the origin login shell need not be bash) and is
# lossless for arbitrary bytes. Each embedded ' becomes the '\'' sequence.
sq() {
    local s=${1//\'/\'\\\'\'}
    printf "'%s'" "$s"
}

USR=`/usr/bin/whoami`
CWD=`pwd`
TOKEN=`/bin/cat /var/.cagefs/.cagefs.token`
# It's user's tmp directory and write to it is secure procedure
# because this script is running only under usual user
LOCKFILE=/tmp/.crontab.lock

# automatically obtain next available fd
# previous strategy with `ulimit -n` failed
# in environment where limit is very high (e.g. 1073741816)
exec {FD}>$LOCKFILE

# Sibling-wrapper hardening of the same command-injection vector named
# in cagefs.proxy.program for F-05 / CLOS-4596: caller-controlled $CWD
# (`pwd` — attacker controls via mkdir+cd inside the cage), $USR and
# $TOKEN are embedded into a command that runs under `eval` (needed for
# the `$FD> $LOCKFILE` dynamic-fd redirection). Single-quote each value
# with sq() so metacharacters cannot be re-interpreted. The number of
# quoting passes must match the number of shell re-parses the value
# crosses, which depends on the mode:
if [[ -e /var/.cagefs/origin ]]; then
    ORIGIN=`/bin/cat /var/.cagefs/origin`
    REMOTE="/usr/bin/ssh -F /etc/ssh/cagefs-rexec_config $USR@$ORIGIN"
    # Distributed mode: the eval'd command is shipped by ssh and the
    # origin login shell re-parses it, so values cross TWO re-parses
    # (local eval, then remote shell) — quote twice.
    Q_USR=$(sq "$(sq "$USR")")
    Q_CWD=$(sq "$(sq "$CWD")")
    Q_TOKEN=$(sq "$(sq "$TOKEN")")
else
    REMOTE=""
    # Local mode: the eval'd command runs here with no ssh hop, so values
    # cross only ONE re-parse (the eval) — quote once. A second pass would
    # survive the single eval as literal quote characters and corrupt the
    # arguments proxyexec receives.
    Q_USR=$(sq "$USR")
    Q_CWD=$(sq "$CWD")
    Q_TOKEN=$(sq "$TOKEN")
fi

eval "(
    /usr/bin/flock -x -w 10 $FD || exit 1
    echo -n \"\" | $REMOTE CAGEFS_TOKEN=$Q_TOKEN /usr/sbin/proxyexec -c cagefs.sock $Q_USR $Q_CWD CRONTAB_CHECK $$
) $FD> $LOCKFILE"

[ $? -ne 0 ] && exit 1

eval "(
  /usr/bin/flock -x -w 10 $FD || exit 1
$REMOTE CAGEFS_TOKEN=$Q_TOKEN /usr/sbin/proxyexec -c cagefs.sock $Q_USR $Q_CWD CRONTAB_LIST $$ 2>/dev/null |cat > /var/spool/cron/$USR
) $FD> $LOCKFILE"

/usr/bin/crontab.cagefs $@

eval "(
  /usr/bin/flock -x -w 10 $FD || exit 1
if [ -e /var/spool/cron/$USR ]; then
        cat /var/spool/cron/$USR | $REMOTE CAGEFS_TOKEN=$Q_TOKEN /usr/sbin/proxyexec -c cagefs.sock $Q_USR $Q_CWD CRONTAB_SAVE $$ 2>/dev/null
else
        echo -n \"\" | $REMOTE CAGEFS_TOKEN=$Q_TOKEN /usr/sbin/proxyexec -c cagefs.sock $Q_USR $Q_CWD CRONTAB_SAVE $$ 2>/dev/null
fi
) $FD>$LOCKFILE"
