This file is indexed.

/usr/bin/mysqlauditgrep is in mysql-utilities 1.3.5-2.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#! /usr/bin/python
#
# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#

"""
This file contains the audit log file search utility which allows user to
retrieve log entries according to the specified search criteria (i.e.,
from specific users, search patterns, date ranges, or query types).
"""

from mysql.utilities.common.tools import check_python_version

# Check Python version compatibility
check_python_version()

import os.path
import sys

from datetime import datetime

from mysql.utilities.common import pattern_matching

from mysql.utilities.exception import UtilError
from mysql.utilities.common.options import add_verbosity
from mysql.utilities.common.options import add_regexp
from mysql.utilities.common.options import add_format_option_with_extras
from mysql.utilities.common.options import CaseInsensitiveChoicesOption
from mysql.utilities.common.options import UtilitiesParser
from mysql.utilities.common.tools import check_connector_python
from mysql.utilities.command import audit_log
from mysql.utilities.command.audit_log import AuditLog
from mysql.utilities import VERSION_FRM


class MyParser(UtilitiesParser):
    def format_epilog(self, formatter):
        return self.epilog

# Constants
NAME = "MySQL Utilities - mysqlauditgrep "
DESCRIPTION = "mysqlauditgrep - audit log search utility "
USAGE = "%prog [options] AUDIT_LOG_FILE "

# Check for connector/python
if not check_connector_python():
    sys.exit(1)

# Setup the command parser
parser = MyParser(
    version=VERSION_FRM.format(program=os.path.basename(sys.argv[0])),
    description=DESCRIPTION,
    usage=USAGE,
    add_help_option=False,
    option_class=CaseInsensitiveChoicesOption,
    epilog="")

# Default option to provide help information
parser.add_option("--help", action="help", help="display this help message "
                  "and exit")

# Setup utility-specific options:

# Output format, default is initially set to None to determine the correct
# behavior when no search criteria is specified.
add_format_option_with_extras(parser, "display the output in either GRID "
                              "(default), TAB, CSV, VERTICAL and RAW format",
                              None, ['raw'])

# Search criteria to find entries for specified users
parser.add_option("--users", "-u", action="store", dest="users",
                  type="string", default=None,
                  help="find log entries by user name. Accepts a comma-"
                  "separated list of user names, for example: joe,sally,nick")

# Show audit log file statistics
parser.add_option("--file-stats", action="store_true", default=False,
                  dest="stats", help="display the audit log statistics.")

# Search criteria to retrieve entries starting from a specific date/time
parser.add_option("--start-date", action="store", dest="start_date",
                  type="string", default=None,
                  help="retrieve log entries starting from the specified "
                  "date/time. If not specified or the value is 0, all entries "
                  "from the start of the log are displayed. Accepted formats: "
                  "yyyy-mm-ddThh:mm:ss or yyyy-mm-dd.")

# Search criteria to retrieve entries until the specific date/time
parser.add_option("--end-date", action="store", dest="end_date",
                  type="string", default=None,
                  help="retrieve log entries until the specified date/time."
                  "If not specified or the value is 0, all entries to the "
                  "end of the log are displayed. Accepted formats: "
                  "yyyy-mm-ddThh:mm:ss or yyyy-mm-dd.")

# Search pattern to retrieve matching entries
parser.add_option("-e", "--pattern", action="store", dest="pattern",
                  type="string", default=None,
                  help="search pattern to retrieve matching entries.")

# Search criteria to retrieve entries from the given SQL stmt/cmd types
parser.add_option("--query-type", action="store", dest="query_type",
                  type="string", default=None,
                  help="search for all SQL statements/commands from the given "
                  "list of commands. Accepts a comma-separated list of "
                  "commands. Supported values: "
                  + ", ".join(audit_log.QUERY_TYPES))

# Search criteria to retrieve entries from the given SQL stmt/cmd types
parser.add_option("--event-type", action="store", dest="event_type",
                  type="string", default=None,
                  help="search for all recorded event types from the given "
                  "list of supported log events. Accepts a comma-separated "
                  "list of event types. Supported values: "
                  + ", ".join(audit_log.EVENT_TYPES))

# Search criteria to retrieve entries with the specified status.
parser.add_option("--status", action="store", dest="status",
                  type="string", default=None,
                  help="search for all entries with the specified status "
                       "values. Accepts a comma-separated list of "
                       "non-negative integers (corresponding to MySQL error "
                       "codes) or intervals marked with a dash. "
                       "For example: 1051,1068-1075,1109,1146.")

# Add regexp option
add_regexp(parser)

# Add verbosity mode
add_verbosity(parser, False)


def exist_search_criteria():
    # Return true if at least one search criteria is specified
    return (opt.users or opt.start_date or opt.end_date or opt.pattern
            or opt.query_type or opt.event_type or opt.status)


# Parse the command line arguments.
opt, args = parser.parse_args()

# Perform error checking

# Only one positional argument is allowed: the audit log file
num_args = len(args)
if num_args < 1:
    parser.error("You must specify the audit log file to be processed.")
elif num_args > 1:
    parser.error("You can only process one audit log file at a time.")

# Check if the specified argument is a file
if not os.path.isfile(args[0]):
    parser.error("The specified argument is not a file: %s" % args[0])

# Check date/time ranges
start_date = None
if opt.start_date and opt.start_date != "0":
    date, sep, time = opt.start_date.partition("T")
    if time:
        try:
            sdate = datetime.strptime(opt.start_date, "%Y-%m-%dT%H:%M:%S")
        except ValueError:
            parser.error("Invalid start date/time format "
                         + "(yyyy-mm-ddThh:mm:ss): " + opt.start_date)
    else:
        try:
            sdate = datetime.strptime(opt.start_date, "%Y-%m-%d")
        except ValueError:
            parser.error("Invalid start date format (yyyy-mm-dd): "
                         + opt.start_date)
    start_date = sdate.strftime("%Y-%m-%dT%H:%M:%S")

end_date = None
if opt.end_date and opt.end_date != "0":
    date, sep, time = opt.end_date.partition("T")
    if time:
        try:
            edate = datetime.strptime(opt.end_date, "%Y-%m-%dT%H:%M:%S")
        except ValueError:
            parser.error("Invalid end date/time format "
                         + "(yyyy-mm-ddThh:mm:ss): " + opt.end_date)
    else:
        try:
            edate = datetime.strptime(opt.end_date, "%Y-%m-%d")
        except ValueError:
            parser.error("Invalid start date format (yyyy-mm-dd): "
                         + opt.end_date)
    end_date = edate.strftime("%Y-%m-%dT%H:%M:%S")

# Check if the value specified for the --users option is valid
users = None
if opt.users:
    users = opt.users.split(",")
    users = filter(None, users)
    if not len(users) > 0:
        parser.error("The value for the option --users is not valid: '"
                     + opt.users + "'")

# Check if the value specified for the --query-type option is valid
query_types = None
if opt.query_type:
    query_types = opt.query_type.split(",")
    # filter empty values and convert all to lower cases
    query_types = filter(None, query_types)
    query_types = map((lambda x: x.lower()), query_types)
    if not len(query_types) > 0:
        parser.error("The value for the option --query-type is not valid: '"
                     + opt.query_type + "'")
    else:
        valid_qts = map((lambda x: x.lower()), audit_log.QUERY_TYPES)
        for qt in query_types:
            if qt not in valid_qts:
                parser.error("The specified QUERY_TYPE value is not valid: '"
                     + qt + "'\nSupported values: " + ",".join(valid_qts))

# Check if the value specified for the --event-type option is valid
event_types = None
if opt.event_type:
    # filter empty values and convert all to lower cases
    event_types = opt.event_type.split(",")
    event_types = filter(None, event_types)
    event_types = map((lambda x: x.lower()), event_types)
    if not len(event_types) > 0:
        parser.error("The value for the option --event-type is not valid: '"
                     + opt.event_type + "'")
    else:
        valid_ets = map((lambda x: x.lower()), audit_log.EVENT_TYPES)
        for et in event_types:
            if et not in valid_ets:
                parser.error("The specified EVENT_TYPE value is not valid: '"
                     + et + "'\nSupported values: " + ",".join(valid_ets))

# Check specified pattern
if opt.use_regexp and not opt.pattern:
    parser.error("The --pattern option is required if REGEXP option is set.")

pattern = opt.pattern
if opt.pattern and not opt.use_regexp:
    # Convert SQL LIKE pattern to Python REGEXP
    pattern = pattern_matching.convertSQL_LIKE2REGEXP(opt.pattern)

# Check if the values specified for the --status option are valid
status_list = []
if opt.status:
    # filter empty values and convert all to integers cases
    status_values = opt.status.split(",")
    status_values = filter(None, status_values)
    if not len(status_values) > 0:
        parser.error("The value for the option --status is not valid: "
                     "'{0}'.".format(opt.status))
    for value in status_values:
        interval = value.split('-')
        if len(interval) == 2:
            try:
                lv = int(interval[0])
            except ValueError:
                parser.error("Invalid status value '{0}' (must be a "
                             "non-negative integer) for interval "
                             "'{1}'.".format(interval[0], value))
            try:
                hv = int(interval[1])
            except ValueError:
                parser.error("Invalid status value '{0}' (must be a "
                             "non-negative integer) for interval "
                             "'{1}'.".format(interval[1], value))
            # Add interval (tuple) to the status list.
            status_list.append((lv, hv))
        elif len(interval) == 1:
            # Add single value to the status list.
            try:
                status_list.append(int(value))
            except ValueError:
                parser.error("Invalid status value '{0}' (must be a "
                             "non-negative integer).".format(value))
        else:
            # Invalid format.
            parser.error("Invalid format for status interval (a single "
                         "dash must be used): '{0}'.".format(value))

# Create dictionary of options
options = {
    'log_name': args[0],
    'verbosity': opt.verbosity,
    'format': opt.format,
    'users': users,
    'start_date': start_date,
    'end_date': end_date,
    'pattern': pattern,
    'use_regexp': opt.use_regexp,
    'query_type': query_types,
    'event_type': event_types,
    'status': status_list,
}

try:
    if not exist_search_criteria() and not (opt.format or opt.stats):
        print("#\n# No search criteria defined.\n#")
    else:
        # Create and init the AuditLog obj with the provided options
        log = AuditLog(options)

        # Open the audit log file
        log.open_log()

        # Parse the audit log file and apply filters
        log.parse_log()

        # Close the audit log
        log.close_log()

        if opt.stats:
            # Show audit log stats
            log.show_statistics()
        else:
            # Print the resulting data (to the sdtout) in the specified format
            log.output_formatted_log()

except UtilError:
    _, e, _ = sys.exc_info()
    print("ERROR: %s" % e.errmsg)
    sys.exit(1)

sys.exit(0)