aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/dtracetoolkit/Apps/shellsnoop
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/dtracetoolkit/Apps/shellsnoop')
-rwxr-xr-xcddl/contrib/dtracetoolkit/Apps/shellsnoop264
1 files changed, 264 insertions, 0 deletions
diff --git a/cddl/contrib/dtracetoolkit/Apps/shellsnoop b/cddl/contrib/dtracetoolkit/Apps/shellsnoop
new file mode 100755
index 000000000000..69ff379a6519
--- /dev/null
+++ b/cddl/contrib/dtracetoolkit/Apps/shellsnoop
@@ -0,0 +1,264 @@
+#!/bin/sh
+#
+# shellsnoop - A program to print read/write details from shells,
+# such as keystrokes and command outputs.
+# Written using DTrace (Solaris 10 3/05).
+#
+# This program sounds somewhat dangerous (snooping keystrokes), but is
+# no more so than /usr/bin/truss, and both need root or dtrace privileges to
+# run. In fact, less dangerous, as we only print visible text (not password
+# text, for example). Having said that, it goes without saying that this
+# program shouldn't be used for breeching privacy of other users.
+#
+# This was written as a tool to demonstrate the capabilities of DTrace.
+#
+# $Id: shellsnoop 19 2007-09-12 07:47:59Z brendan $
+#
+# USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]
+#
+# -q # quiet, only print data
+# -s # include start time, us
+# -v # include start time, string
+# -p PID # process ID to snoop
+# -u UID # user ID to snoop
+# eg,
+# shellsnoop # default output
+# shellsnoop -v # human readable timestamps
+# shellsnoop -p 1892 # snoop this PID only
+# shellsnoop -qp 1892 # watch this PID data only
+#
+# FIELDS:
+# UID User ID
+# PID process ID
+# PPID parent process ID
+# COMM command name
+# DIR direction (R read, W write)
+# TEXT text contained in the read/write
+# TIME timestamp for the command, us
+# STRTIME timestamp for the command, string
+#
+# SEE ALSO: ttywatcher
+#
+# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at Docs/cddl1.txt
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# CDDL HEADER END
+#
+# Author: Brendan Gregg [Sydney, Australia]
+#
+# 28-Mar-2004 Brendan Gregg Created this.
+# 21-Jan-2005 " " Wrapped in sh to provide options.
+# 30-Nov-2005 " " Fixed trailing buffer text bug.
+# 30-Nov-2005 " " Fixed sh no keystroke text in quiet bug.
+# 30-Nov-2005 " " Last update.
+#
+
+
+##############################
+# --- Process Arguments ---
+#
+opt_pid=0; opt_uid=0; opt_time=0; opt_timestr=0; opt_quiet=0; opt_debug=0
+filter=0; pid=0; uid=0
+
+while getopts dhp:qsu:v name
+do
+ case $name in
+ d) opt_debug=1 ;;
+ p) opt_pid=1; pid=$OPTARG ;;
+ q) opt_quiet=1 ;;
+ s) opt_time=1 ;;
+ u) opt_uid=1; uid=$OPTARG ;;
+ v) opt_timestr=1 ;;
+ h|?) cat <<-END >&2
+ USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]
+ shellsnoop # default output
+ -q # quiet, only print data
+ -s # include start time, us
+ -v # include start time, string
+ -p PID # process ID to snoop
+ -u UID # user ID to snoop
+ END
+ exit 1
+ esac
+done
+
+if [ $opt_quiet -eq 1 ]; then
+ opt_time=0; opt_timestr=0
+fi
+if [ $opt_pid -eq 1 -o $opt_uid -eq 1 ]; then
+ filter=1
+fi
+
+
+#################################
+# --- Main Program, DTrace ---
+#
+dtrace -n '
+ /*
+ * Command line arguments
+ */
+ inline int OPT_debug = '$opt_debug';
+ inline int OPT_quiet = '$opt_quiet';
+ inline int OPT_pid = '$opt_pid';
+ inline int OPT_uid = '$opt_uid';
+ inline int OPT_time = '$opt_time';
+ inline int OPT_timestr = '$opt_timestr';
+ inline int FILTER = '$filter';
+ inline int PID = '$pid';
+ inline int UID = '$uid';
+
+ #pragma D option quiet
+ #pragma D option switchrate=20hz
+
+ /*
+ * Print header
+ */
+ dtrace:::BEGIN /OPT_time == 1/
+ {
+ printf("%-14s ","TIME");
+ }
+ dtrace:::BEGIN /OPT_timestr == 1/
+ {
+ printf("%-20s ","STRTIME");
+ }
+ dtrace:::BEGIN /OPT_quiet == 0/
+ {
+ printf("%5s %5s %8s %3s %s\n", "PID", "PPID", "CMD", "DIR", "TEXT");
+ }
+
+ /*
+ * Remember this PID is a shell child
+ */
+ syscall::execve:entry
+ /execname == "sh" || execname == "ksh" || execname == "csh" ||
+ execname == "tcsh" || execname == "zsh" || execname == "bash"/
+ {
+ child[pid] = 1;
+
+ }
+ syscall::execve:entry
+ /(OPT_pid == 1 && PID != ppid) || (OPT_uid == 1 && UID != uid)/
+ {
+ /* forget if filtered */
+ child[pid] = 0;
+ }
+
+ /*
+ * Print shell keystrokes
+ */
+ syscall::write:entry, syscall::read:entry
+ /(execname == "sh" || execname == "ksh" || execname == "csh" ||
+ execname == "tcsh" || execname == "zsh" || execname == "bash")
+ && (arg0 >= 0 && arg0 <= 2)/
+ {
+ self->buf = arg1;
+ }
+ syscall::write:entry, syscall::read:entry
+ /(OPT_pid == 1 && PID != pid) || (OPT_uid == 1 && UID != uid)/
+ {
+ self->buf = 0;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_time == 1/
+ {
+ printf("%-14d ", timestamp/1000);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_timestr == 1/
+ {
+ printf("%-20Y ", walltimestamp);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0 && OPT_quiet == 0/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+
+ printf("%5d %5d %8s %3s %s\n", pid, curpsinfo->pr_ppid, execname,
+ probefunc == "read" ? "R" : "W", stringof(this->text));
+ }
+ syscall::write:return
+ /self->buf && child[pid] == 0 && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ }
+ syscall::read:return
+ /self->buf && execname == "sh" && child[pid] == 0 && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && child[pid] == 0/
+ {
+ self->buf = 0;
+ }
+
+ /*
+ * Print command output
+ */
+ syscall::write:entry, syscall::read:entry
+ /child[pid] == 1 && (arg0 == 1 || arg0 == 2)/
+ {
+ self->buf = arg1;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_time == 1/
+ {
+ printf("%-14d ", timestamp/1000);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_timestr == 1/
+ {
+ printf("%-20Y ", walltimestamp);
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_quiet == 0/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+
+ printf("%5d %5d %8s %3s %s", pid, curpsinfo->pr_ppid, execname,
+ probefunc == "read" ? "R" : "W", stringof(this->text));
+
+ /* here we check if a newline is needed */
+ this->length = strlen(this->text);
+ printf("%s", this->text[this->length - 1] == '\'\\n\'' ? "" : "\n");
+ self->buf = 0;
+ }
+ syscall::write:return, syscall::read:return
+ /self->buf && OPT_quiet == 1/
+ {
+ this->text = (char *)copyin(self->buf, arg0);
+ this->text[arg0] = '\'\\0\'';
+ printf("%s", stringof(this->text));
+ self->buf = 0;
+ }
+
+ /*
+ * Cleanup
+ */
+ syscall::exit:entry
+ {
+ child[pid] = 0;
+
+ /* debug */
+ this->parent = (char *)curthread->td_proc->p_pptr->p_comm;
+ OPT_debug == 1 ? printf("PID %d CMD %s exited. (%s)\n",
+ pid, execname, stringof(this->parent)) : 1;
+ }
+'