Skip to content
Snippets Groups Projects
Verified Commit b9b36f48 authored by Dominik George's avatar Dominik George
Browse files

Initial commit.

parents
Branches
Tags
No related merge requests found
stracify 0 → 100755
#!/bin/mksh
#-
# Copyright 2017 Dominik George <d.george@tarent.de>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#-
# Wrapper to run a certain binary wrapped with a call to strace.
# Tries to break as few things as possible if anything goes wrong.
# Strip any path components from $0
called=${0##*/}
# Configuration
DATADIR=/var/log/stracify
# Override configuration from local sysconfig
[[ -e /etc/default/stracify ]] && . /etc/default/stracify
[[ -e /etc/sysconfig/stracify ]] && . /etc/sysconfig/stracify
# Helper functions
die() {
print -u2 -r -- "$1"
exit 1
}
usage() {
cat <<-EOF
Usage: stracify <wrap|unwrap> <path> [filter]
EOF
}
get_distro() {
# Tries to determine the running distribution
# Used to determine best way to divert files
if [[ -e /etc/debian_version ]]; then
echo "Debian"
else
echo "unknown"
fi
}
get_normpath() {
# Normalise a path for use as log directory name
normpath=${1#/}
normpath=${normpath//_/__}
normpath=${normpath//\//_}
echo "$normpath"
}
if [[ "$called" = "stracify" ]]; then
# We were called verbatim - management mode
# Check root access
[[ $(id -u) = 0 ]] || die "stracify must be run as root."
# Ensure existence of stuff
mkdir -p "$DATADIR" || die "Could not create data directory $DATADIR."
# Determine action to be taken
case "$1" in
"wrap")
# Wrap a binary - arguments: path to wrap and optional strace fitler expression
path=$2; filter=$3
# Do sanity checks on path
if [[ -z "$path" ]]; then
usage
die "Invalid arguments."
fi
if [[ "$path" = "${path#/}" ]]; then
die "Path must be absolute."
fi
if ! [[ -x "$path" ]]; then
die "$path is not executable or does not exist."
fi
# Check whether the binary might already be stracified
if [[ -e "$path.unstracified" ]]; then
die "$path seems to be already stracified"
fi
# Create log directory for this binary
# Ensure to make it world-accessible, so all users can call the
# wrapped bianry.
normpath=$(get_normpath "$path")
mkdir -p "$DATADIR/$normpath"
chmod 3777 "$DATADIR/$normpath"
# Store fitler expression, if any
echo "$filter" > "$DATADIR/$normpath/filter"
chmod 644 "$DATADIR/$normpath/filter"
# Store extended ACLs of the original file
if [[ -x "$(which setfacl)" ]]; then
aclfile=$(mktemp)
getfacl "$path" >"$aclfile" 2>/dev/null
fi
# Now do the real diversion
case "$(get_distro)" in
"Debian")
# We can add a real diversion so it will survive package updates, etc.
dpkg-divert --quiet --local --rename --divert "$path.unstracified" "$path"
;;
*)
# Fall back to just moving the binary
mv "$path" "$path.unstracified"
;;
esac
# Install stracify wrapper
# This is needed because symlinks do not have access and owner flags
# FIXME: Ensure updateing the wrapper if necessary
# FIXME: Use a C program isntead to also capture SUID/SGID
cp "$(realpath "$0")" "$path"
# Restore all modes of the original file
chown --reference="$path.unstracified" "$path"
chmod --reference="$path.unstracified" "$path"
if [[ -x "$(which setfacl)" ]]; then
cd /; setfacl --restore="$aclfile"; cd - >/dev/null
rm -f "$aclfile"
fi
;;
"unwrap")
path=$2
if [[ -z "$path" ]]; then
usage
die "Invalid arguments."
fi
if [[ "$path" = "${path#/}" ]]; then
die "Path must be absolute."
fi
if ! [[ -x "$path" ]]; then
die "$path is not executable or does not exist."
fi
if ! [[ -e "$path.unstracified" ]]; then
die "No unstracified version of $path found."
fi
rm -f "$path"
case "$(get_distro)" in
"Debian")
dpkg-divert --quiet --local --rename --divert "$path.unstracified" --remove "$path"
;;
*)
mv "$path.unstracified" "$path"
;;
esac
;;
*)
usage
die "Invalid arguments."
;;
esac
else
# We got called as a wrapped binary
# Determine real path of the called binary
path=$0
# Check that the called binary is stracified
normpath=$(get_normpath "$path")
if [[ -d "$DATADIR/$normpath" ]]; then
# Assemble strace fitler option
filter=$(<"$DATADIR/$normpath/filter")
[[ -n "$filter" ]] && filter="-e $filter"
# Create a log directory for our user
user=$(id -nu)
mkdir -p "$DATADIR/$normpath/$user"
chmod 750 "$DATADIR/$normpath/$user"
# Assemble log file name
datestr=$(date -Iseconds)
logfile="strace_${datestr}_$$.log"
# Call binary wrapped in strace
exec strace -o "$DATADIR/$normpath/$user/$logfile" -ff -tt -T -yy $filter mksh -c "exec -a '$0' '$0.unstracified' '$@'"
else
# Try to call a possibly incompletely stracified binary
if [[ -x "$path.stracified" ]]; then
# Pass execution to the guessed binary
exec "$path.unstracified" "$@"
else
# We are skrewed. Make the caller think the binary is non-existent
echo "stracify: $0: command not found"
exit 127
fi
fi
fi
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment