Esempio n. 1
0
    def event_history(self, columns, *, sieve=None, repres=None, quiet=None):
        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        self._events_to_show = _filter_events(self._all_events, sieve)
        if not self._events_to_show:
            print_info('No USB events found!')
            return

        if not quiet:
            try:
                number, filename = _output_choice('event history',
                                                  'history.json', 'history/')
            except USBRipError as e:
                print_critical(str(e), initial_error=e.errors['initial_error'])
                return

            if number == '1':
                _json_dump(self._events_to_show, 'event history', filename)
                return

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-History-Events', repres)
Esempio n. 2
0
def _read_log_file(filename):
    filtered = DefaultOrderedDict(list)

    if filename.endswith('.gz'):
        print_info('Unpacking \'{}\''.format(filename))
        try:
            log = gzip.open(filename, 'rb')
        except PermissionError as e:
            print_warning('Permission denied: \'{}\''.format(filename),
                          initial_error=str(e))
            return filtered
        else:
            sentinel = b''
            filename = filename[:-3]
    else:
        log = open(filename, 'r')
        sentinel = ''

    print_info('Reading \'{}\''.format(filename))
    regex = re.compile(r'usb')
    for line in iter(log.readline, sentinel):
        if isinstance(line, bytes):
            line = line.decode(encoding='utf-8')
        if regex.search(line):
            filtered[line[:15]].append(line)  # line[:15] == 'Mon dd hh:mm:ss'

    log.close()
    return filtered
Esempio n. 3
0
def _filter_events(all_events, sieve=None):
    if not sieve:
        sieve = {'external': False, 'dates': [], 'number': -1}
    else:
        print_info('Filtering events')

    if sieve['external']:
        events_to_show = [
            event for event in all_events if event['disconn'] is not None
        ]
    else:
        events_to_show = all_events

    if sieve['dates']:
        events_to_show = [
            event for date in sieve['dates'] for event in events_to_show
            if event['conn'][:6] == date
        ]

    if not len(events_to_show):
        return None

    SIZE = len(events_to_show)
    if sieve['number'] == -1 or sieve['number'] >= SIZE:
        if sieve['number'] > SIZE:
            print_warning('USB action history has only {} entries instead of requested {}, ' \
                                   'displaying all of them...'.format(SIZE, sieve['number']))
        sieve['number'] = SIZE

    return [events_to_show[SIZE - i] for i in range(sieve['number'], 0, -1)]
Esempio n. 4
0
    def generate_auth_json(self, output_auth):
        try:
            os_makedirs(os.path.dirname(output_auth))
        except USBRipError as e:
            print_critical(str(e), initial_error=e.errors['initial_error'])
            return

        try:
            auth_json = open(output_auth, 'w')
        except PermissionError as e:
            print_critical('Permission denied: \'{}\''.format(output_auth),
                           initial_error=str(e))
            return

        print_info('Generating authorized device list (JSON)')

        auth = defaultdict(list)
        for event in self._all_events:
            for key, val in event.items():
                if key in ('vid', 'pid', 'prod', 'manufact', 'serial') and \
                               val is not None                                     and \
                               val not in auth[key]:
                    auth[key].append(val)

        for key in auth.keys():
            auth[key].sort()

        json.dump(auth, auth_json, sort_keys=True, indent=4)
        auth_json.close()

        print_info('New authorized device list: \'{}\''.format(output_auth))
Esempio n. 5
0
def _get_raw_history():
    raw_history = DefaultOrderedDict(list)

    print_info(
        'Searching for log files: \'/var/log/syslog*\' or \'/var/log/messages*\''
    )

    syslog_files = sorted([
        filename for filename in list_files('/var/log/')
        if filename.rsplit('/', 1)[1].startswith('syslog')
    ])

    if len(syslog_files) > 0:
        for syslog in syslog_files:
            raw_history.update(_read_log_file(syslog))
    else:
        messages_files = sorted([
            filename for filename in list_files('/var/log/')
            if filename.rsplit('/', 1)[1].startswith('messages')
        ])

        if len(messages_files) > 0:
            for messages in messages_files:
                raw_history.update(_read_log_file(messages))
        else:
            raise USBRipError('None of log file types was found!')

    return raw_history
Esempio n. 6
0
def _output_choice(list_name, default_filename, dirname):
    while True:
        print('[?] How would you like your {} list to be generated?\n'.format(
            list_name))

        print('    1. JSON-file')
        print('    2. Terminal stdout')

        number = input('\n[>] Please enter the number of your choice: ')

        if number == '1':
            while True:
                filename = input('[>] Please enter the base name for the output file ' \
                                             '(default is \'{}\'): '.format(default_filename))

                if all(c in printable
                       for c in filename) and len(filename) < 256:
                    if not filename:
                        filename = default_filename
                    elif filename[-5:] != '.json':
                        filename = filename + '.json'

                    filename = root_dir_join(dirname + filename)

                    try:
                        dirname = os.path.dirname(filename)
                        os_makedirs(dirname)
                    except USBRipError as e:
                        print_critical(str(e),
                                       initial_error=e.errors['initial_error'])
                        return (None, '')
                    else:
                        print_info('Created \'{}\''.format(dirname))

                    overwrite = True
                    if os.path.exists(filename):
                        while True:
                            overwrite = input(
                                '[?] File exists. Would you like to overwrite it? [Y/n]: '
                            )
                            if len(overwrite) == 1 and overwrite in 'Yy':
                                overwrite = True
                                break
                            elif len(overwrite) == 1 and overwrite in 'Nn':
                                overwrite = False
                                break

                    if overwrite:
                        return (int(number), filename)

        elif number == '2':
            return (int(number), '')
Esempio n. 7
0
    def search_violations(self,
                          input_auth,
                          columns,
                          *,
                          sieve=None,
                          repres=None):
        try:
            auth = _process_auth_json(input_auth)
        except json.decoder.JSONDecodeError as e:
            print_critical('Failed to decode authorized device list (JSON)',
                           initial_error=str(e))
            return

        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        print_info('Searching for violations', quiet=USBEvents.QUIET)

        for event in self._all_events:
            try:
                if any(event[key] not in vals and event[key] is not None
                       for key, vals in auth.items()):
                    self._violations.append(event)
            except KeyError as e:
                print_critical(
                    'Invalid structure of authorized device list (JSON)',
                    initial_error=str(e))
                return

        self._events_to_show = _filter_events(self._violations, sieve)
        if not self._events_to_show:
            print_info('No USB violation events found!', quiet=USBEvents.QUIET)
            json.dump([], auth_json)
            auth_json.close()
            return

        if not USBEvents.QUIET and ISATTY:
            number, filename = _output_choice('violation', 'viol.json',
                                              'violations/')
            if number is None:
                return
            elif number == 1:
                _json_dump(self._events_to_show, 'violation', filename)
                return

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-Violation-Events', repres)
Esempio n. 8
0
    def search_violations(self,
                          input_auth,
                          *,
                          sieve=None,
                          repres=None,
                          quiet=None):
        try:
            auth = _process_auth_json(input_auth)
        except json.decoder.JSONDecodeError as e:
            print_critical('Failed to decode authorized device list (JSON)',
                           initial_error=str(e))
            return

        print_info('Searching for violations')

        for event in self._all_events:
            try:
                if any(event[key] not in vals and event[key] is not None
                       for key, vals in auth.items()):
                    self._violations.append(event)
            except KeyError as e:
                print_critical(
                    'Invalid structure of authorized device list (JSON)',
                    initial_error=str(e))
                return

        columns = [key for key in COLUMN_NAMES.keys()]
        table_data = [[val for val in COLUMN_NAMES.values()]]

        self._events_to_show = _filter_events(self._violations, sieve)
        if not self._events_to_show:
            print_info('No USB violation events found!')
            return

        if not quiet:
            try:
                number, filename = _output_choice('violation', 'viol.json',
                                                  'violations/')
            except USBRipError as e:
                print_critical(str(e), initial_error=e.errors['initial_error'])
                return

            if number == '1':
                _json_dump(self._events_to_show, 'violation', filename)
                return

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-Violation-Events', repres)
Esempio n. 9
0
def _download_database(filename):
    try:
        os_makedirs(os.path.dirname(filename))
    except USBRipError as e:
        print_critical(str(e), initial_error=e.errors['initial_error'])
        return

    try:
        usb_ids = open(filename, 'w+')
    except PermissionError as e:
        print_critical('Permission denied: \'{}\''.format(filename),
                       initial_error=str(e))
        return

    db, latest_ver, latest_date, error, e = _get_latest_version()

    if error:
        usb_ids.close()
        os.remove(filename)
        if error == USBIDs._INTERNET_CONNECTION_ERROR:
            raise USBRipError('No internet connection')
        elif error == USBIDs._SERVER_TIMEOUT_ERROR:
            raise USBRipError('Server timeout',
                              errors={
                                  'errcode': error,
                                  'initial_error': e
                              })
        elif error == USBIDs._SERVER_CONTENT_ERROR:
            raise USBRipError('Server content error: no version or date found',
                              errors={
                                  'errcode': error,
                                  'initial_error': e
                              })

    usb_ids.write(db)
    usb_ids.seek(0)

    print_info('Database downloaded')

    print('Version:  {}'.format(latest_ver))
    print('Date:     {}'.format(latest_date))

    return usb_ids
Esempio n. 10
0
def _json_dump(events_to_show, list_name, filename):
    print_info('Generating {} list (JSON)'.format(list_name))

    out = OrderedDict()
    for event in events_to_show:
        out[event['conn']] = OrderedDict()
        for key, val in sorted(event.items()):
            if key != 'conn':
                out[event['conn']][key] = val

    try:
        with open(filename, 'w') as out_json:
            json.dump(out, out_json, indent=4)
    except PermissionError as e:
        print_critical('Permission denied: \'{}\''.format(filename),
                       initial_error=str(e))
        return

    print_info('New {} list: \'{}\''.format(list_name, filename))
Esempio n. 11
0
def _get_latest_version():
	connected, error, e = _check_connection('www.google.com')
	if not connected:
		return (None, -1, -1, error, e)

	print_info('Getting latest version and date', quiet=USBIDs.QUIET)

	try:
		resp = requests.get('http://www.linux-usb.org/usb.ids', timeout=10)
	except requests.exceptions.Timeout as e:
		return (None, -1, -1, USBIDs._SERVER_TIMEOUT_ERROR, str(e))

	soup = BeautifulSoup(resp.text, 'html.parser')
	db = soup.text
	
	try:
		latest_ver  = re.search(r'^# Version:\s*(.*?$)', db, re.MULTILINE).group(1)
		latest_date = re.search(r'^# Date:\s*(.*?$)', db, re.MULTILINE).group(1)
	except AttributeError as e:
		return (None, -1, -1, USBIDs._SERVER_CONTENT_ERROR, str(e))

	return (db, latest_ver, latest_date, 0, '')
Esempio n. 12
0
    def event_history(self, columns, *, sieve=None, repres=None):
        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        self._events_to_show = _filter_events(self._all_events, sieve)
        if not self._events_to_show:
            print_info('No USB events found!', quiet=USBEvents.QUIET)
            return

        if not USBEvents.QUIET and ISATTY:
            number, filename = _output_choice('event history', 'history.json',
                                              'history/')
            if number is None:
                return
            elif number == 1:
                _json_dump(self._events_to_show, 'event history', filename)
                return

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-History-Events', repres)
Esempio n. 13
0
    def generate_auth_json(self, output_auth, *, sieve=None):
        try:
            dirname = os.path.dirname(filename)
            os_makedirs(dirname)
        except USBRipError as e:
            print_critical(str(e), initial_error=e.errors['initial_error'])
            return
        else:
            print_info('Created \'{}\''.format(dirname))

        try:
            auth_json = open(output_auth, 'w')
        except PermissionError as e:
            print_critical('Permission denied: \'{}\''.format(output_auth),
                           initial_error=str(e))
            return

        self._events_to_show = _filter_events(self._all_events, sieve)
        if not self._events_to_show:
            print_info('No USB violation events found!', quiet=USBEvents.QUIET)
            json.dump([], auth_json)
            auth_json.close()
            return

        print_info('Generating authorized device list (JSON)',
                   quiet=USBEvents.QUIET)

        auth = defaultdict(list)
        for event in self._events_to_show:
            for key, val in event.items():
                if key in ('vid', 'pid', 'prod', 'manufact', 'serial') and \
                               val is not None                                     and \
                               val not in auth[key]:
                    auth[key].append(val)

        for key in auth.keys():
            auth[key].sort()

        json.dump(auth, auth_json, sort_keys=True, indent=4)
        auth_json.close()

        print_info('New authorized device list: \'{}\''.format(output_auth),
                   quiet=USBEvents.QUIET)
Esempio n. 14
0
def _update_database(filename):
    try:
        usb_ids = open(filename, 'r+')
    except PermissionError as e:
        print_critical('Permission denied: \'{}\''.format(filename),
                       initial_error=str(e))
        return

    curr_ver, curr_date = _get_current_version(usb_ids)

    print_info('Getting current database version')
    print('Version:  {}'.format(curr_ver))
    print('Date:     {}'.format(curr_date))

    print_info('Checking local database for update')
    db, latest_ver, latest_date, error, e = _get_latest_version()

    if error:
        if error == USBIDs._INTERNET_CONNECTION_ERROR:
            print_warning('No internet connection, using current version',
                          errcode=error)
        elif error == USBIDs._SERVER_TIMEOUT_ERROR:
            print_warning('Server timeout, using current version',
                          errcode=error,
                          initial_error=e)
        elif error == USBIDs._SERVER_CONTENT_ERROR:
            print_warning('Server error, using current version',
                          errcode=error,
                          initial_error=e)
        return usb_ids

    if curr_ver != latest_ver and curr_date != latest_date:  # if there's newer database version
        print('Updating database... ', end='')

        usb_ids.write(db)
        usb_ids.seek(0)
        usb_ids.truncate()

        print('Done\n')

        print('Version:  {}'.format(latest_ver))
        print('Date:     {}'.format(latest_date))

    print_info('Local database is up-to-date')

    return usb_ids
Esempio n. 15
0
def _represent_events(events_to_show, columns, table_data, title, repres=None):
    print_info('Preparing gathered events')

    if not repres:
        repres = {'table': False, 'list': False, 'smart': True}

    max_len = {
        'conn':
        15,
        'user':
        max(max(len(event['user']) for event in events_to_show), len('User')),
        'vid':
        4,
        'pid':
        4,
        'prod':
        max(max(len(str(event['prod'])) for event in events_to_show),
            len('Product')),
        'manufact':
        max(max(len(str(event['manufact'])) for event in events_to_show),
            len('Manufacturer')),
        'serial':
        max(max(len(str(event['serial'])) for event in events_to_show),
            len('Serial Number')),
        'port':
        max(max(len(event['port']) for event in events_to_show), len('Port')),
        'disconn':
        15
    }

    for event in events_to_show:
        if 'conn' in columns:
            try:
                prev_cday
            except NameError:
                prev_cday = ''
            curr_cday = event['conn'][:6]
            if prev_cday != curr_cday:
                cday = ['{} {}'.format(curr_cday, BULLET * 8)
                        ]  # 8 == len(event['conn'] - event['conn'][:6] - 1)
                table_data.append(cday + [
                    SEPARATOR * max_len[name]
                    for name in columns if name != 'conn'
                ])
            prev_cday = curr_cday

        row = []
        for name in columns:
            if event[name] is None:
                event[name] = ABSENCE

            item = event[name]
            if name == 'conn' and IS_COLORED:
                item = colored(item, 'green')
            elif name == 'disconn' and IS_COLORED:
                item = colored(item, 'red')

            row.append(item)

        table_data.append(row)

    if IS_COLORED:
        event_table = _build_single_table(
            USBEvents.TableClass, table_data,
            colored(title, 'white', attrs=['bold']))
    else:
        event_table = _build_single_table(USBEvents.TableClass, table_data,
                                          title)

    # Display as table
    if repres['smart'] and event_table.ok or repres['table']:
        print_info('Representation: Table')
        print('\n' + event_table.table)

    # Display as list
    elif repres['smart'] and not event_table.ok or repres['list']:
        if not event_table.ok:
            print_warning(
                'Terminal window is too small to display table properly')
            print_warning('Representation: List')

        max_len = max(len(str(val)) for event in events_to_show for val in event.values()) + \
                        len('Serial Number:  ')  # max length string
        if not max_len // 2: max_len += 1
        date_sep_len = (max_len - 8) // 2

        cprint('\n' + title, 'white', attrs=['bold'])

        prev_cday = ''
        for event in events_to_show:
            curr_cday = event['conn'][:6]
            if prev_cday != curr_cday:
                print(SEPARATOR * max_len)
                print('{} {} {}'.format(BULLET * date_sep_len, curr_cday,
                                        BULLET * date_sep_len))
                print(SEPARATOR * max_len)
            else:
                print(SEPARATOR * max_len)
            prev_cday = curr_cday

            if IS_COLORED:
                print(
                    colored('Connected:      ', 'magenta', attrs=['bold']) +
                    colored(event['conn'], 'green'))
                print(
                    colored('User:           '******'magenta', attrs=['bold']) +
                    event['user'])
                print(
                    colored('VID:            ', 'magenta', attrs=['bold']) +
                    event['vid'])
                print(
                    colored('PID:            ', 'magenta', attrs=['bold']) +
                    event['pid'])
                print(
                    colored('Product:        ', 'magenta', attrs=['bold']) +
                    str(event['prod']))
                print(
                    colored('Manufacturer:   ', 'magenta', attrs=['bold']) +
                    str(event['manufact']))
                print(
                    colored('Serial Number:  ', 'magenta', attrs=['bold']) +
                    str(event['serial']))
                print(
                    colored('Bus-Port:       ', 'magenta', attrs=['bold']) +
                    event['port'])
                print(
                    colored('Disconnected:   ', 'magenta', attrs=['bold']) +
                    colored(event['disconn'], 'red'))
            else:
                print('Connected:      ' + event['conn'])
                print('User:           '******'user'])
                print('VID:            ' + event['vid'])
                print('PID:            ' + event['pid'])
                print('Product:        ' + str(event['prod']))
                print('Manufacturer:   ' + str(event['manufact']))
                print('Serial Number:  ' + str(event['serial']))
                print('Bus-Port:       ' + event['port'])
                print('Disconnected:   ' + event['disconn'])
        print(SEPARATOR * max_len)