{"id":515,"date":"2011-10-05T15:31:44","date_gmt":"2011-10-05T19:31:44","guid":{"rendered":"http:\/\/theblane.com\/blog\/?p=515"},"modified":"2011-10-05T15:31:44","modified_gmt":"2011-10-05T19:31:44","slug":"solaris-d-shell-snooping","status":"publish","type":"post","link":"http:\/\/www.theblane.com\/blog\/archives\/515","title":{"rendered":"Solaris  &#8211; D &#8211; Shell snooping"},"content":{"rendered":"<p>#!\/usr\/bin\/sh<br \/>\n#<br \/>\n# shellsnoop &#8211; A program to print read\/write details from shells,<br \/>\n#       such as keystrokes and command outputs.<br \/>\n#       Written using DTrace (Solaris 10 build 69).<br \/>\n#<br \/>\n# 21-Jan-2005, ver 0.80         (check for newer versions)<br \/>\n#<br \/>\n#<br \/>\n# USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]<br \/>\n#<br \/>\n#       shellsnoop      # default output<br \/>\n#<br \/>\n#       -s              # include start time, us<br \/>\n#       -q              # quiet, only print data<br \/>\n#       -v              # include start time, string<br \/>\n#       -p PID          # process ID to snoop<br \/>\n#       -u UID          # user ID to snoop<br \/>\n#<br \/>\n#  eg,<br \/>\n#       shellsnoop -v           # human readable timestamps<br \/>\n#       shellsnoop -p 1892      # snoop this PID only<br \/>\n#       shellsnoop -qp 1892     # watch this PID data only<br \/>\n#<br \/>\n# FIELDS:<br \/>\n#<br \/>\n#       UID             User ID<br \/>\n#       PID             process ID<br \/>\n#       PPID            parent process ID<br \/>\n#       COMM            command name<br \/>\n#       DIR             direction (R read, W write)<br \/>\n#       TEXT            text contained in the read\/write<br \/>\n#       TIME            timestamp for the command, us<br \/>\n#       STRTIME         timestamp for the command, string<br \/>\n#<br \/>\n# SEE ALSO: ttywatcher<br \/>\n#<br \/>\n# Standard Disclaimer: This is freeware, use at your own risk.<br \/>\n#<br \/>\n# Author: Brendan Gregg  [Sydney, Australia]<br \/>\n#<br \/>\n# 28-Mar-2004   Brendan Gregg   Created this.<br \/>\n# 21-Jan-2005      &#8221;      &#8221;     Wrapped in sh to provide options.<br \/>\n#<\/p>\n<p>##############################<br \/>\n# &#8212; Process Arguments &#8212;<br \/>\n#<br \/>\nopt_pid=0; opt_uid=0; opt_time=0; opt_timestr=0; opt_quiet=0; opt_debug=0<br \/>\nfilter=0; pid=0; uid=0<\/p>\n<p>while getopts dhp:qsu:v name<br \/>\ndo<br \/>\n        case $name in<br \/>\n        d)      opt_debug=1 ;;<br \/>\n        p)      opt_pid=1; pid=$OPTARG ;;<br \/>\n        q)      opt_quiet=1 ;;<br \/>\n        s)      opt_time=1 ;;<br \/>\n        u)      opt_uid=1; uid=$OPTARG ;;<br \/>\n        v)      opt_timestr=1 ;;<br \/>\n h|?)    cat <<-END >&#038;2<br \/>\n                USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]<br \/>\n                       shellsnoop               # default output<br \/>\n                                -q              # quiet, only print data<br \/>\n                                -s              # include start time, us<br \/>\n                                -v              # include start time, string<br \/>\n                                -p PID          # process ID to snoop<br \/>\n                                -u UID          # user ID to snoop<br \/>\n                END<br \/>\n                exit 1<br \/>\n        esac<br \/>\ndone<\/p>\n<p>if [ $opt_quiet -eq 1 ]; then<br \/>\n        opt_time=0; opt_timestr=0<br \/>\nfi<br \/>\nif [ $opt_pid -eq 1 -o $opt_uid -eq 1 ]; then<br \/>\n        filter=1<br \/>\nfi<\/p>\n<p>#################################<br \/>\n# &#8212; Main Program, DTrace &#8212;<br \/>\n#<br \/>\ndtrace -n &#8216;<br \/>\n \/*<br \/>\n **  Command line arguments<br \/>\n *\/<br \/>\n inline int OPT_debug   = &#8216;$opt_debug&#8217;;<br \/>\n inline int OPT_quiet   = &#8216;$opt_quiet&#8217;;<br \/>\n inline int OPT_pid     = &#8216;$opt_pid&#8217;;<br \/>\n inline int OPT_uid     = &#8216;$opt_uid&#8217;;<br \/>\n inline int OPT_time    = &#8216;$opt_time&#8217;;<br \/>\n inline int OPT_timestr = &#8216;$opt_timestr&#8217;;<br \/>\n inline int FILTER      = &#8216;$filter&#8217;;<br \/>\n inline int PID         = &#8216;$pid&#8217;;<br \/>\n inline int UID         = &#8216;$uid&#8217;;<\/p>\n<p> #pragma D option quiet<\/p>\n<p> \/*<br \/>\n **  Print header<br \/>\n *\/<br \/>\n dtrace:::BEGIN \/OPT_time == 1\/ {<br \/>\n        printf(&#8220;%-14s &#8220;,&#8221;TIME&#8221;);<br \/>\n }<br \/>\n dtrace:::BEGIN \/OPT_timestr == 1\/ {<br \/>\n        printf(&#8220;%-20s &#8220;,&#8221;STRTIME&#8221;);<br \/>\n }<br \/>\n dtrace:::BEGIN \/OPT_quiet == 0\/ {<br \/>\n        printf(&#8220;%5s %5s %8s %3s  %s\\n&#8221;,&#8221;PID&#8221;,&#8221;PPID&#8221;,&#8221;CMD&#8221;,&#8221;DIR&#8221;,&#8221;TEXT&#8221;);<br \/>\n }<\/p>\n<p> \/*<br \/>\n **  Remember this PID is a shell child<br \/>\n *\/<br \/>\n syscall::exec:entry, syscall::exece:entry<br \/>\n \/execname == &#8220;sh&#8221;   || execname == &#8220;ksh&#8221;  || execname == &#8220;csh&#8221;  ||<br \/>\n  execname == &#8220;tcsh&#8221; || execname == &#8220;zsh&#8221;  || execname == &#8220;bash&#8221;\/<br \/>\n{<br \/>\n        child[pid] = 1;<\/p>\n<p>        \/* debug *\/<br \/>\n        this->parent = (char *)curthread->t_procp->p_parent->p_user.u_comm;<br \/>\n        OPT_debug == 1 ? printf(&#8220;PID %d CMD %s started. (%s)\\n&#8221;,<br \/>\n         pid, execname, stringof(this->parent)) : 1;<br \/>\n }<br \/>\n syscall::exec:entry, syscall::exece:entry<br \/>\n \/(OPT_pid == 1 &#038;&#038; PID != ppid) || (OPT_uid == 1 &#038;&#038; UID != uid)\/<br \/>\n {<br \/>\n        \/* forget if filtered *\/<br \/>\n        child[pid] = 0;<br \/>\n }<\/p>\n<p> \/*<br \/>\n **  Print shell keystrokes<br \/>\n *\/<br \/>\n syscall::write:entry, syscall::read:entry<br \/>\n \/(execname == &#8220;sh&#8221;   || execname == &#8220;ksh&#8221;  || execname == &#8220;csh&#8221;  ||<br \/>\n  execname == &#8220;tcsh&#8221; || execname == &#8220;zsh&#8221;  || execname == &#8220;bash&#8221;)<br \/>\n  &#038;&#038; (arg0 >= 0 &#038;&#038; arg0 <= 2)\/\n {\n        self->buf = arg1;<br \/>\n        self->len = arg2;<br \/>\n }<br \/>\n syscall::write:entry, syscall::read:entry<br \/>\n \/(OPT_pid == 1 &#038;&#038; PID != pid) || (OPT_uid == 1 &#038;&#038; UID != uid)\/<br \/>\n {<br \/>\n        self->buf = NULL;<br \/>\n        self->len = 0;<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; child[pid] == 0 &#038;&#038; OPT_time == 1\/ {<br \/>\n        printf(&#8220;%-14d &#8220;,timestamp\/1000);<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; child[pid] == 0 &#038;&#038; OPT_timestr == 1\/ {<br \/>\n        printf(&#8220;%-20Y &#8220;,walltimestamp);<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; child[pid] == 0 &#038;&#038; OPT_quiet == 0\/<br \/>\n {<br \/>\n        this->text = (char *)copyin(self->buf, self->len);<\/p>\n<p>        printf(&#8220;%5d %5d %8s %3s  %s\\n&#8221;, pid, curpsinfo->pr_ppid, execname,<br \/>\n            probefunc == &#8220;read&#8221; ? &#8220;R&#8221; : &#8220;W&#8221;, stringof(this->text));<br \/>\n        self->buf = NULL;<br \/>\n        self->len = 0;<br \/>\n }<br \/>\n syscall::write:return<br \/>\n \/self->buf != NULL &#038;&#038; child[pid] == 0 &#038;&#038; OPT_quiet == 1\/<br \/>\n {<br \/>\n        this->text = (char *)copyin(self->buf, self->len);<br \/>\n        printf(&#8220;%s&#8221;,stringof(this->text));<br \/>\n        self->buf = NULL;<br \/>\nself->len = 0;<br \/>\n }<br \/>\n syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; child[pid] == 0 &#038;&#038; OPT_quiet == 1\/<br \/>\n {<br \/>\n        self->buf = NULL;<br \/>\n        self->len = 0;<br \/>\n }<\/p>\n<p> \/*<br \/>\n **  Print command output<br \/>\n *\/<br \/>\n syscall::write:entry, syscall::read:entry<br \/>\n \/child[pid] == 1 &#038;&#038; (arg0 == 1 || arg0 == 2)\/<br \/>\n {<br \/>\n        self->buf = arg1;<br \/>\n        self->len = arg2;<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; OPT_time == 1\/ {<br \/>\n        printf(&#8220;%-14d &#8220;,timestamp\/1000);<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; OPT_timestr == 1\/ {<br \/>\n        printf(&#8220;%-20Y &#8220;,walltimestamp);<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; OPT_quiet == 0\/<br \/>\n {<br \/>\n        this->text = (char *)copyin(self->buf, self->len);<\/p>\n<p>        printf(&#8220;%5d %5d %8s %3s  %s&#8221;, pid, curpsinfo->pr_ppid, execname,<br \/>\n            probefunc == &#8220;read&#8221; ? &#8220;R&#8221; : &#8220;W&#8221;, stringof(this->text));<\/p>\n<p>        \/* here we check if a newline is needed *\/<br \/>\n        this->length = strlen(this->text);<br \/>\n        printf(&#8220;%s&#8221;, this->text[this->length &#8211; 1] == &#8216;\\&#8217;\\\\n\\&#8221; ? &#8220;&#8221; : &#8220;\\n&#8221;);<br \/>\n        self->buf = NULL;<br \/>\n        self->len = 0;<br \/>\n }<br \/>\n syscall::write:return, syscall::read:return<br \/>\n \/self->buf != NULL &#038;&#038; OPT_quiet == 1\/<br \/>\n {<br \/>\n        this->text = (char *)copyin(self->buf, self->len);<br \/>\n        printf(&#8220;%s&#8221;,stringof(this->text));<br \/>\n        self->buf = NULL;<br \/>\n        self->len = 0;<br \/>\n }<\/p>\n<p> \/*<br \/>\n **  Cleanup<br \/>\n *\/<br \/>\n fbt:genunix:exit:entry<br \/>\n {<br \/>\n        child[pid] = 0;<\/p>\n<p>        \/* debug *\/<br \/>\n        this->parent = (char *)curthread->t_procp->p_parent->p_user.u_comm;<br \/>\n        OPT_debug == 1 ? printf(&#8220;PID %d CMD %s exited. (%s)\\n&#8221;,<br \/>\n         pid,execname, stringof(this->parent)) : 1;<br \/>\n }<br \/>\n&#8216;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>#!\/usr\/bin\/sh # # shellsnoop &#8211; A program to print read\/write details from shells, # such as keystrokes and command outputs.&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,10],"tags":[],"class_list":["post-515","post","type-post","status-publish","format-standard","hentry","category-computer-stuff","category-solaris"],"_links":{"self":[{"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/posts\/515","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/comments?post=515"}],"version-history":[{"count":1,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/posts\/515\/revisions"}],"predecessor-version":[{"id":516,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/posts\/515\/revisions\/516"}],"wp:attachment":[{"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/media?parent=515"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/categories?post=515"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.theblane.com\/blog\/wp-json\/wp\/v2\/tags?post=515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}