def output_format(file, windows=False, archive=None): if file[T_TYPE] == 'X': return '--- TRUNCATED ---' name = to_utf8(file[T_NAME]) if archive: name += u' \u25bb ' + archive if windows: out = u' {}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) else: out = u' {}{}{}{}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<5}'.format(file[T_UID]), u'{:<5}'.format(file[T_GID]), u' {:06o} '.format(file[T_MODE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) if archive: out=Color(out, 'yellow') elif file[T_TYPE] == 'D': out=Color(out, 'lightyellow') elif 'U' in file[T_SPEC]: out=Color(out, 'lightred') elif 'G' in file[T_SPEC]: out=Color(out, 'red') elif file[T_TYPE] == 'B': out=Color(out, 'grey') elif file[T_TYPE] == 'C': out=Color(out, 'grey') elif file[T_TYPE] == 'F': out=Color(out, 'cyan') elif file[T_TYPE] == 'S': out=Color(out, 'magenta') elif file[T_TYPE] == 'L': out=Color(out, 'grey') elif not file[T_SIZE]: out=Color(out, 'darkgrey') elif 'E' in file[T_SPEC]: out=Color(out, 'lightgreen') elif 'W' in file[T_SPEC] and not windows: out=Color(out, 'blue') return out
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils.basic_cmds', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams', 'pupwinutils.security'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument( '-v', '--verbose', action='store_true', default=False, help='Print more information (certificates for example)') cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) oneliners = [] certificates = None for extra, values in extra.iteritems(): if extra == 'Certificates': certificates = [ load_cert_string(cert, FORMAT_DER).as_text() for cert in values ] elif isinstance(values, dict): records = [{ 'KEY': k.decode('utf-8'), 'VALUE': v.decode('utf-8') if isinstance(v, str) else str(v) } for k, v in values.iteritems()] infos.append(Table(records, ['KEY', 'VALUE'], caption=extra)) elif isinstance(values, (list, tuple)): if all( isinstance(value, (list, tuple)) and len(value) == 2 for value in values): infos.append( List('{}: {}'.format(key, value) for key, value in values)) else: infos.append(List(values, caption=extra)) elif isinstance(values, int): oneliners.append('{}: {}'.format(extra, values)) elif '\n' in values: infos.append(Line(extra + ':', values)) else: oneliners.append(extra + ': ' + values) if args.verbose: magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) if magic: oneliners.append('Magic: {}'.format(magic)) if certificates: infos.extend(certificates) if oneliners: infos.append(List(oneliners, caption='Other')) self.log(MultiPart(infos))
def output_format(file, windows=False, archive=None, time=False, uid_len=0, gid_len=0): if file[T_TYPE] == 'X': return '--- TRUNCATED ---' name = to_str(file[T_NAME]) if archive: name += u' \u25bb ' + archive timestamp_field = u'{:<18}' if time else u'{:<10}' if windows: out = u' {}{}{}{}{}{}'.format( timestamp_field.format(file_timestamp(file[T_TIMESTAMP], time)), u'{:<2}'.format(file[T_TYPE] + ('+' if file[T_HAS_XATTR] else '')), to_str(file[T_UID]).rjust(uid_len + 1) + u' ' if uid_len else u'', to_str(file[T_GID]).rjust(gid_len + 1) + u' ' if gid_len else u'', u'{:>9}'.format(size_human_readable(file[T_SIZE])), u' {:<40}'.format(name)) else: if not uid_len: uid_len = 5 if not gid_len: gid_len = 5 out = u' {}{}{}{}{}{}{}'.format( timestamp_field.format(file_timestamp(file[T_TIMESTAMP], time)), u'{:<2}'.format(file[T_TYPE] + ('+' if file[T_HAS_XATTR] else '')), to_str(file[T_UID]).rjust(uid_len + 1) + ' ', to_str(file[T_GID]).rjust(gid_len + 1) + ' ', u'{:04o} '.format(file[T_MODE] & 0o7777), u'{:>9}'.format(size_human_readable(file[T_SIZE])), u' {:<40}'.format(name)) if archive: out = Color(out, 'yellow') elif file[T_TYPE] == 'D': out = Color(out, 'lightyellow') elif 'U' in file[T_SPEC]: out = Color(out, 'lightred') elif 'G' in file[T_SPEC]: out = Color(out, 'red') elif file[T_TYPE] == 'B': out = Color(out, 'grey') elif file[T_TYPE] == 'C': out = Color(out, 'grey') elif file[T_TYPE] == 'F': out = Color(out, 'cyan') elif file[T_TYPE] == 'S': out = Color(out, 'magenta') elif file[T_TYPE] == 'L': out = Color(out, 'grey') elif not file[T_SIZE]: out = Color(out, 'darkgrey') elif 'W' in file[T_SPEC] and not windows: out = Color(out, 'blue') elif file[T_HAS_XATTR]: out = Color(out, 'lightmagenta') elif 'E' in file[T_SPEC]: out = Color(out, 'lightgreen') return out
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) if magic: infos.append('Magic: {}'.format(magic)) for extra, values in extra.iteritems(): if type(values) in (list, tuple): infos.append(List(values, caption=extra)) else: infos.append(Line(extra + ':', values)) self.log(MultiPart(infos))