sudo 0.1.1 → 0.3.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +19 -0
- data/LICENSE +22 -0
- data/README.md +107 -0
- data/lib/sudo/constants.rb +13 -6
- data/lib/sudo/proxy.rb +15 -3
- data/lib/sudo/support/kernel.rb +9 -17
- data/lib/sudo/support/process.rb +4 -6
- data/lib/sudo/system.rb +9 -11
- data/lib/sudo/wrapper.rb +65 -40
- metadata +83 -40
- data/MANIFEST +0 -17
- data/README.rdoc +0 -119
- data/examples/block.rb +0 -18
- data/examples/dsl.rb +0 -14
- data/examples/lib/writable_root.rb +0 -7
- data/examples/new.rb +0 -28
- data/examples/writable_root.rb +0 -52
- data/lib/sudo/dsl.rb +0 -27
- data/lib/sudo/support/object.rb +0 -5
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8533dcc019e5bf40c31a3a2f0d00fb1ed7799710fbd623e1f35bdc7b3854f8ad
|
4
|
+
data.tar.gz: d21c8cc10c30840bdcd0d6a9c86816ea8123897305c5e4b41b6503301c39e8f6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 53a797c78535d39c6fd4c123726345cc6ad4a73617f8e835437ab49c86168dbfd83696776ea7c2a1fdb26419e88f9cb6799bf33365447ff42c2a023015c0fc48
|
7
|
+
data.tar.gz: e81deabf36e8a0a4a4bad76e8d94560c0518e25deb8f8dac7184dcbb9befee866f704a2f17716dafc773ad0427329120c7ca88562fb82af21e061234681c5114
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Sudo
|
2
|
+
|
3
|
+
## 0.3.0 _(July 04, 2023)_
|
4
|
+
- Works on ruby 3.2
|
5
|
+
|
6
|
+
## 0.2.0 _(November 05, 2018)_
|
7
|
+
- Modernized
|
8
|
+
- Tests
|
9
|
+
- Works on ruby 2.3 - 2.5
|
10
|
+
- More robust dependency loading
|
11
|
+
|
12
|
+
## 0.0.3 _(October 25, 2010)_
|
13
|
+
-
|
14
|
+
|
15
|
+
## 0.0.2 _(October 22, 2010)_
|
16
|
+
-
|
17
|
+
|
18
|
+
## 0.0.1 _(October 22, 2010)_
|
19
|
+
-
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2010-2023 Guido De Rosa
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
[](https://badge.fury.io/rb/sudo)[](https://travis-ci.com/gderosa/rubysu)
|
2
|
+
[](https://codeclimate.com/github/gderosa/rubysu/maintainability)
|
3
|
+
[](https://codeclimate.com/github/gderosa/rubysu/test_coverage)
|
4
|
+
|
5
|
+
# Ruby Sudo
|
6
|
+
|
7
|
+
Give Ruby objects superuser privileges.
|
8
|
+
|
9
|
+
Based on [dRuby](http://ruby-doc.org/stdlib-2.5.3/libdoc/drb/rdoc/DRb.html) and [sudo](http://www.sudo.ws/).
|
10
|
+
|
11
|
+
Only tested with [MRI](http://en.wikipedia.org/wiki/Ruby_MRI).
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Your user must be allowed, in `/etc/sudoers`, to run `ruby` and `kill`
|
16
|
+
commands as root.
|
17
|
+
|
18
|
+
A password may be required from the console, depending on the
|
19
|
+
`NOPASSWD` options in `/etc/sudoers`.
|
20
|
+
|
21
|
+
Spawns a sudo-ed Ruby process running a
|
22
|
+
[DRb](http://ruby-doc.org/stdlib-2.5.3/libdoc/drb/rdoc/DRb.html) server. Communication is
|
23
|
+
done via a Unix socket (and, of course, permissions are set to `0600`).
|
24
|
+
|
25
|
+
No long-running daemons involved, everything is created on demand.
|
26
|
+
|
27
|
+
Access control is entirely delegated to `sudo`.
|
28
|
+
|
29
|
+
### Application Code
|
30
|
+
|
31
|
+
Let's start with a trivial example:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require 'my_gem/my_class'
|
35
|
+
require 'sudo'
|
36
|
+
|
37
|
+
obj = MyGem::MyClass.new
|
38
|
+
|
39
|
+
# Now, create a Sudo::Wrapper object:
|
40
|
+
sudo = Sudo::Wrapper.new
|
41
|
+
|
42
|
+
# 'mygem/myclass' will be automatically required in the
|
43
|
+
# sudo DRb server
|
44
|
+
|
45
|
+
# Start the sudo-ed Ruby process:
|
46
|
+
sudo.start!
|
47
|
+
sudo[obj].my_instance_method
|
48
|
+
sudo[MyClass].my_class_method
|
49
|
+
|
50
|
+
# Call stop! when finished, otherwise, that will be done
|
51
|
+
# when the `sudo` object gets garbage-collected.
|
52
|
+
sudo.stop!
|
53
|
+
```
|
54
|
+
|
55
|
+
A convienient utility for working with sudo is to use the `run` method and pass it a block.
|
56
|
+
Run will automatically start and stop the ruby sudo process around the block.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
require 'fileutils'
|
60
|
+
require 'sudo'
|
61
|
+
|
62
|
+
Sudo::Wrapper.run do |sudo|
|
63
|
+
sudo[FileUtils].mkdir_p '/ONLY/ROOT/CAN/DO/THAT'
|
64
|
+
end
|
65
|
+
# Sockets and processes are closed automatically when the block exits
|
66
|
+
```
|
67
|
+
|
68
|
+
Both `Sudo::Wrapper.run` and `Sudo::Wrapper.new` take the same named arguments: `ruby_opts` (default: `''` ) and `load_gems` (default: `true`).
|
69
|
+
|
70
|
+
If you'd like to pass options to the sudo-spawned ruby process, pass them as a string to `ruby_opts`.
|
71
|
+
|
72
|
+
If you'd like to prevent the loading of `gems` currently loaded from the calling program, pass `false` to `load_gems`. This will give your sudo process a unmodifed environment. The only things required via the sudo process are `'drb/drb'`, `'fileutils'`, and of course `'sudo'`.
|
73
|
+
|
74
|
+
## Todo
|
75
|
+
|
76
|
+
`sudo` has a `-A` option to accept password via an external program (maybe
|
77
|
+
graphical): support this feature.
|
78
|
+
|
79
|
+
## Credits
|
80
|
+
|
81
|
+
### Author and Copyright
|
82
|
+
|
83
|
+
Guido De Rosa ([@gderosa](http://github.com/gderosa/)).
|
84
|
+
|
85
|
+
See LICENSE.
|
86
|
+
|
87
|
+
### Contributors
|
88
|
+
|
89
|
+
Dale Stevens ([@voltechs](https://github.com/voltechs))
|
90
|
+
|
91
|
+
Robert M. Koch ([@threadmetal](https://github.com/threadmetal))
|
92
|
+
|
93
|
+
Wolfgang Teuber ([@wteuber](https://github.com/wteuber))
|
94
|
+
|
95
|
+
### Other aknowledgements
|
96
|
+
Thanks to Tony Arcieri and Brian Candler for suggestions on
|
97
|
+
[ruby-talk](http://www.ruby-forum.com/topic/262655).
|
98
|
+
|
99
|
+
Initially developed by G. D. while working at [@vemarsas](https://github.com/vemarsas).
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
1. Fork it ( https://github.com/gderosa/rubysu/fork )
|
104
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
105
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
106
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
107
|
+
5. Create a new Pull Request
|
data/lib/sudo/constants.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
1
3
|
module Sudo
|
2
4
|
|
3
|
-
VERSION = '0.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
VERSION = '0.3.0'
|
6
|
+
|
7
|
+
def self.root
|
8
|
+
@root ||= Pathname.new(File.expand_path('../../', __dir__))
|
9
|
+
end
|
10
|
+
|
11
|
+
LIBDIR = root.join('lib')
|
12
|
+
SERVER_SCRIPT = root.join('libexec/server.rb')
|
13
|
+
SUDO_CMD = `which sudo`.chomp
|
14
|
+
RUBY_CMD = `which ruby`.chomp
|
8
15
|
|
9
|
-
|
16
|
+
RuntimeError = Class.new(RuntimeError)
|
10
17
|
|
11
18
|
end
|
data/lib/sudo/proxy.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'sudo/support/object'
|
2
1
|
|
3
2
|
module Sudo
|
4
3
|
|
@@ -7,15 +6,28 @@ module Sudo
|
|
7
6
|
@object = object
|
8
7
|
@proxy = proxy
|
9
8
|
end
|
10
|
-
def method_missing(method=:
|
9
|
+
def method_missing(method=:itself, *args, &blk)
|
11
10
|
@proxy.proxy @object, method, *args, &blk
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
class Proxy
|
16
|
-
def proxy(object, method=:
|
15
|
+
def proxy(object, method=:itself, *args, &blk)
|
17
16
|
object.send method, *args, &blk
|
18
17
|
end
|
18
|
+
|
19
|
+
def loaded_specs
|
20
|
+
# Something's weird with this method when called outside
|
21
|
+
Gem.loaded_specs.to_a.to_h
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_path
|
25
|
+
$LOAD_PATH
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_load_path(path)
|
29
|
+
$LOAD_PATH << path
|
30
|
+
end
|
19
31
|
end
|
20
32
|
|
21
33
|
end
|
data/lib/sudo/support/kernel.rb
CHANGED
@@ -1,20 +1,12 @@
|
|
1
|
-
|
2
|
-
def wait_for(conf)
|
3
|
-
start = Time.now
|
4
|
-
defaults = {
|
5
|
-
:timeout => nil,
|
6
|
-
:step => 0.125
|
7
|
-
}
|
8
|
-
conf = defaults.update conf
|
9
|
-
condition = false
|
10
|
-
loop do
|
11
|
-
condition = yield
|
1
|
+
require 'timeout'
|
12
2
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
3
|
+
module Kernel
|
4
|
+
def wait_for(timeout: nil, step: 0.125)
|
5
|
+
Timeout::timeout(timeout) do
|
6
|
+
condition = false
|
7
|
+
sleep(step) until (condition = yield) and return condition
|
17
8
|
end
|
18
|
-
|
19
|
-
|
9
|
+
rescue Timeout::Error
|
10
|
+
return false
|
11
|
+
end
|
20
12
|
end
|
data/lib/sudo/support/process.rb
CHANGED
@@ -3,12 +3,10 @@ module Process
|
|
3
3
|
# Thanks to:
|
4
4
|
# http://stackoverflow.com/questions/141162/how-can-i-determine-if-a-different-process-id-is-running-using-java-or-jruby-on-l
|
5
5
|
def exists?(pid)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
false
|
11
|
-
end
|
6
|
+
Process.getpgid( pid )
|
7
|
+
true
|
8
|
+
rescue Errno::ESRCH
|
9
|
+
false
|
12
10
|
end
|
13
11
|
end
|
14
12
|
end
|
data/lib/sudo/system.rb
CHANGED
@@ -4,31 +4,29 @@ require 'sudo/constants'
|
|
4
4
|
module Sudo
|
5
5
|
module System
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
ProcessStillExists = Class.new(RuntimeError)
|
8
|
+
FileStillExists = Class.new(RuntimeError)
|
9
9
|
|
10
10
|
class << self
|
11
11
|
|
12
12
|
def kill(pid)
|
13
13
|
if pid and Process.exists? pid
|
14
|
-
system "sudo kill #{pid}"
|
15
|
-
system "sudo kill -9 #{pid}"
|
16
|
-
raise ProcessStillExists,
|
17
|
-
"Couldn't kill sudo process (PID=#{pid})"
|
14
|
+
system "sudo kill #{pid}" or
|
15
|
+
system "sudo kill -9 #{pid}" or
|
16
|
+
raise ProcessStillExists, "Couldn't kill sudo process (PID=#{pid})"
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
20
|
def unlink(file)
|
22
|
-
if file and File.
|
23
|
-
system
|
24
|
-
raise
|
25
|
-
"Couldn't delete #{file}"
|
21
|
+
if file and File.exist? file
|
22
|
+
system("sudo rm -f #{file}") or
|
23
|
+
raise(FileStillExists, "Couldn't delete #{file}")
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
27
|
# just to check if we can sudo; and we'll receive a sudo token
|
30
28
|
def check
|
31
|
-
raise SudoFailed unless system "
|
29
|
+
raise SudoFailed unless system "#{SUDO_CMD} -E #{RUBY_CMD} -e ''"
|
32
30
|
end
|
33
31
|
|
34
32
|
end
|
data/lib/sudo/wrapper.rb
CHANGED
@@ -6,17 +6,18 @@ require 'sudo/system'
|
|
6
6
|
require 'sudo/proxy'
|
7
7
|
|
8
8
|
module Sudo
|
9
|
+
|
9
10
|
class Wrapper
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
RuntimeError = Class.new(RuntimeError)
|
13
|
+
NotRunning = Class.new(RuntimeError)
|
14
|
+
SudoFailed = Class.new(RuntimeError)
|
15
|
+
SudoProcessExists = Class.new(RuntimeError)
|
16
|
+
SudoProcessAlreadyExists = Class.new(SudoProcessExists)
|
17
|
+
NoValidSocket = Class.new(RuntimeError)
|
18
|
+
SocketNotFound = Class.new(NoValidSocket)
|
19
|
+
NoValidSudoPid = Class.new(RuntimeError)
|
20
|
+
SudoProcessNotFound = Class.new(NoValidSudoPid)
|
20
21
|
|
21
22
|
class << self
|
22
23
|
|
@@ -24,11 +25,13 @@ module Sudo
|
|
24
25
|
# cleanup when the block exits.
|
25
26
|
#
|
26
27
|
# ruby_opts:: is passed to Sudo::Wrapper::new .
|
27
|
-
def run(ruby_opts
|
28
|
-
sudo = new(ruby_opts).start!
|
29
|
-
|
28
|
+
def run(ruby_opts: '', load_gems: true) # :yields: sudo
|
29
|
+
sudo = new(ruby_opts: ruby_opts, load_gems: load_gems).start!
|
30
|
+
yield sudo
|
31
|
+
rescue Exception => e # Bubble all exceptions...
|
32
|
+
raise e
|
33
|
+
ensure # and ensure sudo stops
|
30
34
|
sudo.stop!
|
31
|
-
retval
|
32
35
|
end
|
33
36
|
|
34
37
|
# Do the actual resources clean-up.
|
@@ -45,13 +48,12 @@ module Sudo
|
|
45
48
|
# +ruby_opts+ are the command line options to the sudo ruby interpreter;
|
46
49
|
# usually you don't need to specify stuff like "-rmygem/mylib", libraries
|
47
50
|
# will be sorta "inherited".
|
48
|
-
def initialize(ruby_opts
|
51
|
+
def initialize(ruby_opts: '', load_gems: true)
|
49
52
|
@proxy = nil
|
50
53
|
@socket = "/tmp/rubysu-#{Process.pid}-#{object_id}"
|
51
54
|
@sudo_pid = nil
|
52
55
|
@ruby_opts = ruby_opts
|
53
|
-
@
|
54
|
-
# @load_path = [] # currentl unused
|
56
|
+
@load_gems = load_gems == true
|
55
57
|
end
|
56
58
|
|
57
59
|
def server_uri; "drbunix:#{@socket}"; end
|
@@ -61,43 +63,27 @@ module Sudo
|
|
61
63
|
Sudo::System.check
|
62
64
|
|
63
65
|
@sudo_pid = spawn(
|
64
|
-
"#{SUDO_CMD}
|
66
|
+
"#{SUDO_CMD} -E #{RUBY_CMD} -I#{LIBDIR} #{@ruby_opts} #{SERVER_SCRIPT} #{@socket} #{Process.uid}"
|
65
67
|
)
|
66
68
|
Process.detach(@sudo_pid) if @sudo_pid # avoid zombies
|
67
|
-
|
68
|
-
|
69
|
-
)
|
69
|
+
finalizer = Finalizer.new(pid: @sudo_pid, socket: @socket)
|
70
|
+
ObjectSpace.define_finalizer(self, finalizer)
|
70
71
|
|
71
|
-
if wait_for(:
|
72
|
+
if wait_for(timeout: 1){File.exist? @socket}
|
72
73
|
@proxy = DRbObject.new_with_uri(server_uri)
|
73
74
|
else
|
74
75
|
raise RuntimeError, "Couldn't create DRb socket #{@socket}"
|
75
76
|
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
load_features
|
78
|
+
load!
|
80
79
|
|
81
80
|
self
|
82
81
|
end
|
83
82
|
|
84
|
-
# Load needed libraries in the DRb server. Usually you don't need
|
85
|
-
# to call this directly.
|
86
|
-
def load_features
|
87
|
-
unless $LOADED_FEATURES == @loaded_features
|
88
|
-
new_features = $LOADED_FEATURES - @loaded_features
|
89
|
-
new_features.each do |feature|
|
90
|
-
@proxy.proxy Kernel, :require, feature
|
91
|
-
@loaded_features << feature
|
92
|
-
end
|
93
|
-
#@loaded_features += new_features
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
83
|
def running?
|
98
84
|
true if (
|
99
85
|
@sudo_pid and Process.exists? @sudo_pid and
|
100
|
-
@socket and File.
|
86
|
+
@socket and File.exist? @socket and
|
101
87
|
@proxy
|
102
88
|
)
|
103
89
|
end
|
@@ -106,14 +92,14 @@ module Sudo
|
|
106
92
|
# ruby process and the Unix-domain socket used to communicate
|
107
93
|
# to it via ::DRb.
|
108
94
|
def stop!
|
109
|
-
self.class.cleanup!(:
|
95
|
+
self.class.cleanup!(pid: @sudo_pid, socket: @socket)
|
110
96
|
@proxy = nil
|
111
97
|
end
|
112
98
|
|
113
99
|
# Gives a copy of +object+ with root privileges.
|
114
100
|
def [](object)
|
115
101
|
if running?
|
116
|
-
|
102
|
+
load!
|
117
103
|
MethodProxy.new object, @proxy
|
118
104
|
else
|
119
105
|
raise NotRunning
|
@@ -133,5 +119,44 @@ module Sudo
|
|
133
119
|
end
|
134
120
|
end
|
135
121
|
|
122
|
+
protected
|
123
|
+
|
124
|
+
def load!
|
125
|
+
load_gems if load_gems?
|
126
|
+
end
|
127
|
+
|
128
|
+
def load_gems?
|
129
|
+
@load_gems == true
|
130
|
+
end
|
131
|
+
|
132
|
+
def prospective_gems
|
133
|
+
(Gem.loaded_specs.keys - @proxy.loaded_specs.keys)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Load needed libraries in the DRb server. Usually you don't need
|
137
|
+
def load_gems
|
138
|
+
load_paths
|
139
|
+
prospective_gems.each do |prospect|
|
140
|
+
gem_name = prospect.dup
|
141
|
+
begin
|
142
|
+
loaded = @proxy.proxy(Kernel, :require, gem_name)
|
143
|
+
# puts "Loading Gem: #{gem_name} => #{loaded}"
|
144
|
+
rescue LoadError, NameError => e
|
145
|
+
old_gem_name = gem_name.dup
|
146
|
+
gem_name.gsub!('-', '/')
|
147
|
+
retry if old_gem_name != gem_name
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def load_paths
|
153
|
+
host_paths = $LOAD_PATH
|
154
|
+
proxy_paths = @proxy.load_path
|
155
|
+
diff_paths = host_paths - proxy_paths
|
156
|
+
diff_paths.each do |path|
|
157
|
+
@proxy.add_load_path(path)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
136
161
|
end
|
137
162
|
end
|
metadata
CHANGED
@@ -1,70 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sudo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Guido De Rosa
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
date: 2023-07-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry-byebug
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '12.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |
|
70
|
+
Give Ruby objects superuser privileges.
|
17
71
|
Based on dRuby and sudo (the Unix program).
|
18
|
-
|
19
|
-
|
20
|
-
email: guido.derosa@vemarsas.it
|
72
|
+
email:
|
73
|
+
- guidoderosa@gmail.com
|
21
74
|
executables: []
|
22
75
|
extensions: []
|
23
|
-
extra_rdoc_files:
|
24
|
-
- README.rdoc
|
76
|
+
extra_rdoc_files: []
|
25
77
|
files:
|
26
|
-
-
|
27
|
-
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
- examples/lib/writable_root.rb
|
31
|
-
- libexec/server.rb
|
78
|
+
- CHANGELOG.md
|
79
|
+
- LICENSE
|
80
|
+
- README.md
|
81
|
+
- lib/sudo.rb
|
32
82
|
- lib/sudo/constants.rb
|
33
|
-
- lib/sudo/dsl.rb
|
34
83
|
- lib/sudo/proxy.rb
|
35
|
-
- lib/sudo.rb
|
36
84
|
- lib/sudo/support/kernel.rb
|
37
|
-
- lib/sudo/support/object.rb
|
38
85
|
- lib/sudo/support/process.rb
|
39
86
|
- lib/sudo/system.rb
|
40
87
|
- lib/sudo/wrapper.rb
|
41
|
-
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
- README.rdoc
|
88
|
+
- libexec/server.rb
|
89
|
+
homepage: https://github.com/TwilightCoders/rubysu
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata:
|
93
|
+
allowed_push_host: https://rubygems.org
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
50
96
|
require_paths:
|
51
97
|
- lib
|
52
98
|
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
99
|
requirements:
|
55
|
-
- -
|
100
|
+
- - ">="
|
56
101
|
- !ruby/object:Gem::Version
|
57
|
-
version: '
|
102
|
+
version: '2.3'
|
58
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
104
|
requirements:
|
61
|
-
- -
|
105
|
+
- - ">="
|
62
106
|
- !ruby/object:Gem::Version
|
63
107
|
version: '0'
|
64
108
|
requirements: []
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
specification_version: 3
|
109
|
+
rubygems_version: 3.1.6
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
69
112
|
summary: Give Ruby objects superuser privileges
|
70
113
|
test_files: []
|
data/MANIFEST
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
examples/block.rb
|
2
|
-
examples/dsl.rb
|
3
|
-
examples/new.rb
|
4
|
-
examples/writable_root.rb
|
5
|
-
examples/lib/writable_root.rb
|
6
|
-
libexec/server.rb
|
7
|
-
lib/sudo/constants.rb
|
8
|
-
lib/sudo/dsl.rb
|
9
|
-
lib/sudo/proxy.rb
|
10
|
-
lib/sudo.rb
|
11
|
-
lib/sudo/support/kernel.rb
|
12
|
-
lib/sudo/support/object.rb
|
13
|
-
lib/sudo/support/process.rb
|
14
|
-
lib/sudo/system.rb
|
15
|
-
lib/sudo/wrapper.rb
|
16
|
-
MANIFEST
|
17
|
-
README.rdoc
|
data/README.rdoc
DELETED
@@ -1,119 +0,0 @@
|
|
1
|
-
= Ruby \Sudo
|
2
|
-
|
3
|
-
Give Ruby objects superuser privileges.
|
4
|
-
|
5
|
-
Based on dRuby[http://ruby-doc.org/ruby-1.9/classes/DRb.html] and
|
6
|
-
sudo[http://www.sudo.ws/].
|
7
|
-
|
8
|
-
Only tested with {MRI 1.9}[http://en.wikipedia.org/wiki/Ruby_MRI] .
|
9
|
-
|
10
|
-
== REQUIREMENTS
|
11
|
-
|
12
|
-
Your user must be allowed, in +/etc/sudoers+, to run +ruby+ and +kill+
|
13
|
-
commands as root.
|
14
|
-
|
15
|
-
A password will be required from the console, or not, depending on
|
16
|
-
the +NOPASSWD+ options in +/etc/sudoers+.
|
17
|
-
|
18
|
-
== USAGE
|
19
|
-
|
20
|
-
Let's start with a trivial example:
|
21
|
-
|
22
|
-
require 'mygem/myclass'
|
23
|
-
require 'sudo'
|
24
|
-
|
25
|
-
obj = MyGem::MyClass.new
|
26
|
-
|
27
|
-
|
28
|
-
Now, create a Sudo::Wrapper object:
|
29
|
-
|
30
|
-
sudo = Sudo::Wrapper.new
|
31
|
-
|
32
|
-
|
33
|
-
Start the sudo-ed Ruby process:
|
34
|
-
|
35
|
-
# 'mygem/myclass' will be automatically required in the
|
36
|
-
# sudo DRb server
|
37
|
-
|
38
|
-
sudo.start!
|
39
|
-
|
40
|
-
|
41
|
-
Use it!
|
42
|
-
|
43
|
-
sudo[obj].my_instance_method
|
44
|
-
sudo[MyClass].my_class_method
|
45
|
-
|
46
|
-
|
47
|
-
When you've done, +stop!+ it. Otherwise, that will be done (only) when
|
48
|
-
the +sudo+ object gets garbage-collected.
|
49
|
-
|
50
|
-
sudo.stop!
|
51
|
-
|
52
|
-
=== With a block
|
53
|
-
|
54
|
-
Use Sudo::Wrapper::run in this case.
|
55
|
-
|
56
|
-
require 'fileutils'
|
57
|
-
require 'sudo'
|
58
|
-
|
59
|
-
Sudo::Wrapper.run do |sudo|
|
60
|
-
sudo[FileUtils].mkdir_p '/ONLY/ROOT/CAN/DO/THAT'
|
61
|
-
end
|
62
|
-
# Sockets and processes are closed automatically when the block exits
|
63
|
-
|
64
|
-
== PRINCIPLES OF OPERATION
|
65
|
-
|
66
|
-
Spawns a sudo-ed Ruby process running a
|
67
|
-
DRb[http://ruby-doc.org/ruby-1.9/classes/DRb.html] server. Communication is
|
68
|
-
done via a Unix socket (and, of course, permissions are set to +0600+).
|
69
|
-
|
70
|
-
No long-running daemons involved, everything is created on demand.
|
71
|
-
|
72
|
-
Access control is entirely delegated to +sudo+.
|
73
|
-
|
74
|
-
== TODO
|
75
|
-
|
76
|
-
+sudo+ has a +-A+ option to accept password via an external program
|
77
|
-
(maybe graphical): support this feature.
|
78
|
-
|
79
|
-
== CREDITS
|
80
|
-
|
81
|
-
=== AUTHOR
|
82
|
-
|
83
|
-
{Guido De Rosa}[http://github.com/gderosa/].
|
84
|
-
|
85
|
-
Sponsored by {VEMAR s.a.s.}[http://www.vemarsas.it/]
|
86
|
-
|
87
|
-
=== CONTRIBUTORS
|
88
|
-
|
89
|
-
{Robert M. Koch}[http://github.com/threadmetal/].
|
90
|
-
|
91
|
-
=== THANKS
|
92
|
-
|
93
|
-
Thanks to Tony Arcieri and Brian Candler for suggestions on
|
94
|
-
ruby-talk[http://www.ruby-forum.com/topic/262655].
|
95
|
-
|
96
|
-
=== COPYRIGHT
|
97
|
-
|
98
|
-
(The MIT License)
|
99
|
-
|
100
|
-
Copyright (c) 2010, 2011, 2012, 2013 Guido De Rosa
|
101
|
-
|
102
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
103
|
-
a copy of this software and associated documentation files (the
|
104
|
-
'Software'), to deal in the Software without restriction, including
|
105
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
106
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
107
|
-
permit persons to whom the Software is furnished to do so, subject to
|
108
|
-
the following conditions:
|
109
|
-
|
110
|
-
The above copyright notice and this permission notice shall be
|
111
|
-
included in all copies or substantial portions of the Software.
|
112
|
-
|
113
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
114
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
115
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
116
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
117
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
118
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
119
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/examples/block.rb
DELETED
data/examples/dsl.rb
DELETED
data/examples/new.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
autoload :IPAddr, 'ipaddr'
|
3
|
-
require 'sudo'
|
4
|
-
|
5
|
-
# Requires and autoloads are inherited by the sudo process.
|
6
|
-
|
7
|
-
su = Sudo::Wrapper.new
|
8
|
-
|
9
|
-
su.start!
|
10
|
-
|
11
|
-
su[File].open '/TEST', 'w' do |f|
|
12
|
-
f.puts "Hello from UID=#{su[Process].uid}!"
|
13
|
-
f.puts "#{su[IPAddr].new}"
|
14
|
-
end
|
15
|
-
|
16
|
-
su[FileUtils].cp '/etc/shadow', '/etc/shadow2'
|
17
|
-
|
18
|
-
# If you don't call stop! explicitly, the corresponding process and file
|
19
|
-
# cleanup will be done when su gets garbage-collected.
|
20
|
-
#
|
21
|
-
su.stop!
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
data/examples/writable_root.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'sudo'
|
2
|
-
|
3
|
-
|
4
|
-
t0 = Time.now
|
5
|
-
su = Sudo::Wrapper.new.start!
|
6
|
-
t1 = Time.now
|
7
|
-
|
8
|
-
writable_root = su[File].writable? '/'
|
9
|
-
t2 = Time.now
|
10
|
-
writable_root_by_normal_user = File.writable? '/'
|
11
|
-
|
12
|
-
puts
|
13
|
-
puts "writable_root = #{writable_root}"
|
14
|
-
puts "writable_root_by_normal_user = #{writable_root_by_normal_user}"
|
15
|
-
puts "Starting Sudo::Wrapper object took #{t1-t0} seconds"
|
16
|
-
puts "Using it, as in su[File].writable? '/', took #{t2-t1} seconds"
|
17
|
-
|
18
|
-
puts
|
19
|
-
puts "Now trying on an instance of WritableRoot custom class:"
|
20
|
-
|
21
|
-
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
|
22
|
-
require 'writable_root'
|
23
|
-
|
24
|
-
wr1 = WritableRoot.new
|
25
|
-
wr2 = WritableRoot.new
|
26
|
-
|
27
|
-
wr1.check
|
28
|
-
su[wr2].check
|
29
|
-
|
30
|
-
puts
|
31
|
-
puts "Hit ENTER to stop the Sudo::Wrapper object"
|
32
|
-
puts "(in the meantime, you can look at the ruby sudo-ed process with ps)"
|
33
|
-
gets
|
34
|
-
|
35
|
-
# Optional (it will be stopped automatically as soon as 'su' object gets out of scope).
|
36
|
-
su.stop!
|
37
|
-
|
38
|
-
puts "Now trying with a block (Sudo::Wrapper.run):"
|
39
|
-
writable_root = Sudo::Wrapper.run do |sudo|
|
40
|
-
print "As uid=#{ sudo[Process].uid }, "
|
41
|
-
sudo[File].writable? '/'
|
42
|
-
end
|
43
|
-
puts "writable_root = #{writable_root.inspect}"
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
data/lib/sudo/dsl.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
DEPRECATED
|
3
|
-
|
4
|
-
It's not clear what the scope of __default_sudo_wrapper should be:
|
5
|
-
local, instance, class? global? and what about thread-safety?
|
6
|
-
|
7
|
-
=end
|
8
|
-
|
9
|
-
=begin
|
10
|
-
require 'sudo/wrapper'
|
11
|
-
|
12
|
-
module Sudo
|
13
|
-
|
14
|
-
module DSL
|
15
|
-
def sudo_start(*args, &blk)
|
16
|
-
@__default_sudo_wrapper = Sudo::Wrapper.new(*args, &blk).start!
|
17
|
-
end
|
18
|
-
def sudo_stop
|
19
|
-
@__default_sudo_wrapper.stop!
|
20
|
-
end
|
21
|
-
def sudo(object)
|
22
|
-
@__default_sudo_wrapper[object]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
=end
|