libacl 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +66 -0
- data/lib/libacl.rb +387 -0
- metadata +75 -0
data/README
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
An implementation of linux ACL (posix1e).
|
2
|
+
Provides more convenience than ruby-acl, and uses FFI so it requires no
|
3
|
+
extra compilation of c files, and works with jruby.
|
4
|
+
|
5
|
+
|
6
|
+
first install ffi/nice-ffi:
|
7
|
+
gem install ffi nice-ffi
|
8
|
+
|
9
|
+
Then download the file 'acl-ffi.rb' and load it:
|
10
|
+
require 'acl-ffi.rb'
|
11
|
+
|
12
|
+
Usage example:
|
13
|
+
require 'acl-ffi.rb'
|
14
|
+
require 'test/unit/assertions'
|
15
|
+
include Test::Unit::Assertions
|
16
|
+
require 'fileutils'
|
17
|
+
include FileUtils
|
18
|
+
|
19
|
+
acl= LibACL::ACL.from_text 'user::rwx
|
20
|
+
group::rx
|
21
|
+
other::---
|
22
|
+
mask::rwx
|
23
|
+
user:root:rwx
|
24
|
+
group:daemon:rx'
|
25
|
+
assert acl.valid?
|
26
|
+
|
27
|
+
|
28
|
+
acl_invalid= LibACL::ACL.from_text '
|
29
|
+
user:nonexiestent_user:---
|
30
|
+
group:does_not_exist:rx
|
31
|
+
garbage_entry:user:::*:xyz'
|
32
|
+
assert !acl_invalid.valid?
|
33
|
+
|
34
|
+
|
35
|
+
#You can write ACL's to and read from directories and files
|
36
|
+
touch '/tmp/foo'
|
37
|
+
mkdir '/tmp/dir' unless File.exist? '/tmp/dir'
|
38
|
+
|
39
|
+
acl.set_file '/tmp/foo'
|
40
|
+
acl.set_default '/tmp/dir'
|
41
|
+
|
42
|
+
acl_foo = LibACL::ACL.from_file '/tmp/foo'
|
43
|
+
acl_def = LibACL::ACL.default '/tmp/dir'
|
44
|
+
|
45
|
+
assert_equal acl_foo.to_text, acl.to_text
|
46
|
+
assert_equal acl_def.to_text, acl.to_text
|
47
|
+
|
48
|
+
|
49
|
+
#Operate on each entry
|
50
|
+
p "Each entry in acl_foo:"
|
51
|
+
acl_foo.each do |entry|
|
52
|
+
puts entry
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
#You can query the acl and get a text representation
|
57
|
+
assert_equal acl_foo.user_obj.permset.to_s, 'rwx'
|
58
|
+
assert_equal acl_foo.other.permset.to_s, "---"
|
59
|
+
|
60
|
+
|
61
|
+
#Find works as expected, and convenience methods exist
|
62
|
+
found = acl_foo.find do |entry|
|
63
|
+
entry.tag_type == :mask
|
64
|
+
end
|
65
|
+
|
66
|
+
assert found == acl_foo.mask
|
data/lib/libacl.rb
ADDED
@@ -0,0 +1,387 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'ffi', '>= 0.5.0'
|
3
|
+
require 'ffi'
|
4
|
+
require 'nice-ffi'
|
5
|
+
require 'test/unit/assertions'
|
6
|
+
include Test::Unit::Assertions
|
7
|
+
|
8
|
+
#Types:
|
9
|
+
#
|
10
|
+
#typedef unsigned int acl_type_t;
|
11
|
+
#typedef int acl_tag_t;
|
12
|
+
#typedef unsigned int acl_perm_t;
|
13
|
+
#
|
14
|
+
#typedef struct __acl_ext *acl_t;
|
15
|
+
#typedef struct __acl_entry_ext *acl_entry_t;
|
16
|
+
#typedef struct __acl_permset_ext *acl_permset_t;
|
17
|
+
|
18
|
+
|
19
|
+
#FFI Posix ACL tested on linux and definitely not working on darwin.
|
20
|
+
module LibACL
|
21
|
+
extend NiceFFI::Library
|
22
|
+
#ffi_lib 'libacl'
|
23
|
+
|
24
|
+
|
25
|
+
if FFI::Platform::IS_LINUX
|
26
|
+
ffi_lib 'libacl'
|
27
|
+
|
28
|
+
# === Constants ===
|
29
|
+
#23.2.2 acl_perm_t values
|
30
|
+
enum :acl_perm, [
|
31
|
+
:read, 0x04,
|
32
|
+
:write, 0x02,
|
33
|
+
:execute, 0x01]
|
34
|
+
|
35
|
+
|
36
|
+
#23.2.5 acl_tag_t values
|
37
|
+
enum :acl_tag, [
|
38
|
+
:undefined_tag, 0x00,
|
39
|
+
:user_obj, 0x01, #regular owner
|
40
|
+
:user, 0x02,
|
41
|
+
:group_obj, 0x04,
|
42
|
+
:group, 0x08,
|
43
|
+
:mask, 0x10,
|
44
|
+
:other, 0x20]
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
#23.3.6 acl_type_t values */
|
49
|
+
enum :acl_type, [
|
50
|
+
:access, 0x8000,
|
51
|
+
:default, 0x4000]
|
52
|
+
|
53
|
+
|
54
|
+
#23.2.7 ACL qualifier constants */
|
55
|
+
#type :id_t
|
56
|
+
ACL_UNDEFINED_ID = -1
|
57
|
+
|
58
|
+
|
59
|
+
#23.2.8 ACL Entry Constants */
|
60
|
+
enum :acl_entry, [
|
61
|
+
:first_entry,0,
|
62
|
+
:next_entry,1]
|
63
|
+
|
64
|
+
end #is linux
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
class ACL < NiceFFI::OpaqueStruct
|
69
|
+
include Enumerable
|
70
|
+
#Create struct capable of holding num entries
|
71
|
+
def self.init(num=10)
|
72
|
+
LibACL::acl_init(num)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.release(ptr)
|
76
|
+
acl_free(ptr)
|
77
|
+
end
|
78
|
+
|
79
|
+
#Construct from file, using mode :access or :default
|
80
|
+
def self.from_file(path, mode=:access)
|
81
|
+
LibACL::acl_get_file(path,mode)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.default(dir)
|
85
|
+
assert File.directory? dir
|
86
|
+
self.from_file(dir,:default)
|
87
|
+
end
|
88
|
+
|
89
|
+
#Construct from text
|
90
|
+
def self.from_text(text)
|
91
|
+
LibACL::acl_from_text(text)
|
92
|
+
end
|
93
|
+
|
94
|
+
#Create a copy of acl.
|
95
|
+
def clone
|
96
|
+
LibACL::acl_dup(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
def valid?
|
100
|
+
LibACL::acl_valid(self)==0
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def to_text
|
105
|
+
LibACL::acl_to_text(self, nil)
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
def set_file(path, mode=:access)
|
110
|
+
assert valid?
|
111
|
+
assert File.exists? path
|
112
|
+
LibACL::acl_set_file(path, mode, self)
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def set_default(dir)
|
117
|
+
assert valid?
|
118
|
+
assert File.directory? dir
|
119
|
+
set_file(dir, :default)
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def create_entry
|
124
|
+
entry_p = FFI::MemoryPointer.new :pointer
|
125
|
+
#acl_p = self.pointer
|
126
|
+
ret= LibACL::acl_create_entry(self, entry_p )
|
127
|
+
raise "Can't create entry" if ret == -1
|
128
|
+
|
129
|
+
|
130
|
+
#test this case...
|
131
|
+
# #in case of reallocation
|
132
|
+
# if acl_p.pointer.address != self.pointer.address
|
133
|
+
# self.pointer=acl_p
|
134
|
+
# end
|
135
|
+
Entry.new entry_p.read_pointer
|
136
|
+
end
|
137
|
+
|
138
|
+
#I'm unsure of how memory is handled in this case
|
139
|
+
#Test!
|
140
|
+
def delete_entry(entry)
|
141
|
+
ret = LibACL::acl_delete_entry(self,entry)
|
142
|
+
raise "Can't delete #{entry}" if ret == -1
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def each(&blk)
|
147
|
+
ptr = FFI::MemoryPointer.new :pointer
|
148
|
+
having = LibACL::acl_get_entry(self, :first_entry, ptr)
|
149
|
+
while (having>0)
|
150
|
+
entry=Entry.new ptr.read_pointer
|
151
|
+
blk.call entry
|
152
|
+
having = LibACL::acl_get_entry(self, :next_entry, ptr)
|
153
|
+
end
|
154
|
+
|
155
|
+
raise "Error getting entry" if having == -1
|
156
|
+
end
|
157
|
+
|
158
|
+
#methods using each implementation
|
159
|
+
|
160
|
+
def user_obj
|
161
|
+
entry_find :user_obj
|
162
|
+
end
|
163
|
+
|
164
|
+
def group_obj
|
165
|
+
entry_find :group_obj
|
166
|
+
end
|
167
|
+
|
168
|
+
def other
|
169
|
+
entry_find :other
|
170
|
+
end
|
171
|
+
|
172
|
+
def mask
|
173
|
+
entry_find :mask
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
def entry_find(tag)
|
178
|
+
find do |entry|
|
179
|
+
entry.tag_type==tag
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
class Entry < NiceFFI::OpaqueStruct
|
188
|
+
def self.release(ptr)
|
189
|
+
acl_free(ptr)
|
190
|
+
end
|
191
|
+
|
192
|
+
#replace this entry with source
|
193
|
+
def replace(source)
|
194
|
+
LibACL::acl_copy_entry(self,source)
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def permset
|
199
|
+
ptr = FFI::MemoryPointer.new :pointer
|
200
|
+
ret = LibACL::acl_get_permset(self, ptr)
|
201
|
+
raise "Error" if ret!=0
|
202
|
+
Permset.new ptr.read_pointer
|
203
|
+
end
|
204
|
+
|
205
|
+
#def permset=
|
206
|
+
#
|
207
|
+
#end
|
208
|
+
|
209
|
+
def tag_type
|
210
|
+
type= LibACL::find_type(:acl_tag)
|
211
|
+
ptr = FFI::MemoryPointer.new type
|
212
|
+
ret = LibACL::acl_get_tag_type(self, ptr)
|
213
|
+
raise "Error" if ret !=0
|
214
|
+
type[ptr.read_int]
|
215
|
+
end
|
216
|
+
|
217
|
+
def qualifier
|
218
|
+
ptr = LibACL::acl_get_qualifier(self)
|
219
|
+
if ptr.null?
|
220
|
+
return nil
|
221
|
+
else
|
222
|
+
return ptr.read_int
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def == (other)
|
227
|
+
permset == other.permset and
|
228
|
+
tag_type == other.tag_type and
|
229
|
+
qualifier == other.qualifier
|
230
|
+
end
|
231
|
+
|
232
|
+
def to_s
|
233
|
+
# tag=tag_type.to_s.sub("_obj","")
|
234
|
+
"#{tag_type}:#{qualifier}:#{permset}"
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
class Permset<NiceFFI::OpaqueStruct
|
240
|
+
@@perm_t=LibACL::find_type(:acl_perm)
|
241
|
+
|
242
|
+
def clear
|
243
|
+
LibACL::acl_clear_perms(self)
|
244
|
+
end
|
245
|
+
|
246
|
+
def add(perm)
|
247
|
+
LibACL::acl_add_perm(self,@@perm_t[perm])
|
248
|
+
end
|
249
|
+
|
250
|
+
def delete(perm)
|
251
|
+
LibACL::acl_delete_perm(self,@@perm_t[perm])
|
252
|
+
end
|
253
|
+
|
254
|
+
def is_set?(perm)
|
255
|
+
LibACL::acl_get_perm(self, @@perm_t[perm]) >0
|
256
|
+
end
|
257
|
+
|
258
|
+
#a linux hack/shortcut
|
259
|
+
def to_i
|
260
|
+
pointer.read_int
|
261
|
+
end
|
262
|
+
|
263
|
+
def == (other)
|
264
|
+
to_i == other.to_i
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
def read?
|
269
|
+
is_set? :read
|
270
|
+
end
|
271
|
+
|
272
|
+
def write?
|
273
|
+
is_set? :write
|
274
|
+
end
|
275
|
+
|
276
|
+
def execute?
|
277
|
+
is_set? :execute
|
278
|
+
end
|
279
|
+
|
280
|
+
def to_s
|
281
|
+
ret=""
|
282
|
+
read? ? ret << "r" : ret << "-"
|
283
|
+
write? ? ret << "w" : ret << "-"
|
284
|
+
execute? ? ret << "x" : ret << "-"
|
285
|
+
ret
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
|
292
|
+
|
293
|
+
|
294
|
+
#=== ACL manipulation ===
|
295
|
+
|
296
|
+
#arg: entries_nr to allocate
|
297
|
+
attach_function 'acl_init',[:int],NiceFFI::TypedPointer( ACL )
|
298
|
+
attach_function 'acl_dup', [:pointer],NiceFFI::TypedPointer( ACL )
|
299
|
+
attach_function 'acl_free', [:pointer],:void
|
300
|
+
attach_function 'acl_valid', [:pointer],:int
|
301
|
+
|
302
|
+
|
303
|
+
#=== Entry manipulation ===
|
304
|
+
|
305
|
+
#copy (dest, source): code
|
306
|
+
attach_function 'acl_copy_entry',[:pointer, :pointer],:int
|
307
|
+
|
308
|
+
#acl, entry*: code
|
309
|
+
attach_function 'acl_create_entry',[:pointer, :pointer],:int
|
310
|
+
attach_function 'acl_delete_entry',[:pointer, :pointer],:int
|
311
|
+
|
312
|
+
#*acl, entry_id, *entry_p: having code
|
313
|
+
attach_function 'acl_get_entry', [:pointer, :int, :pointer], :int
|
314
|
+
|
315
|
+
#Manipulate ACL entry permissions */
|
316
|
+
|
317
|
+
# extern int acl_add_perm(acl_permset_t permset_d, acl_perm_t perm);
|
318
|
+
attach_function 'acl_add_perm',[:pointer,:acl_perm],:int
|
319
|
+
|
320
|
+
# extern int acl_calc_mask(acl_t *acl_p);
|
321
|
+
# extern int acl_clear_perms(acl_permset_t permset_d);
|
322
|
+
attach_function 'acl_clear_perms',[:pointer],:int
|
323
|
+
|
324
|
+
# extern int acl_delete_perm(acl_permset_t permset_d, acl_perm_t perm);
|
325
|
+
attach_function 'acl_delete_perm',[:pointer, :acl_perm],:int
|
326
|
+
|
327
|
+
# extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
|
328
|
+
attach_function 'acl_get_permset', [:pointer,:pointer],:int
|
329
|
+
# extern int acl_set_permset(acl_entry_t entry_d, acl_permset_t permset_d);
|
330
|
+
|
331
|
+
|
332
|
+
#on linux
|
333
|
+
if FFI::Platform::IS_LINUX
|
334
|
+
attach_function 'acl_get_perm',[:pointer,:acl_perm],:int
|
335
|
+
elsif FFI::Platform::IS_BSD
|
336
|
+
attach_function 'acl_get_perm',:acl_get_perm_np,[:pointer,:acl_perm],:int
|
337
|
+
end
|
338
|
+
#on bsd/osx
|
339
|
+
#attach_function 'acl_get_perm_np',[:pointer,:pointer],:int
|
340
|
+
|
341
|
+
|
342
|
+
# #Manipulate ACL entry tag type and qualifier */
|
343
|
+
# extern void * acl_get_qualifier(acl_entry_t entry_d);
|
344
|
+
attach_function 'acl_get_qualifier',[:pointer],:pointer
|
345
|
+
# extern int acl_get_tag_type(acl_entry_t entry_d, acl_tag_t *tag_type_p);
|
346
|
+
attach_function 'acl_get_tag_type',[:pointer,:pointer],:int
|
347
|
+
# extern int acl_set_qualifier(acl_entry_t entry_d, const void *tag_qualifier_p);
|
348
|
+
attach_function 'acl_set_qualifier',[:pointer,:pointer],:int
|
349
|
+
# extern int acl_set_tag_type(acl_entry_t entry_d, acl_tag_t tag_type);
|
350
|
+
|
351
|
+
|
352
|
+
|
353
|
+
#=== Format translation ===
|
354
|
+
|
355
|
+
#attach_function 'acl_copy_ext', [:inbuffer,:pointer,:ssize_t],:ssize_t
|
356
|
+
#extern acl_t acl_copy_int(const void *buf_p);
|
357
|
+
|
358
|
+
attach_function 'acl_from_text', [:string],NiceFFI::TypedPointer( ACL )
|
359
|
+
attach_function 'acl_size',[:pointer],:ssize_t
|
360
|
+
|
361
|
+
#second pointer is ssize_t *len_p
|
362
|
+
attach_function 'acl_to_text',[:pointer,:pointer],:string
|
363
|
+
|
364
|
+
#=== Object manipulation ===
|
365
|
+
|
366
|
+
#extern int acl_delete_def_file(const char *path_p);
|
367
|
+
#extern acl_t acl_get_fd(int fd);
|
368
|
+
|
369
|
+
#path, type: new acl
|
370
|
+
attach_function 'acl_get_file',[:string, :acl_type ],NiceFFI::TypedPointer( ACL )
|
371
|
+
|
372
|
+
#extern int acl_set_fd(int fd, acl_t acl);
|
373
|
+
|
374
|
+
#int acl_set_file(const char *path_p, acl_type_t type, acl_t acl);
|
375
|
+
attach_function 'acl_set_file',[:string, :acl_type, :pointer],:int
|
376
|
+
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
|
381
|
+
|
382
|
+
|
383
|
+
|
384
|
+
|
385
|
+
|
386
|
+
|
387
|
+
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: libacl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Zachris Trolin
|
8
|
+
autorequire: libacl
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-01 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ffi
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nice-ffi
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: zachris.trolin@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README
|
43
|
+
files:
|
44
|
+
- lib/libacl.rb
|
45
|
+
- README
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/zachris/acl-ffi
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Linux ACL for ruby using ffi
|
74
|
+
test_files: []
|
75
|
+
|