forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile_stat.rb
228 lines (206 loc) · 4.83 KB
/
file_stat.rb
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
# -*- coding: binary -*-
#
# This is just a container class basically, that acts like File::Struct
#
# You must supply an initialize method that somehow populates the stathash..
#
module Rex
module Post
###
#
# This class emulates the ruby FileStat class against a remote entity in a
# generic fashion. Refer to the ruby documentation for expected behavior.
#
###
class FileStat
#
# Basic file types.
#
@@ftypes = [
'fifo', 'characterSpecial', 'directory',
'blockSpecial', 'file', 'link', 'socket'
]
attr_accessor :stathash
def initialize(buf='')
self.stathash = {}
update(buf) if (buf and not buf.empty?)
end
def dev
self.stathash['st_dev']
end
def ino
self.stathash['st_ino']
end
def mode
self.stathash['st_mode']
end
def nlink
self.stathash['st_nlink']
end
def uid
self.stathash['st_uid']
end
def gid
self.stathash['st_gid']
end
def rdev
self.stathash['st_rdev']
end
def size
self.stathash['st_size']
end
def blksize
self.stathash['st_blksize']
end
def blocks
self.stathash['st_blocks']
end
def atime
::Time.at(self.stathash['st_atime'])
end
def mtime
::Time.at(self.stathash['st_mtime'])
end
def ctime
::Time.at(self.stathash['st_ctime'])
end
def update(buf)
skeys = %W{st_dev st_mode st_nlink st_uid st_gid st_rdev st_ino st_size st_atime st_mtime st_ctime}
svals = buf.unpack("VVVVVVQQQQQ")
skeys.each_index do |i|
self.stathash[ skeys[i] ] = svals[i]
end
end
#
# This handles the old 32bit st_size buf from old stageless meterpreters for backwards compatibility
# Maybe we can remove this in the future
#
def update32(buf)
skeys = %W{st_dev st_ino st_mode st_pad st_nlink st_uid st_gid st_rdev st_size st_ctime st_atime st_mtime}
svals = buf.unpack("VvvvvvvVVVVV")
skeys.each_index do |i|
self.stathash[ skeys[i] ] = svals[i]
end
end
#
# S_IFMT 0170000 bitmask for the file type bitfields
# S_IFSOCK 0140000 socket
# S_IFLNK 0120000 symbolic link
# S_IFREG 0100000 regular file
# S_IFBLK 0060000 block device
# S_IFDIR 0040000 directory
# S_IFCHR 0020000 character device
# S_IFIFO 0010000 fifo
#
# this is my own, just a helper...
def filetype?(mask)
return true if mode & 0170000 == mask
return false
end
def blockdev?
filetype?(060000)
end
def chardev?
filetype?(020000)
end
def directory?
filetype?(040000)
end
def file?
filetype?(0100000)
end
def pipe?
filetype?(010000) # ??? fifo?
end
def socket?
filetype?(0140000)
end
def symlink?
filetype?(0120000)
end
def ftype
return @@ftypes[(mode & 0170000) >> 13].dup
end
#
# S_ISUID 0004000 set UID bit
# S_ISGID 0002000 set GID bit (see below)
# S_ISVTX 0001000 sticky bit (see below)
# S_IRWXU 00700 mask for file owner permissions
# S_IRUSR 00400 owner has read permission
# S_IWUSR 00200 owner has write permission
# S_IXUSR 00100 owner has execute permission
# S_IRWXG 00070 mask for group permissions
# S_IRGRP 00040 group has read permission
# S_IWGRP 00020 group has write permission
# S_IXGRP 00010 group has execute permission
# S_IRWXO 00007 mask for permissions for others (not in group)
# S_IROTH 00004 others have read permission
# S_IWOTH 00002 others have write permisson
# S_IXOTH 00001 others have execute permission
#
def perm?(mask)
return true if mode & mask == mask
return false
end
def setgid?
perm?(02000)
end
def setuid?
perm?(04000)
end
def sticky?
perm?(01000)
end
def executable?
raise NotImplementedError
end
def executable_real?
raise NotImplementedError
end
def grpowned?
raise NotImplementedError
end
def owned?
raise NotImplementedError
end
def readable?
raise NotImplementedError
end
def readable_real?
raise NotImplementedError
end
def writeable?
raise NotImplementedError
end
def writeable_real?
raise NotImplementedError
end
#
# Return pretty information about a file's permissions.
#
def prettymode
m = mode
om = '%06o' % m
perms = ''
3.times {
perms = ((m & 01) == 01 ? 'x' : '-') + perms
perms = ((m & 02) == 02 ? 'w' : '-') + perms
perms = ((m & 04) == 04 ? 'r' : '-') + perms
m >>= 3
}
return "#{om}/#{perms}"
end
#
# Return pretty information about a file.
#
def pretty
" Size: #{size} Blocks: #{blocks} IO Block: #{blksize} Type: #{rdev}\n"\
"Device: #{dev} Inode: #{ino} Links: #{nlink}\n"\
" Mode: #{prettymode}\n"\
" Uid: #{uid} Gid: #{gid}\n"\
"Access: #{atime}\n"\
"Modify: #{mtime}\n"\
"Change: #{ctime}\n"
end
end
end; end # Post/Rex