From mboxrd@z Thu Jan 1 00:00:00 1970 From: Miloslav =?UTF-8?Q?Trma=C4=8D?= Subject: [PATCH, RFC] Interpretation of TTY audit logs Date: Tue, 16 Sep 2008 17:32:22 +0000 Message-ID: <1221586342.2814.33.camel@amilo> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-jHFVgxqk0JysuYwM3EPo" Return-path: Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id m8GHWPik030630 for ; Tue, 16 Sep 2008 13:32:25 -0400 Received: from [10.34.0.128] (dhcp-0-128.brq.redhat.com [10.34.0.128]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id m8GHWOdv025702 for ; Tue, 16 Sep 2008 13:32:24 -0400 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-audit-bounces@redhat.com Errors-To: linux-audit-bounces@redhat.com To: linux-audit List-Id: linux-audit@redhat.com --=-jHFVgxqk0JysuYwM3EPo Content-Type: text/plain Content-Transfer-Encoding: 7bit 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 --=-jHFVgxqk0JysuYwM3EPo Content-Disposition: attachment; filename=audit-1.7.7-interpret-tty.patch Content-Type: text/x-patch; name=audit-1.7.7-interpret-tty.patch; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Index: auparse/auparse-defs.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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,=20 - AUPARSE_TYPE_LIST } auparse_type_t; + AUPARSE_TYPE_LIST, AUPARSE_TYPE_TTY_DATA } auparse_type_t; =20 #ifdef __cplusplus } Index: auparse/interpret.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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] =3D "0123456789ABCDEF"; char *ptr; @@ -95,8 +95,18 @@ return total; } =20 +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 =3D buf; @@ -852,6 +862,134 @@ return out; } =20 +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 =3D=3D NULL) + return; + if (buf->pos =3D=3D buf->allocated) { + char *p; + + buf->allocated *=3D 2; + p =3D realloc(buf->buf, buf->allocated); + if (p =3D=3D NULL) { + free(buf->buf); + buf->buf =3D NULL; + return; + } + buf->buf =3D p; + } + buf->buf[buf->pos] =3D c; + buf->pos++; +} + +/* Represent c as a character within a quoted string, and append it to b= uf. */ +static void tty_append_printable_char(struct string_buf *buf, unsigned c= har 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 =3D=3D '\\' || c =3D=3D '"') + 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 inpu= t_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[] =3D +#define E(SEQ, NAME) SEQ "\0" NAME "\0" +#include "tty_named_keys.h" +#undef E + "\0"; + + unsigned char *src; + const unsigned char *nk; + + src =3D *input; + if (*src >=3D ' ' && *src !=3D 0x7F) + return NULL; /* Fast path */ + nk =3D named_keys; + do { + const unsigned char *p; + size_t nk_len; + + p =3D strchr(nk, '\0'); + nk_len =3D p - nk; + if (nk_len <=3D input_len && memcmp(src, nk, nk_len) =3D=3D 0) { + *input +=3D nk_len; + return p + 1; + } + nk =3D strchr(p + 1, '\0') + 1; + } while (*nk !=3D '\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 =3D au_unescape((char *)raw_data); + if (data =3D=3D NULL) + return NULL; + data_end =3D data + strlen(raw_data) / 2; + + buf.allocated =3D 10; + buf.buf =3D malloc(buf.allocated); /* NULL handled in append_char() */ + buf.pos =3D 0; + in_printable =3D 0; + data_pos =3D data; + while (data_pos < data_end) { + /* FIXME: Unicode */ + const char *desc; + + desc =3D tty_find_named_key(&data_pos, data_end - data_pos); + if (desc !=3D NULL) { + if (in_printable !=3D 0) { + append_char(&buf, '"'); + in_printable =3D 0; + } + if (buf.pos !=3D 0) + append_char(&buf, ','); + while (*desc !=3D '\0') { + append_char(&buf, *desc); + desc++; + } + } else { + if (in_printable =3D=3D 0) { + if (buf.pos !=3D 0) + append_char(&buf, ','); + append_char(&buf, '"'); + in_printable =3D 1; + } + tty_append_printable_char(&buf, *data_pos); + data_pos++; + } + } + if (in_printable !=3D 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; } =20 -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 =3D &r->nv; @@ -885,6 +1013,8 @@ type =3D AUPARSE_TYPE_ESCAPED; else if (r->type =3D=3D AUDIT_AVC && strcmp(name, "saddr") =3D=3D 0) type =3D -1; + else if (r->type =3D=3D AUDIT_USER_TTY && strcmp(name, "msg") =3D=3D 0) + type =3D AUPARSE_TYPE_ESCAPED; else if (strcmp(name, "acct") =3D=3D 0) { if (val[0] =3D=3D '"') type =3D AUPARSE_TYPE_ESCAPED; @@ -949,7 +1079,10 @@ break;=20 case AUPARSE_TYPE_LIST: out =3D print_list(val); - break;=20 + break; + case AUPARSE_TYPE_TTY_DATA: + out =3D print_tty_data(val); + break; case AUPARSE_TYPE_UNCLASSIFIED: default: { char *out2; Index: auparse/typetab.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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); =20 /* Make these hidden to prevent conflicts */ hidden_proto(lookup_type); Index: auparse/tty_named_keys.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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=C4=8D + */ + +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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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 =3D $(BUILT_SOURCES) =20 libauparse_la_LIBADD =3D ${top_builddir}/lib/libaudit.la --=-jHFVgxqk0JysuYwM3EPo Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --=-jHFVgxqk0JysuYwM3EPo--