| |
| DIR=$(dirname "$0") |
| ROOT=${DIR}/.. |
| |
| SWTPM=swtpm |
| SWTPM_EXE=${SWTPM_EXE:-${ROOT}/src/swtpm/${SWTPM}} |
| SWTPM_IOCTL=${SWTPM_IOCTL:-${ROOT}/src/swtpm_ioctl/swtpm_ioctl} |
| SWTPM_BIOS=${SWTPM_BIOS:-${ROOT}/src/swtpm_bios/swtpm_bios} |
| ECHO=$(type -P echo) |
| |
| # Note: Do not use file descriptors above 127 due to OpenBSD. |
| |
| # Wait for a regular file to appear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_file() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -f "${filename}" ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a regular file to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_file_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -f "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a chardev to appear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_chardev() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -c "${filename}" ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a chardev to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_chardev_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -c "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a socket file to appear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_socketfile() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -S "${filename}" ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a socket file to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_socketfile_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -S "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a server socket to appear |
| # |
| # @1: port |
| # @2: host |
| # @3: timeout in seconds |
| function wait_for_serversocket() |
| { |
| local port="$1" |
| local host="$2" |
| local timeout="$3" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null |
| [ $? -eq 0 ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a server socket to disappear |
| # |
| # @1: port |
| # @2: host |
| # @3: timeout in seconds |
| function wait_serversocket_gone() |
| { |
| local port="$1" |
| local host="$2" |
| local timeout="$3" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null |
| [ $? -eq 0 ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Run the swtpm_ioctl command |
| # |
| # @param1: type of interface |
| function run_swtpm_ioctl() |
| { |
| local iface=$1; shift |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} $@ ${SWTPM_DEV_NAME} |
| return $? |
| ;; |
| socket+socket|unix+socket) |
| [ -z "${SWTPM_SERVER_NAME}" ] && { |
| echo "SWTPM_SERVER_NAME not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} \ |
| --tcp ${SWTPM_SERVER_NAME}:${SWTPM_CTRL_PORT} \ |
| $@ |
| return $? |
| ;; |
| socket+unix|unix+unix) |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} \ |
| --unix ${SWTPM_CTRL_UNIX_PATH} \ |
| $@ |
| return $? |
| ;; |
| esac |
| } |
| |
| # Start the swtpm in the background |
| # |
| # @param1: type of interface |
| # @param2.. : parameters to pass to 'swtpm' |
| function run_swtpm() |
| { |
| local iface=$1; shift |
| |
| echo "==== Starting swtpm with interfaces ${iface} ====" |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| |
| if wait_chardev_gone ${SWTPM_DEV_NAME} 2; then |
| echo "${SWTPM_DEV_NAME} is still there and may be used." |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} cuse $@ -n ${SWTPM_DEV_NAME##*/} |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| if wait_for_chardev ${SWTPM_DEV_NAME} 2; then |
| echo "$SWTPM_DEV_NAME did not appear" |
| exit 1 |
| fi |
| |
| SWTPM_PID=$(ps aux | |
| grep "cuse" | |
| grep -E " ${SWTPM_DEV_NAME##*/}\$" | |
| grep -v grep | |
| gawk '{print $2}') |
| return $? |
| ;; |
| socket+socket) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_PORT}" ] && { |
| echo "SWTPM_CTRL_PORT not defined" |
| exit 1 |
| } |
| |
| if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Port ${SWTPM_SERVER_PORT} is still used" |
| exit 1 |
| fi |
| if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Port ${SWTPM_CTRL_PORT} is still used" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket $@ \ |
| --server type=tcp,port=${SWTPM_SERVER_PORT},disconnect \ |
| --ctrl type=tcp,port=${SWTPM_CTRL_PORT} & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Server did not open port ${SWTPM_SERVER_PORT}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Server did not open port ${SWTPM_CTRL_PORT}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| return 0 |
| ;; |
| socket+unix) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| |
| if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Port ${SWTPM_SERVER_PORT} is still used" |
| exit 1 |
| fi |
| if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket $@ \ |
| --server type=tcp,port=${SWTPM_SERVER_PORT},disconnect \ |
| --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| [ $rc -ne 0 ] && return $rc |
| SWTPM_PID=$! |
| if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Server did not open port ${SWTPM_SERVER_PORT}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then |
| echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| return 0 |
| ;; |
| unix+socket) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_PORT}" ] && { |
| echo "SWTPM_CTRL_PORT not defined" |
| exit 1 |
| } |
| |
| if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Port ${SWTPM_CTRL_PORT} is still used" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket $@ \ |
| --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \ |
| --ctrl type=tcp,port=${SWTPM_CTRL_PORT} & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then |
| echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Server did not open port ${SWTPM_CTRL_PORT}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| return 0 |
| ;; |
| unix+unix) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| |
| if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket $@ \ |
| --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \ |
| --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then |
| echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then |
| echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}" |
| kill -9 ${SWTPM_PID} |
| exit 1 |
| fi |
| return 0 |
| ;; |
| esac |
| } |
| |
| # Open the command channel/device on fd 100 |
| # |
| # @param1: type of interface |
| # @param2: must be '100' |
| function swtpm_open_cmddev() |
| { |
| local iface=$1; shift |
| |
| [ "$1" != "100" ] && { |
| echo "swtpm_opendev: Filedescriptor must be 100" |
| exit 1 |
| } |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| exec 100<>${SWTPM_DEV_NAME} |
| return $? |
| ;; |
| socket+socket|socket+unix) |
| [ -z "${SWTPM_SERVER_NAME}" ] && { |
| echo "SWTPM_SERVER_NAME not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| exec 100<>/dev/tcp/${SWTPM_SERVER_NAME}/${SWTPM_SERVER_PORT} |
| return $? |
| ;; |
| unix+socket|unix+unix) |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| # Transmit a command on fd 100 |
| # |
| # @param1: type of interface |
| function swtpm_cmd_tx() |
| { |
| local iface=$1 |
| local cmd_path resp_path |
| |
| cmd_path=$(mktemp) |
| |
| case "${iface}" in |
| cuse) |
| echo -en "$2" > ${cmd_path} |
| cat ${cmd_path} >&100 |
| dd if=/proc/self/fd/100 2>/dev/null | \ |
| od -t x1 -A n | \ |
| tr -s ' ' | \ |
| tr -d '\n' | \ |
| sed 's/ $//g' |
| ;; |
| socket+socket|socket+unix) |
| echo -en "$2" > ${cmd_path} |
| cat ${cmd_path} >&100 |
| cat <&100 | od -t x1 -A n | \ |
| tr -s ' ' | \ |
| tr -d '\n' | \ |
| sed 's/ $//g' |
| ;; |
| unix+socket|unix+unix) |
| echo -en "$2" > ${cmd_path} |
| socat -x -t50 \ |
| FILE:${cmd_path},rdonly \ |
| UNIX-CLIENT:${SWTPM_CMD_UNIX_PATH} 2>&1 | \ |
| sed -n '/^ /p' | \ |
| tail -n1 |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| rm -f ${cmd_path} |
| exit 1 |
| esac |
| |
| rm -f ${cmd_path} |
| } |
| |
| # Transmit a control command on fd 101 |
| # |
| # @param1: type of interface |
| function swtpm_ctrl_tx() |
| { |
| local iface=$1 |
| local ctrl_path resp_path |
| |
| case "${iface}" in |
| socket+socket|unix+socket) |
| $ECHO -en "$2" >&101 |
| cat <&101 | od -t x1 -A n -w128 |
| ;; |
| socket+unix|unix+unix) |
| ctrl_path=$(mktemp) |
| echo -en "$2" > ${ctrl_path} |
| socat -x -t50 \ |
| FILE:${ctrl_path},rdonly \ |
| UNIX-CLIENT:${SWTPM_CTRL_UNIX_PATH} 2>&1 | \ |
| sed -n '/^ /p' | \ |
| tail -n1 |
| rm -f ${ctrl_path} |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| |
| # Run swtpm_bios |
| # |
| # @param1: type of interface |
| # @param2 ...: parameters to pass to swtpm_bios |
| function run_swtpm_bios() |
| { |
| local iface=$1 |
| |
| shift |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --tpm-device ${SWTPM_DEV_NAME} $@ |
| return $? |
| ;; |
| unix+unix|unix+socket) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --unix ${SWTPM_CMD_UNIX_PATH} $@ |
| return $? |
| ;; |
| socket+unix|socket+socket) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --tcp ${SWTPM_SERVER_NAME}:${SWTPM_SERVER_PORT} $@ |
| return $? |
| ;; |
| *) |
| echo "run_swtpm_bios: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| # Get the size of a file in bytes |
| # |
| # @1: filename |
| function get_filesize() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| stat -c%s $1 |
| else |
| # OpenBSD |
| stat -f%z $1 |
| fi |
| } |
| |
| # Get the SHA1 of a file |
| # |
| # @1: filename |
| function get_sha1_file() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| sha1sum $1 | cut -f1 -d" " |
| else |
| # OpenBSD |
| sha1 $1 | cut -d "=" -f2 | tr -d " " |
| fi |
| } |