cap2 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -49,16 +49,16 @@ Capabilities are referenced using lower cased symbols, and without the CAP_ pref
49
49
 
50
50
  ### Querying Capabilities
51
51
 
52
- There are three methods - `permitted?`, `effective?` and `inheritable?` - defined on both `Cap2::Process` and `Cap2::File` for querying capabilities. Each take a capability symbol and return true / false if the capability is in / not in the relevant set:
52
+ There are three methods - `permitted?`, `enabled?` and `inheritable?` - defined on both `Cap2::Process` and `Cap2::File` for querying capabilities. Each of these methods, Cap2::File#enabled? being the exception, take a capability symbol and return true / false if the capability is in / not in the relevant set:
53
53
 
54
54
  ```
55
- # the init daemon - all caps permitted & effective but not inheritable
55
+ # the init daemon - all caps permitted & enabled but not inheritable
56
56
  init = Cap2.process(1) # => #<Cap2::Process @pid=1>
57
57
 
58
58
  init.permitted?(:kill) # => true
59
59
  init.permitted?(:chown) # => true
60
60
 
61
- init.effective?(:fowner) # => true
61
+ init.enabled?(:fowner) # => true
62
62
 
63
63
  init.inheritable?(:kill) # => false
64
64
  init.inheritable?(:fowner) # => false
@@ -69,11 +69,15 @@ ping = Cap2.file('/bin/ping') # => #<Cap2::File @filename="/bin/ping">
69
69
  ping.permitted?(:net_raw) # => true
70
70
  ping.permitted?(:mknod) # => false
71
71
 
72
- ping.effective?(:net_raw) # => true
72
+ ping.enabled? # => true
73
73
 
74
74
  ping.inheritable?(:net_raw) # => false
75
75
  ```
76
76
 
77
+ #### Why does Cap2::File#enabled? not take an arguement?
78
+
79
+ Under the hood, the file effective set is just a single bit. When enabled, any process which exec's the file will have the capabilities from it's resulting permitted set also in it's effective set.
80
+
77
81
  ### Modifying Capabilities
78
82
 
79
83
  Cap2 provides different levels of control over process and file capabilities.
@@ -83,7 +87,7 @@ Cap2 provides different levels of control over process and file capabilities.
83
87
  To modify the permitted capabilities of a file (i.e. the capabilities which will be permitted in any process that exec's the file), use `Cap2::File#permit` and `Cap2::File#unpermit`:
84
88
 
85
89
  ```
86
- Cap2.process.effective?(:setfcap) # => true - needed to set file capabilities
90
+ Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
87
91
 
88
92
  file = Cap2.file('/tmp/file') # => #<Cap2::File @filename="/tmp/file">
89
93
 
@@ -96,26 +100,27 @@ file.unpermit(:mknod) # => true
96
100
  file.permitted?(:mknod) # => false
97
101
  ```
98
102
 
99
- To modify the effective capabilities of a file (i.e. the capabilities which will be enabled in any process that exec's the file), use `Cap2::File#enable_on_exec` and `Cap2::File#disable_on_exec`:
103
+ To modify the effective bit of a file (i.e. whether the resulting permitted capabilities of any process that exec's the file will also be enabled in it's effective set), use `Cap2::File#enable` and `Cap2::File#disable`:
100
104
 
101
105
  ```
102
- Cap2.process.effective?(:setfcap) # => true - needed to set file capabilities
106
+ Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
103
107
 
104
108
  file = Cap2.file('/tmp/file') # => #<Cap2::File @filename="/tmp/file">
105
109
 
106
- file.effective?(:net_raw) # => false
110
+ file.permitted?(:net_raw) # => true
111
+ file.enabled? # => false
107
112
 
108
- file.enable_on_exec(:net_raw) # => true
109
- file.effective?(:net_raw) # => true
113
+ file.enable # => true
114
+ file.enabled? # => true
110
115
 
111
- file.disable_on_exec(:net_raw) # => true
112
- file.effective?(:net_raw) # => false
116
+ file.disable # => true
117
+ file.enabled? # => false
113
118
  ```
114
119
 
115
120
  To modify the inheritable capabilities of a file (i.e. the capabilities which will be ANDed with the inheritable set of any process that exec's the file to determine which capabilities are in the permitted set of the process), use `Cap2::File#allow_inherit` and `Cap2::File#disallow_inherit`:
116
121
 
117
122
  ```
118
- Cap2.process.effective?(:setfcap) # => true - needed to set file capabilities
123
+ Cap2.process.enabled?(:setfcap) # => true - needed to set file capabilities
119
124
 
120
125
  file = Cap2.file('/tmp/file') # => #<Cap2::File @filename="/tmp/file">
121
126
 
@@ -132,22 +137,22 @@ file.inheritable?(:fowner) # => false
132
137
 
133
138
  Cap2 can be used to enable / disable capabilities of the current Ruby process.
134
139
 
135
- Suppose the ruby binary file permits :kill, but does not enable it on exec:
140
+ Suppose the ruby binary file permits `:kill`, but does not enable it on exec:
136
141
 
137
142
  ```
138
143
  ruby = Cap2.file('/usr/bin/ruby') # => #<Cap2::File @filename="/usr/bin/ruby">
139
144
  ruby.permitted?(:kill) # => true
140
- ruby.effective?(:kill) # => false
145
+ ruby.enabled? # => false
141
146
  ```
142
147
 
143
148
  and we want to kill a process running as root with pid 1000:
144
149
 
145
150
  ```
146
- Cap2.process.effective?(:kill) # => false
151
+ Cap2.process.enabled?(:kill) # => false
147
152
  Process.kill("TERM", 1000) # => Errno::EPERM: Operation not permitted
148
153
 
149
154
  Cap2.process.enable(:kill) # => true
150
- Cap2.process.effective?(:kill) # => true
155
+ Cap2.process.enabled?(:kill) # => true
151
156
  Process.kill("TERM", 1000) # => 1
152
157
  ```
153
158
 
@@ -1,29 +1,10 @@
1
1
  #include <ruby.h>
2
+ #include <stdbool.h>
2
3
  #include <errno.h>
3
4
  #include <unistd.h>
4
5
  #include <sys/capability.h>
5
6
  #include "cap2.h"
6
7
 
7
- /*
8
- * Converts a Ruby symbol into cap_flag_t set, defined in <sys/capability.h>
9
- *
10
- * Raises an ArgumentError if set is not a valid capability set.
11
- */
12
- cap_flag_t cap2_sym_to_set(VALUE set) {
13
- char *set_s;
14
-
15
- Check_Type(set, T_SYMBOL);
16
-
17
- set = rb_sym_to_s(set);
18
-
19
- set_s = StringValueCStr(set);
20
-
21
- if(strcmp(set_s, "permitted") == 0) return CAP_PERMITTED;
22
- else if(strcmp(set_s, "effective") == 0) return CAP_EFFECTIVE;
23
- else if(strcmp(set_s, "inheritable") == 0) return CAP_INHERITABLE;
24
- else rb_raise(rb_eArgError, "unknown set %s", set_s);
25
- }
26
-
27
8
  /*
28
9
  * Lookup the value of a capability in cap2_caps, defined in cap2.h
29
10
  * (cap2.h is generated dynamically by extconf.rb).
@@ -52,21 +33,50 @@ cap_value_t cap2_sym_to_cap(VALUE cap) {
52
33
  return cap2_cap_value(StringValueCStr(cap));
53
34
  }
54
35
 
55
- /*
56
- * Returns a boolean representing whether cap_d has the given capability enabled
57
- * in the given set.
58
- */
59
- VALUE cap2_has_cap(cap_t cap_d, VALUE set_sym, VALUE cap_sym) {
60
- cap_flag_t set;
61
- cap_value_t cap;
62
- cap_flag_value_t flag_value = CAP_CLEAR;
36
+ VALUE cap2_caps_to_hash(cap_t cap_d) {
37
+ int i;
38
+ cap_flag_value_t cap_value;
39
+ VALUE caps, permitted, effective, inheritable;
40
+
41
+ permitted = rb_ary_new();
42
+ effective = rb_ary_new();
43
+ inheritable = rb_ary_new();
63
44
 
64
- set = cap2_sym_to_set(set_sym);
65
- cap = cap2_sym_to_cap(cap_sym);
45
+ for(i = 0; i < __CAP_COUNT; i++) {
46
+ cap_get_flag(cap_d, cap2_caps[i].value, CAP_PERMITTED, &cap_value);
47
+ if(cap_value == CAP_SET)
48
+ rb_ary_push(permitted, ID2SYM(rb_intern(cap2_caps[i].name)));
49
+
50
+ cap_get_flag(cap_d, cap2_caps[i].value, CAP_EFFECTIVE, &cap_value);
51
+ if(cap_value == CAP_SET)
52
+ rb_ary_push(effective, ID2SYM(rb_intern(cap2_caps[i].name)));
53
+
54
+ cap_get_flag(cap_d, cap2_caps[i].value, CAP_INHERITABLE, &cap_value);
55
+ if(cap_value == CAP_SET)
56
+ rb_ary_push(inheritable, ID2SYM(rb_intern(cap2_caps[i].name)));
57
+ }
66
58
 
67
- cap_get_flag(cap_d, cap, set, &flag_value);
59
+ caps = rb_hash_new();
68
60
 
69
- return flag_value == CAP_SET ? Qtrue : Qfalse;
61
+ rb_hash_aset(
62
+ caps,
63
+ ID2SYM(rb_intern("permitted")),
64
+ rb_funcall(permitted, rb_intern("to_set"), 0)
65
+ );
66
+
67
+ rb_hash_aset(
68
+ caps,
69
+ ID2SYM(rb_intern("effective")),
70
+ rb_funcall(effective, rb_intern("to_set"), 0)
71
+ );
72
+
73
+ rb_hash_aset(
74
+ caps,
75
+ ID2SYM(rb_intern("inheritable")),
76
+ rb_funcall(inheritable, rb_intern("to_set"), 0)
77
+ );
78
+
79
+ return caps;
70
80
  }
71
81
 
72
82
  /*
@@ -80,14 +90,12 @@ static int cap2_process_pid(VALUE process) {
80
90
  return FIX2INT(pid);
81
91
  }
82
92
 
83
- /*
84
- * Return a cap_t struct containing the capabilities of the given Process object.
85
- */
86
- static cap_t cap2_process_caps(VALUE process) {
93
+ VALUE cap2_process_getcaps(VALUE self) {
87
94
  cap_t cap_d;
88
95
  int pid;
96
+ VALUE result;
89
97
 
90
- pid = cap2_process_pid(process);
98
+ pid = cap2_process_pid(self);
91
99
 
92
100
  cap_d = cap_get_pid(pid);
93
101
 
@@ -97,102 +105,80 @@ static cap_t cap2_process_caps(VALUE process) {
97
105
  "Failed to get capabilities for proccess %d: (%s)\n",
98
106
  pid, strerror(errno)
99
107
  );
108
+ } else {
109
+ result = cap2_caps_to_hash(cap_d);
110
+ cap_free(cap_d);
111
+ return result;
100
112
  }
101
-
102
- return cap_d;
103
113
  }
104
114
 
105
115
  /*
106
- * Enable/disable the given capability in the given set for the given Process
107
- * object.
116
+ * Set the capabilities for self from the caps hash stored in @caps.
108
117
  */
109
- static VALUE cap2_process_set_cap(VALUE process, cap_flag_t set, VALUE cap_sym, cap_flag_value_t set_or_clear) {
118
+ VALUE cap2_process_setcaps(VALUE self) {
119
+ int i;
110
120
  cap_t cap_d;
111
- int pid;
112
- cap_value_t caps[1];
121
+ VALUE caps, cap_array, cap_sym;
122
+ cap_value_t cap_values[__CAP_COUNT];
113
123
 
114
- pid = cap2_process_pid(process);
124
+ cap_d = cap_init();
115
125
 
116
- if((pid_t) pid != getpid())
117
- rb_raise(
118
- rb_eRuntimeError,
119
- "Cannot set capabilities for other processes"
120
- );
126
+ caps = rb_iv_get(self, "@caps");
121
127
 
122
- caps[0] = cap2_sym_to_cap(cap_sym);
128
+ // permitted
129
+ cap_array = rb_funcall(
130
+ rb_hash_aref(caps, ID2SYM(rb_intern("permitted"))),
131
+ rb_intern("to_a"),
132
+ 0
133
+ );
123
134
 
124
- cap_d = cap_get_pid(pid);
135
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
136
+ cap_sym = RARRAY_PTR(cap_array)[i];
137
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
138
+ }
139
+
140
+ cap_set_flag(cap_d, CAP_PERMITTED, i, cap_values, CAP_SET);
125
141
 
126
- cap_set_flag(cap_d, set, 1, caps, set_or_clear);
142
+ // effective
143
+ cap_array = rb_funcall(
144
+ rb_hash_aref(caps, ID2SYM(rb_intern("effective"))),
145
+ rb_intern("to_a"),
146
+ 0
147
+ );
148
+
149
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
150
+ cap_sym = RARRAY_PTR(cap_array)[i];
151
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
152
+ }
153
+
154
+ cap_set_flag(cap_d, CAP_EFFECTIVE, i, cap_values, CAP_SET);
155
+
156
+ // inheritable
157
+ cap_array = rb_funcall(
158
+ rb_hash_aref(caps, ID2SYM(rb_intern("inheritable"))),
159
+ rb_intern("to_a"),
160
+ 0
161
+ );
162
+
163
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
164
+ cap_sym = RARRAY_PTR(cap_array)[i];
165
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
166
+ }
167
+
168
+ cap_set_flag(cap_d, CAP_INHERITABLE, i, cap_values, CAP_SET);
127
169
 
128
170
  if(cap_set_proc(cap_d) == -1) {
129
171
  rb_raise(
130
172
  rb_eRuntimeError,
131
- "Failed to set capabilities for process %d: (%s)\n",
132
- pid, strerror(errno)
173
+ "Failed to set capabilities for current process: (%s)\n",
174
+ strerror(errno)
133
175
  );
134
176
  } else {
177
+ cap_free(cap_d);
135
178
  return Qtrue;
136
179
  }
137
180
  }
138
181
 
139
- /*
140
- * call-seq:
141
- * has?(set, capability) -> true or false
142
- *
143
- * Return whether the process has the given capability enabled in the given set.
144
- *
145
- * Cap2.process(1).has?(:permitted, :kill) #=> true
146
- * Cap2.process(1000).has?(:permitted, :kill) #=> false
147
- */
148
- VALUE cap2_process_has_cap(VALUE self, VALUE set_sym, VALUE cap_sym) {
149
- cap_t cap_d;
150
- VALUE result;
151
-
152
- cap_d = cap2_process_caps(self);
153
-
154
- result = cap2_has_cap(cap_d, set_sym, cap_sym);
155
-
156
- cap_free(cap_d);
157
-
158
- return result;
159
- }
160
-
161
- /*
162
- * call-seq:
163
- * enable(capability) -> true or false
164
- *
165
- * Enable the given capability for this process.
166
- *
167
- * Raises a RuntimeError if the process's pid is not the same as the current
168
- * pid (you cannot enable capabilities for other processes, that's their job).
169
- *
170
- * process = Cap2.process #=> <Cap2::Process>
171
- * process.permitted?(:kill) #=> true
172
- * process.effective?(:kill) #=> false
173
- * process.enable(:kill) #=> true
174
- * process.effective?(:kill) #=> true
175
- */
176
- VALUE cap2_process_enable(VALUE self, VALUE cap_sym) {
177
- return cap2_process_set_cap(self, CAP_EFFECTIVE, cap_sym, CAP_SET);
178
- }
179
-
180
- /*
181
- * call-seq:
182
- * disable(capability) -> true or false
183
- *
184
- * Disable the given capability for this process.
185
- *
186
- * process = Cap2.process #=> <Cap2::Process>
187
- * process.permitted?(:kill) #=> true
188
- * process.effective?(:kill) #=> true
189
- * process.disable(:kill) #=> true
190
- * process.effective?(:kill) #=> false
191
- */
192
- VALUE cap2_process_disable(VALUE self, VALUE cap_sym) {
193
- return cap2_process_set_cap(self, CAP_EFFECTIVE, cap_sym, CAP_CLEAR);
194
- }
195
-
196
182
  /*
197
183
  * Convert @filename stored in the given File object to a char* and return it.
198
184
  */
@@ -205,13 +191,14 @@ static char *cap2_file_filename(VALUE file) {
205
191
  }
206
192
 
207
193
  /*
208
- * Return a cap_t struct containing the capabilities of the given File object.
194
+ * Return a caps hash containing the capabilities of self.
209
195
  */
210
- static cap_t cap2_file_caps(VALUE file) {
196
+ VALUE cap2_file_getcaps(VALUE self) {
211
197
  cap_t cap_d;
212
198
  char *filename;
199
+ VALUE result;
213
200
 
214
- filename = cap2_file_filename(file);
201
+ filename = cap2_file_filename(self);
215
202
 
216
203
  cap_d = cap_get_file(filename);
217
204
 
@@ -221,30 +208,70 @@ static cap_t cap2_file_caps(VALUE file) {
221
208
  "Failed to get capabilities for file %s: (%s)\n",
222
209
  filename, strerror(errno)
223
210
  );
211
+ } else {
212
+ result = cap2_caps_to_hash(cap_d);
213
+ cap_free(cap_d);
214
+ return result;
224
215
  }
225
-
226
- return cap_d;
227
216
  }
228
217
 
229
218
  /*
230
- * Enable/disable the given capability in the given set for the given File
231
- * object.
219
+ * Set the capabilities for self from the caps hash stored in @caps.
232
220
  */
233
- static VALUE cap2_file_set_cap(VALUE file, cap_flag_t set, VALUE cap_sym, cap_flag_value_t set_or_clear) {
221
+ VALUE cap2_file_setcaps(VALUE self) {
222
+ int i;
234
223
  cap_t cap_d;
235
224
  char *filename;
236
- cap_value_t caps[1];
225
+ VALUE caps, cap_array, cap_sym;
226
+ cap_value_t cap_values[__CAP_COUNT];
237
227
 
238
- filename = cap2_file_filename(file);
228
+ cap_d = cap_init();
239
229
 
240
- caps[0] = cap2_sym_to_cap(cap_sym);
230
+ caps = rb_iv_get(self, "@caps");
241
231
 
242
- cap_d = cap_get_file(filename);
232
+ // permitted
233
+ cap_array = rb_funcall(
234
+ rb_hash_aref(caps, ID2SYM(rb_intern("permitted"))),
235
+ rb_intern("to_a"),
236
+ 0
237
+ );
238
+
239
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
240
+ cap_sym = RARRAY_PTR(cap_array)[i];
241
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
242
+ }
243
+
244
+ cap_set_flag(cap_d, CAP_PERMITTED, i, cap_values, CAP_SET);
245
+
246
+ // effective
247
+ cap_array = rb_funcall(
248
+ rb_hash_aref(caps, ID2SYM(rb_intern("effective"))),
249
+ rb_intern("to_a"),
250
+ 0
251
+ );
252
+
253
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
254
+ cap_sym = RARRAY_PTR(cap_array)[i];
255
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
256
+ }
257
+
258
+ cap_set_flag(cap_d, CAP_EFFECTIVE, i, cap_values, CAP_SET);
259
+
260
+ // inheritable
261
+ cap_array = rb_funcall(
262
+ rb_hash_aref(caps, ID2SYM(rb_intern("inheritable"))),
263
+ rb_intern("to_a"),
264
+ 0
265
+ );
266
+
267
+ for(i = 0; i < RARRAY_LEN(cap_array); i++) {
268
+ cap_sym = RARRAY_PTR(cap_array)[i];
269
+ cap_values[i] = cap2_sym_to_cap(cap_sym);
270
+ }
243
271
 
244
- if(cap_d == NULL)
245
- cap_d = cap_init();
272
+ cap_set_flag(cap_d, CAP_INHERITABLE, i, cap_values, CAP_SET);
246
273
 
247
- cap_set_flag(cap_d, set, 1, caps, set_or_clear);
274
+ filename = cap2_file_filename(self);
248
275
 
249
276
  if(cap_set_file(filename, cap_d) == -1) {
250
277
  rb_raise(
@@ -253,123 +280,13 @@ static VALUE cap2_file_set_cap(VALUE file, cap_flag_t set, VALUE cap_sym, cap_fl
253
280
  filename, strerror(errno)
254
281
  );
255
282
  } else {
283
+ cap_free(cap_d);
256
284
  return Qtrue;
257
285
  }
258
286
  }
259
287
 
260
- /*
261
- * call-seq:
262
- * has?(set, capability) -> true or false
263
- *
264
- * Return whether the file has the given capability enabled in the given set.
265
- *
266
- * Cap2.file('/bin/ping').has?(:permitted, :net_raw) #=> true
267
- * Cap2.file('/tmp/ping').has?(:permitted, :net_raw) #=> false
268
- */
269
- VALUE cap2_file_has_cap(VALUE self, VALUE set_sym, VALUE cap_sym) {
270
- cap_t cap_d;
271
- VALUE result;
272
-
273
- cap_d = cap2_file_caps(self);
274
-
275
- result = cap2_has_cap(cap_d, set_sym, cap_sym);
276
-
277
- cap_free(cap_d);
278
-
279
- return result;
280
- }
281
-
282
- /*
283
- * call-seq:
284
- * permit(capability) -> true or false
285
- *
286
- * Permit processes executing this file to enable the given capability.
287
- *
288
- * file = Cap2.file('/tmp/killer') #=> <Cap2::File>
289
- * file.permitted?(:kill) #=> false
290
- * file.permit(:kill) #=> true
291
- * file.permitted?(:kill) #=> true
292
- */
293
- VALUE cap2_file_permit(VALUE self, VALUE cap_sym) {
294
- return cap2_file_set_cap(self, CAP_PERMITTED, cap_sym, CAP_SET);
295
- }
296
-
297
- /*
298
- * call-seq:
299
- * unpermit(capability) -> true or false
300
- *
301
- * Dont permit processes executing ths file to enable the given capability.
302
- *
303
- * file = Cap2.file('/tmp/foo') #=> <Cap2::File>
304
- * file.permit(:kill) #=> true
305
- * file.permitted?(:kill) #=> true
306
- * file.unpermit(:kill) #=> true
307
- * file.permitted?(:kill) #=> false
308
- */
309
- VALUE cap2_file_unpermit(VALUE self, VALUE cap_sym) {
310
- return cap2_file_set_cap(self, CAP_PERMITTED, cap_sym, CAP_CLEAR);
311
- }
312
-
313
- /*
314
- * call-seq:
315
- * allow_inherit(capability) -> true or false
316
- *
317
- * Allow processes executing this file to inherit the given capability.
318
- *
319
- * file = Cap2.file('/tmp/foo') #=> <Cap2::File>
320
- * file.inheritable?(:kill) #=> false
321
- * file.allow_inherit(:kill) #=> true
322
- * file.inheritable?(:kill) #=> true
323
- */
324
- VALUE cap2_file_allow_inherit(VALUE self, VALUE cap_sym) {
325
- return cap2_file_set_cap(self, CAP_INHERITABLE, cap_sym, CAP_SET);
326
- }
327
-
328
- /*
329
- * call-seq:
330
- * disallow_inherit(capability) -> true or false
331
- *
332
- * Dont allow processes executing this file to inherit the given capability.
333
- *
334
- * file = Cap2.file('/tmp/foo') #=> <Cap2::File>
335
- * file.inheritable?(:kill) #=> true
336
- * file.allow_inherit(:kill) #=> true
337
- * file.inheritable?(:kill) #=> false
338
- */
339
- VALUE cap2_file_disallow_inherit(VALUE self, VALUE cap_sym) {
340
- return cap2_file_set_cap(self, CAP_INHERITABLE, cap_sym, CAP_CLEAR);
341
- }
342
-
343
- /*
344
- * call-seq:
345
- * set_effective(capability) -> true or false
346
- *
347
- * Enable the given capability when a proces executes this file.
348
- *
349
- * file = Cap2.file('/tmp/foo') #=> <Cap2::File>
350
- * file.effective?(:kill) #=> false
351
- * file.set_effective(:kill) #=> true
352
- * file.effective?(:kill) #=> true
353
- */
354
- VALUE cap2_file_set_effective(VALUE self, VALUE cap_sym) {
355
- return cap2_file_set_cap(self, CAP_EFFECTIVE, cap_sym, CAP_SET);
356
- }
357
-
358
- /*
359
- * call-seq:
360
- * disable_on_exec(capability) -> true or false
361
- *
362
- * Dont enable the given capability when a process executes this file.
363
- *
364
- * file = Cap2.file('/tmp/foo') #=> <Cap2::File>
365
- * file.effective?(:kill) #=> true
366
- * file.disable_on_exec(:kill) #=> true
367
- * file.effective?(:kill) #=> false
368
- */
369
- VALUE cap2_file_clear_effective(VALUE self, VALUE cap_sym) {
370
- return cap2_file_set_cap(self, CAP_EFFECTIVE, cap_sym, CAP_CLEAR);
371
- }
372
288
  void Init_cap2(void) {
289
+ int i;
373
290
  VALUE rb_mCap2;
374
291
  VALUE rb_cCap2File;
375
292
  VALUE rb_cCap2Process;
@@ -377,16 +294,10 @@ void Init_cap2(void) {
377
294
  rb_mCap2 = rb_define_module("Cap2");
378
295
 
379
296
  rb_cCap2Process = rb_define_class_under(rb_mCap2, "Process", rb_cObject);
380
- rb_define_method(rb_cCap2Process, "has?", cap2_process_has_cap, 2);
381
- rb_define_method(rb_cCap2Process, "enable", cap2_process_enable, 1);
382
- rb_define_method(rb_cCap2Process, "disable", cap2_process_disable, 1);
297
+ rb_define_method(rb_cCap2Process, "getcaps", cap2_process_getcaps, 0);
298
+ rb_define_method(rb_cCap2Process, "save", cap2_process_setcaps, 0);
383
299
 
384
300
  rb_cCap2File = rb_define_class_under(rb_mCap2, "File", rb_cObject);
385
- rb_define_method(rb_cCap2File, "has?", cap2_file_has_cap, 2);
386
- rb_define_method(rb_cCap2File, "permit", cap2_file_permit, 1);
387
- rb_define_method(rb_cCap2File, "unpermit", cap2_file_unpermit, 1);
388
- rb_define_method(rb_cCap2File, "allow_inherit", cap2_file_allow_inherit, 1);
389
- rb_define_method(rb_cCap2File, "disallow_inherit", cap2_file_disallow_inherit, 1);
390
- rb_define_method(rb_cCap2File, "set_effective", cap2_file_set_effective, 1);
391
- rb_define_method(rb_cCap2File, "disable_on_exec", cap2_file_clear_effective, 1);
301
+ rb_define_method(rb_cCap2File, "getcaps", cap2_file_getcaps, 0);
302
+ rb_define_method(rb_cCap2File, "save", cap2_file_setcaps, 0);
392
303
  }
@@ -1,3 +1,4 @@
1
+ require 'set'
1
2
  require 'cap2.so'
2
3
  require 'cap2/process'
3
4
  require 'cap2/file'
@@ -49,7 +50,4 @@ module Cap2
49
50
 
50
51
  # Raised when trying to initialise a File object for a non-existent file.
51
52
  class FileNotFound < StandardError; end
52
-
53
- # Raised when trying to enable unpermitted / uninheritable file capabilities.
54
- class IncompatibleCapabilities < StandardError; end
55
53
  end
Binary file
@@ -1,26 +1,71 @@
1
- require 'cap2/set_methods'
2
-
3
1
  module Cap2
4
- # A class with methods for querying capabilities for the
2
+ # A class with methods for managing capabilities for the
5
3
  # file with filename provided to the initialize method.
6
4
  class File
7
- include SetMethods
8
-
9
5
  # Initialize a new File object for the given filename.
10
6
  def initialize(filename)
11
7
  @filename = filename
8
+ @caps = getcaps
9
+ end
10
+
11
+ # Returns whether the given capability is permitted
12
+ def permitted?(capability)
13
+ reload
14
+ @caps[:permitted].include? capability
15
+ end
16
+
17
+ # Returns whether the given capability is inheritable
18
+ def inheritable?(capability)
19
+ reload
20
+ @caps[:inheritable].include? capability
21
+ end
22
+
23
+ # Returns whether or not the file has any effective
24
+ # capabilities.
25
+ def enabled?
26
+ reload
27
+ !@caps[:effective].empty?
28
+ end
29
+
30
+ # Permit processes executing this file to enable the given capability.
31
+ def permit(capability)
32
+ @caps[:permitted].add(capability)
33
+ save
34
+ end
35
+
36
+ # Dont permit processes executing this file to enable the given capability.
37
+ def unpermit(capability)
38
+ @caps[:permitted].delete(capability)
39
+ save
40
+ end
41
+
42
+ # Allow processes executing this file to inherit the given capability.
43
+ def allow_inherit(capability)
44
+ @caps[:inheritable].add(capability)
45
+ save
46
+ end
47
+
48
+ # Dont allow processes executing this file to inherit the given capability.
49
+ def disallow_inherit(capability)
50
+ @caps[:inheritable].delete(capability)
51
+ save
52
+ end
53
+
54
+ # Enable the permitted capabilities when a proces executes this file.
55
+ def enable
56
+ @caps[:effective] = @caps[:permitted] + @caps[:inheritable]
57
+ save
58
+ end
59
+
60
+ # Dont enable the permitted capabilities when a proces executes this file.
61
+ def disable
62
+ @caps[:effective].clear
63
+ save
12
64
  end
13
65
 
14
- # Enable the given capability in the file's effective set.
15
- #
16
- # The capability must be either permitted or inheritable (or else it cannot
17
- # possibly be enabled in the new process).
18
- def enable_on_exec(capability)
19
- if permitted?(capability) || inheritable?(capability)
20
- set_effective(capability)
21
- else
22
- raise IncompatibleCapabilities, 'cannot enable_on_exec a capability which is neither permitted nor inheritable'
23
- end
66
+ private
67
+ def reload
68
+ @caps = getcaps
24
69
  end
25
70
  end
26
71
  end
@@ -1,14 +1,56 @@
1
- require 'cap2/set_methods'
2
-
3
1
  module Cap2
4
- # A class with methods for querying capabilities for the
2
+ # A class with methods for managing capabilities for the
5
3
  # process with pid provided to the initialize method.
6
4
  class Process
7
- include SetMethods
8
-
9
5
  # Initialize a new Process object for the given pid.
10
6
  def initialize(pid)
11
- @pid = pid
7
+ @pid = pid
8
+ @caps = getcaps
9
+ end
10
+
11
+ # Returns whether the given capability is permitted
12
+ def permitted?(capability)
13
+ reload
14
+ @caps[:permitted].include? capability
15
+ end
16
+
17
+ # Returns whether the given capability is enabled
18
+ def enabled?(capability)
19
+ reload
20
+ @caps[:effective].include? capability
21
+ end
22
+
23
+ # Returns whether the given capability is inheritable
24
+ def inheritable?(capability)
25
+ reload
26
+ @caps[:inheritable].include? capability
27
+ end
28
+
29
+ # Enable the given capability for this process.
30
+ def enable(capability)
31
+ check_pid
32
+ @caps[:effective].add(capability)
33
+ save
34
+ end
35
+
36
+ # Disable the given capability for this process.
37
+ def disable(capability)
38
+ check_pid
39
+ @caps[:effective].delete(capability)
40
+ save
41
+ end
42
+
43
+ private
44
+ # Raises a RuntimeError if the process's pid is not the same as the current
45
+ # pid (you cannot enable capabilities for other processes, that's their job).
46
+ def check_pid
47
+ unless @pid == Process.pid
48
+ raise 'Cannot modify capabilities of other processes'
49
+ end
50
+ end
51
+
52
+ def reload
53
+ @caps = getcaps
12
54
  end
13
55
  end
14
56
  end
@@ -1,3 +1,3 @@
1
1
  module Cap2
2
- Version = '0.1.1'
2
+ Version = '0.2.0'
3
3
  end
@@ -19,17 +19,17 @@ describe Cap2::File do
19
19
  end
20
20
  end
21
21
 
22
- describe '#effective?' do
23
- context "when the file doesn't have the given capability" do
24
- it { should_not be_effective(:dac_override) }
22
+ describe '#enabled?' do
23
+ context "when the file's enabled bit is not set" do
24
+ it { should_not be_enabled }
25
25
  end
26
26
 
27
- context 'when the file does have the given capability' do
27
+ context "when the file's enabled bit is set" do
28
28
  before(:each) do
29
- run_as_root('permit(:dac_override)', 'enable_on_exec(:dac_override)')
29
+ run_as_root('permit(:dac_override)', 'enable')
30
30
  end
31
31
 
32
- it { should be_effective(:dac_override) }
32
+ it { should be_enabled }
33
33
  end
34
34
  end
35
35
 
@@ -83,48 +83,49 @@ describe Cap2::File do
83
83
  end
84
84
  end
85
85
 
86
- describe '#enable_on_exec' do
87
- context 'when the capability is not permitted or inheritable' do
88
- specify do
89
- expect { subject.enable_on_exec(:lease) }.to \
90
- raise_error(
91
- Cap2::IncompatibleCapabilities,
92
- 'cannot enable_on_exec a capability which is neither permitted nor inheritable'
93
- )
94
- end
95
- end
96
-
97
- context 'when the capability is permitted' do
86
+ context 'enabling and disabling' do
87
+ context 'when at least one capability is permitted' do
98
88
  before(:each) do
99
- run_as_root('permit(:lease)')
89
+ run_as_root('permit(:kill)')
100
90
  end
101
91
 
102
- specify do
103
- expect { running_as_root('enable_on_exec(:lease)') }.to \
104
- change { subject.effective?(:lease) }.from(false).to(true)
92
+ describe '#enable' do
93
+ specify do
94
+ expect { running_as_root('enable') }.to \
95
+ change { subject.enabled? }.from(false).to(true)
96
+ end
105
97
  end
106
- end
107
98
 
108
- context 'when the capability is inheritable' do
109
- before(:each) do
110
- run_as_root('allow_inherit(:lease)')
111
- end
99
+ describe '#disable' do
100
+ before(:each) do
101
+ run_as_root('enable')
102
+ end
112
103
 
113
- specify do
114
- expect { running_as_root('enable_on_exec(:lease)') }.to \
115
- change { subject.effective?(:lease) }.from(false).to(true)
104
+ specify do
105
+ expect { running_as_root('disable') }.to \
106
+ change { subject.enabled? }.from(true).to(false)
107
+ end
116
108
  end
117
109
  end
118
- end
119
110
 
120
- describe '#disable_on_exec' do
121
- before(:each) do
122
- run_as_root('permit(:kill)', 'enable_on_exec(:kill)')
123
- end
111
+ context 'when no capabilities are permitted or inheritable' do
112
+ describe '#enable' do
113
+ specify do
114
+ expect { running_as_root('enable') }.to_not \
115
+ change { subject.enabled? }.from(false)
116
+ end
117
+ end
124
118
 
125
- specify do
126
- expect { running_as_root('disable_on_exec(:kill)') }.to \
127
- change { subject.effective?(:kill) }.from(true).to(false)
119
+ describe '#disable' do
120
+ before(:each) do
121
+ run_as_root('enable')
122
+ end
123
+
124
+ specify do
125
+ expect { running_as_root('disable') }.to_not \
126
+ change { subject.enabled? }.from(false)
127
+ end
128
+ end
128
129
  end
129
130
  end
130
131
 
@@ -15,17 +15,17 @@ describe Cap2::Process do
15
15
  end
16
16
  end
17
17
 
18
- describe '#effective?' do
18
+ describe '#enabled?' do
19
19
  context "when the process doesn't have the given capability" do
20
20
  subject { Cap2::Process.new(Process.pid) }
21
21
 
22
- it { should_not be_effective(:dac_override) }
22
+ it { should_not be_enabled(:dac_override) }
23
23
  end
24
24
 
25
25
  context 'when the process does have the given capability' do
26
26
  subject { Cap2::Process.new(1) }
27
27
 
28
- it { should be_effective(:dac_override) }
28
+ it { should be_enabled(:dac_override) }
29
29
  end
30
30
  end
31
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cap2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-02 00:00:00.000000000 Z
12
+ date: 2012-09-07 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! " Cap2 is a Ruby library for managing the POSIX 1003.1e capabilities\n
15
15
  \ available in Linux kernels.\n\n These capabilities are a partitioning of
@@ -32,7 +32,6 @@ files:
32
32
  - lib/cap2/process.rb
33
33
  - lib/cap2/version.rb
34
34
  - lib/cap2/file.rb
35
- - lib/cap2/set_methods.rb
36
35
  - lib/cap2.so
37
36
  - spec/process_spec.rb
38
37
  - spec/cap2_spec.rb
@@ -1,26 +0,0 @@
1
- module Cap2
2
- # A mixin for the Cap2::Process and Cap2::File
3
- # classes providing convenience methods for querying
4
- # permitted, effective and inheritable capabilities.
5
- #
6
- # Each method takes a capability argument, a lower
7
- # cased name of a capability, without the 'CAP_' prefix.
8
- # For example, :chown would query the CAP_CHOWN capability.
9
- module SetMethods
10
- # Returns whether the given capability is permitted
11
- def permitted?(capability)
12
- has?(:permitted, capability)
13
- end
14
-
15
- # Returns whether the given capability is effective
16
- def effective?(capability)
17
- has?(:effective, capability)
18
- end
19
-
20
- # Returns whether the given capability is inheritable
21
- def inheritable?(capability)
22
- has?(:inheritable, capability)
23
- end
24
- end
25
- end
26
-