From: "Miloslav Trmač" <mitr@redhat.com>
To: linux-audit <linux-audit@redhat.com>
Subject: [PATCH, RFC] Interpretation of TTY audit logs
Date: Tue, 16 Sep 2008 17:32:22 +0000 [thread overview]
Message-ID: <1221586342.2814.33.camel@amilo> (raw)
[-- Attachment #1: Type: text/plain, Size: 1847 bytes --]
Hello,
the attached patch implements TTY audit log data interpretation: it
turns
data=627F6361740D6964202D610D6C73202D6C202F626F090D10202D6C72740D0110011B661B640B202D6C7274156364202D1B7F6364207E6D69096C69096F090D6C730D126370201B3E63640D6C730D726D20627A496D09757F0D6364202D0D12637020051B7F626F09766D6C0937090D6364202F626F090D126D6B696E6974720D04
into
"b",backspace,"cat",ret,"id -a",ret,"ls -l /bo",tab,ret,^P,"
-lrt",ret,^A,^P,^A,esc,"f",esc,"d",^K," -lrt",^U,"cd
-",esc,backspace,"cd ~mi",tab,"li",tab,"o",tab,ret,"ls",ret,^R,"cp
",esc,">cd",ret,"ls",ret,"rm bzIm",tab,"u",backspace,ret,"cd
-",ret,^R,"cp
",^E,esc,backspace,"bo",tab,"vml",tab,"7",tab,ret,"cd /bo",tab,ret,^R,"mkinitr",ret,^D
(Usually, bash would be patched to emit an USER_TTY record for each
command line, and each USER_TTY record causes emitting a TTY record for
the collected data. This record was created without a patched bash, so
it contains all commands in the session.)
So far the patch supports only a few basic control sequences (arrow and
function keys with no modifiers). Before I add many more, I have a few
questions:
* Is it OK to hard-code the control sequences in the library?
Would it be preferable store them in a separate file instead,
letting end-users add or modify control sequences?
* How to share the code with src/ausearch-report.c? Copying the
code is ugly; reasonable options are
* move the data interpretation code to libaudit (either
only TTY audit interpretation, or all of it)
* link ausearch to libauparse
* Is there any reason to support conflicting terminal types (e.g.
something other than vt100-like terminals)? Are there conflicts
in the control sequences emitted by commonly used terminal
emulators?
Thank you,
Mirek
[-- Attachment #2: audit-1.7.7-interpret-tty.patch --]
[-- Type: text/x-patch, Size: 9031 bytes --]
Index: auparse/auparse-defs.h
===================================================================
--- auparse/auparse-defs.h (revision 108)
+++ auparse/auparse-defs.h (working copy)
@@ -77,7 +77,7 @@
AUPARSE_TYPE_SOCKADDR, AUPARSE_TYPE_FLAGS, AUPARSE_TYPE_PROMISC,
AUPARSE_TYPE_CAPABILITY, AUPARSE_TYPE_SUCCESS, AUPARSE_TYPE_A0,
AUPARSE_TYPE_A1, AUPARSE_TYPE_A2, AUPARSE_TYPE_SIGNAL,
- AUPARSE_TYPE_LIST } auparse_type_t;
+ AUPARSE_TYPE_LIST, AUPARSE_TYPE_TTY_DATA } auparse_type_t;
#ifdef __cplusplus
}
Index: auparse/interpret.c
===================================================================
--- auparse/interpret.c (revision 108)
+++ auparse/interpret.c (working copy)
@@ -79,7 +79,7 @@
* This function will take a pointer to a 2 byte Ascii character buffer and
* return the actual hex value.
*/
-static unsigned char x2c(unsigned char *buf)
+static unsigned char x2c(const unsigned char *buf)
{
static const char AsciiArray[17] = "0123456789ABCDEF";
char *ptr;
@@ -95,8 +95,18 @@
return total;
}
+static int is_hex_string(const char *str)
+{
+ while (*str) {
+ if (!isxdigit(*str))
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
/* returns a freshly malloc'ed and converted buffer */
-const char *au_unescape(char *buf)
+char *au_unescape(char *buf)
{
int len, i;
char saved, *str, *ptr = buf;
@@ -852,6 +862,134 @@
return out;
}
+struct string_buf {
+ char *buf; /* NULL if was ever out of memory */
+ size_t allocated;
+ size_t pos;
+};
+
+/* Append c to buf. */
+static void append_char(struct string_buf *buf, char c)
+{
+ if (buf->buf == NULL)
+ return;
+ if (buf->pos == buf->allocated) {
+ char *p;
+
+ buf->allocated *= 2;
+ p = realloc(buf->buf, buf->allocated);
+ if (p == NULL) {
+ free(buf->buf);
+ buf->buf = NULL;
+ return;
+ }
+ buf->buf = p;
+ }
+ buf->buf[buf->pos] = c;
+ buf->pos++;
+}
+
+/* Represent c as a character within a quoted string, and append it to buf. */
+static void tty_append_printable_char(struct string_buf *buf, unsigned char c)
+{
+ if (c < 0x20 || c > 0x7E) {
+ append_char(buf, '\\');
+ append_char(buf, '0' + ((c >> 6) & 07));
+ append_char(buf, '0' + ((c >> 3) & 07));
+ append_char(buf, '0' + (c & 07));
+ } else {
+ if (c == '\\' || c == '"')
+ append_char(buf, '\\');
+ append_char(buf, c);
+ }
+}
+
+/* Search for a name of a sequence of TTY bytes.
+ If found, return the name and advance *INPUT. Return NULL otherwise. */
+static const char *tty_find_named_key(unsigned char **input, size_t input_len)
+{
+ /* NUL-terminated list of (sequence, NUL, name, NUL) entries.
+ First match wins, even if a longer match were possible later */
+ static const unsigned char named_keys[] =
+#define E(SEQ, NAME) SEQ "\0" NAME "\0"
+#include "tty_named_keys.h"
+#undef E
+ "\0";
+
+ unsigned char *src;
+ const unsigned char *nk;
+
+ src = *input;
+ if (*src >= ' ' && *src != 0x7F)
+ return NULL; /* Fast path */
+ nk = named_keys;
+ do {
+ const unsigned char *p;
+ size_t nk_len;
+
+ p = strchr(nk, '\0');
+ nk_len = p - nk;
+ if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) {
+ *input += nk_len;
+ return p + 1;
+ }
+ nk = strchr(p + 1, '\0') + 1;
+ } while (*nk != '\0');
+ return NULL;
+}
+
+static const char *print_tty_data(const char *raw_data)
+{
+ struct string_buf buf;
+ int in_printable;
+ unsigned char *data, *data_pos, *data_end;
+
+ if (!is_hex_string(raw_data))
+ return strdup(raw_data);
+ data = au_unescape((char *)raw_data);
+ if (data == NULL)
+ return NULL;
+ data_end = data + strlen(raw_data) / 2;
+
+ buf.allocated = 10;
+ buf.buf = malloc(buf.allocated); /* NULL handled in append_char() */
+ buf.pos = 0;
+ in_printable = 0;
+ data_pos = data;
+ while (data_pos < data_end) {
+ /* FIXME: Unicode */
+ const char *desc;
+
+ desc = tty_find_named_key(&data_pos, data_end - data_pos);
+ if (desc != NULL) {
+ if (in_printable != 0) {
+ append_char(&buf, '"');
+ in_printable = 0;
+ }
+ if (buf.pos != 0)
+ append_char(&buf, ',');
+ while (*desc != '\0') {
+ append_char(&buf, *desc);
+ desc++;
+ }
+ } else {
+ if (in_printable == 0) {
+ if (buf.pos != 0)
+ append_char(&buf, ',');
+ append_char(&buf, '"');
+ in_printable = 1;
+ }
+ tty_append_printable_char(&buf, *data_pos);
+ data_pos++;
+ }
+ }
+ if (in_printable != 0)
+ append_char(&buf, '"');
+ append_char(&buf, '\0');
+ free(data);
+ return buf.buf;
+}
+
int lookup_type(const char *name)
{
int i;
@@ -861,16 +999,6 @@
return AUPARSE_TYPE_UNCLASSIFIED;
}
-static int is_hex_string(const char *str)
-{
- while (*str) {
- if (!isxdigit(*str))
- return 0;
- str++;
- }
- return 1;
-}
-
const char *interpret(const rnode *r)
{
const nvlist *nv = &r->nv;
@@ -885,6 +1013,8 @@
type = AUPARSE_TYPE_ESCAPED;
else if (r->type == AUDIT_AVC && strcmp(name, "saddr") == 0)
type = -1;
+ else if (r->type == AUDIT_USER_TTY && strcmp(name, "msg") == 0)
+ type = AUPARSE_TYPE_ESCAPED;
else if (strcmp(name, "acct") == 0) {
if (val[0] == '"')
type = AUPARSE_TYPE_ESCAPED;
@@ -949,7 +1079,10 @@
break;
case AUPARSE_TYPE_LIST:
out = print_list(val);
- break;
+ break;
+ case AUPARSE_TYPE_TTY_DATA:
+ out = print_tty_data(val);
+ break;
case AUPARSE_TYPE_UNCLASSIFIED:
default: {
char *out2;
Index: auparse/typetab.h
===================================================================
--- auparse/typetab.h (revision 108)
+++ auparse/typetab.h (working copy)
@@ -69,3 +69,4 @@
_S(AUPARSE_TYPE_A1, "a1" )
_S(AUPARSE_TYPE_A2, "a2" )
_S(AUPARSE_TYPE_SIGNAL, "sig" )
+_S(AUPARSE_TYPE_TTY_DATA, "data" )
Index: auparse/interpret.h
===================================================================
--- auparse/interpret.h (revision 108)
+++ auparse/interpret.h (working copy)
@@ -37,7 +37,7 @@
const char *interpret(const rnode *r);
void aulookup_destroy_uid_list(void);
void aulookup_destroy_gid_list(void);
-const char *au_unescape(char *buf);
+char *au_unescape(char *buf);
/* Make these hidden to prevent conflicts */
hidden_proto(lookup_type);
Index: auparse/tty_named_keys.h
===================================================================
--- auparse/tty_named_keys.h (revision 0)
+++ auparse/tty_named_keys.h (revision 0)
@@ -0,0 +1,71 @@
+/* tty_named_keys.h --
+ * Copyright 2008 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * Miloslav Trmač <mitr@redhat.com>
+ */
+
+E("\x01", "^A")
+E("\x02", "^B")
+E("\x03", "^C")
+E("\x04", "^D")
+E("\x05", "^E")
+E("\x06", "^F")
+E("\x07", "^G")
+E("\x08", "^H")
+E("\t", "tab")
+E("\n", "nl")
+E("\x0B", "^K")
+E("\x0C", "^L")
+E("\r", "ret")
+E("\x0E", "^N")
+E("\x0F", "^O")
+E("\x10", "^P")
+E("\x11", "^Q")
+E("\x12", "^R")
+E("\x13", "^S")
+E("\x14", "^T")
+E("\x15", "^U")
+E("\x16", "^V")
+E("\x17", "^W")
+E("\x18", "^X")
+E("\x19", "^Y")
+E("\x1A", "^Z")
+/* \x1B handled only after all other escape sequences */
+E("\x7F", "backspace")
+
+E("\x1B[A", "up")
+E("\x1B[B", "down")
+E("\x1B[C", "right")
+E("\x1B[D", "left")
+
+E("\x1B""OP", "F1")
+E("\x1B""OQ", "F2")
+E("\x1B""OR", "F3")
+E("\x1B""OS", "F4")
+E("\x1B[15~", "F5")
+E("\x1B[17~", "F6")
+E("\x1B[18~", "F7")
+E("\x1B[19~", "F8")
+E("\x1B[20~", "F9")
+E("\x1B[21~", "F10")
+E("\x1B[23~", "F11")
+E("\x1B[24~", "F12")
+
+E("\x1B", "esc")
+E("\x7F", "backspace")
Index: auparse/Makefile.am
===================================================================
--- auparse/Makefile.am (revision 108)
+++ auparse/Makefile.am (working copy)
@@ -32,7 +32,7 @@
auparse.c auditd-config.c message.c data_buf.c auparse-defs.h \
data_buf.h nvlist.h auparse.h ellist.h \
internal.h nvpair.h rnode.h interpret.h \
- private.h expression.c expression.h
+ private.h expression.c expression.h tty_named_keys.h
nodist_libauparse_la_SOURCES = $(BUILT_SOURCES)
libauparse_la_LIBADD = ${top_builddir}/lib/libaudit.la
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next reply other threads:[~2008-09-16 17:32 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-16 17:32 Miloslav Trmač [this message]
2008-09-19 20:55 ` [PATCH, RFC] Interpretation of TTY audit logs Steve Grubb
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1221586342.2814.33.camel@amilo \
--to=mitr@redhat.com \
--cc=linux-audit@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.