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

Initial commit.

parents
No related branches found
No related tags found
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.
Finish editing this message first!
Please register or to comment