processwanker 0.0.7

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.
@@ -0,0 +1,167 @@
1
+ ############################################################################
2
+ #
3
+ # net_connection.rb
4
+ #
5
+ # handles the physical TCP/SSL connection between client(s) and daemon(s)
6
+ #
7
+ ############################################################################
8
+
9
+ require 'openssl'
10
+ require 'config'
11
+ require 'thread'
12
+ require 'util'
13
+
14
+ module ProcessWanker
15
+
16
+ ############################################################################
17
+ #
18
+ #
19
+ #
20
+ ############################################################################
21
+
22
+ class NetConnection
23
+ include Log
24
+
25
+ attr_accessor :ssl_connection
26
+ attr_accessor :user
27
+
28
+ ############################################################################
29
+ #
30
+ #
31
+ #
32
+ ############################################################################
33
+
34
+ def initialize(ssl_connection)
35
+ @write_mutex=Mutex.new
36
+ @ssl_connection=ssl_connection
37
+ @read_thread = Thread.new { read_proc }
38
+ @user = ssl_connection.peer_cert.subject.to_a.select { |x| x[0]=="CN" }.map { |x| x[1] }[0]
39
+ end
40
+
41
+ ############################################################################
42
+ #
43
+ #
44
+ #
45
+ ############################################################################
46
+
47
+ def wait
48
+ @read_thread.join
49
+ end
50
+
51
+ ############################################################################
52
+ #
53
+ #
54
+ #
55
+ ############################################################################
56
+
57
+ def send_msg(msg)
58
+
59
+ @write_mutex.synchronize do
60
+ debug("sending message #{msg.inspect}")
61
+ begin
62
+ data=Marshal.dump(msg)
63
+ length=[data.length].pack("N")
64
+ @ssl_connection.write(length + data)
65
+ rescue Exception => e
66
+ on_close()
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ ############################################################################
73
+ #
74
+ #
75
+ #
76
+ ############################################################################
77
+
78
+ def close_rudely()
79
+ ProcessWanker::with_logged_rescue("close_rudely",Log::DEBUG) do
80
+ @ssl_connection.io.close()
81
+ end
82
+ disconnect()
83
+ end
84
+
85
+ ############################################################################
86
+ #
87
+ #
88
+ #
89
+ ############################################################################
90
+
91
+ def disconnect()
92
+ on_close()
93
+ if(Thread.current != @read_thread)
94
+ @read_thread.join
95
+ end
96
+ end
97
+
98
+ ############################################################################
99
+ #
100
+ #
101
+ #
102
+ ############################################################################
103
+
104
+ def read_proc
105
+ while(@ssl_connection)
106
+ read_connection()
107
+ end
108
+ end
109
+
110
+ ############################################################################
111
+ #
112
+ #
113
+ #
114
+ ############################################################################
115
+
116
+ def read_connection()
117
+ begin
118
+ length=@ssl_connection.read(4)
119
+ raise "closed" if(length.length != 4)
120
+ length=length.unpack("N")[0]
121
+ data=@ssl_connection.read(length)
122
+ raise "closed" if(data.length != length)
123
+ msg=Marshal.load(data)
124
+ on_msg(msg)
125
+ rescue Exception => e
126
+ on_close()
127
+ end
128
+ end
129
+
130
+ ############################################################################
131
+ #
132
+ #
133
+ #
134
+ ############################################################################
135
+
136
+ def on_close()
137
+ ProcessWanker::with_logged_rescue("on_close",Log::DEBUG) do
138
+ @ssl_connection.close if(@ssl_connection)
139
+ end
140
+ @ssl_connection=nil
141
+ end
142
+
143
+ ############################################################################
144
+ #
145
+ #
146
+ #
147
+ ############################################################################
148
+
149
+ def on_msg(msg)
150
+ # puts msg.inspect
151
+ end
152
+
153
+ ############################################################################
154
+ #
155
+ #
156
+ #
157
+ ############################################################################
158
+
159
+ ############################################################################
160
+ #
161
+ #
162
+ #
163
+ ############################################################################
164
+
165
+ end
166
+
167
+ end
@@ -0,0 +1,232 @@
1
+ ############################################################################
2
+ #
3
+ # net_server.rb
4
+ #
5
+ # accept incoming TLS connections, parse and dispatch requests
6
+ #
7
+ ############################################################################
8
+
9
+ require 'openssl'
10
+ require 'config'
11
+ require 'net_util'
12
+ require 'socket'
13
+ require 'net_server_client'
14
+ require 'thread'
15
+ require 'config_daemon'
16
+
17
+ module ProcessWanker
18
+
19
+ ############################################################################
20
+ #
21
+ #
22
+ #
23
+ ############################################################################
24
+
25
+ class TCPFilteredServer < TCPServer
26
+
27
+ include Log
28
+
29
+ def initialize(hostname,port,auth)
30
+ @auth=auth
31
+ super(hostname,port)
32
+ end
33
+
34
+ def accept()
35
+ while(true)
36
+ con=super()
37
+ debug("got TCP connection from #{con.peeraddr.inspect}")
38
+ return(con) if(validate_auth(con))
39
+ ProcessWanker::with_logged_rescue("accept - reject remote addr") do
40
+ con.close()
41
+ end
42
+ end
43
+ end
44
+
45
+ def validate_auth(con)
46
+
47
+ remote_addr=con.peeraddr[3]
48
+ remote_addr=IPAddr.new(remote_addr)
49
+
50
+ if(!@auth.allow_ip(remote_addr))
51
+ info("reject ip #{remote_addr.inspect}")
52
+ return(false)
53
+ end
54
+
55
+ true
56
+ end
57
+
58
+ end
59
+
60
+ ############################################################################
61
+ #
62
+ #
63
+ #
64
+ ############################################################################
65
+
66
+ class NetServer
67
+
68
+ include Log
69
+
70
+ @@instance=nil
71
+
72
+ ############################################################################
73
+ #
74
+ #
75
+ #
76
+ ############################################################################
77
+
78
+ def initialize(cfg)
79
+
80
+ @@instance=self
81
+ @mutex=Mutex.new
82
+ @clients=[]
83
+
84
+ daemon=cfg.daemon
85
+ auth=daemon.get_auth
86
+ @auth=auth
87
+
88
+ # check that we're not using default certs and listening anything other than
89
+ # localhost.
90
+ if(@auth.is_default)
91
+ if(daemon.listen_hostname != ConfigDaemon::DEFAULT_LISTEN_HOSTNAME)
92
+
93
+ error "***"
94
+ error "*** For security reasons, I will only listen on #{ConfigDaemon::DEFAULT_LISTEN_HOSTNAME} while using"
95
+ error "*** the default built-in SSL certificates. You must generate real"
96
+ error "*** certificates if you wish to control this daemon remotely."
97
+ error "***"
98
+
99
+ daemon.listen_hostname=ConfigDaemon::DEFAULT_LISTEN_HOSTNAME
100
+
101
+ end
102
+ end
103
+
104
+ @ca_cert=auth.ca_cert
105
+ @context=OpenSSL::SSL::SSLContext.new
106
+ @context.cert=auth.my_cert
107
+ @context.key=auth.my_key
108
+ @context.verify_mode=OpenSSL::SSL::VERIFY_PEER
109
+ @context.verify_callback=proc do |preverify_ok,ssl_context|
110
+ verify_peer(preverify_ok,ssl_context)
111
+ end
112
+
113
+ # @tcp_server=TCPServer.new(daemon.listen_hostname,daemon.listen_port)
114
+ @tcp_server=TCPFilteredServer.new(daemon.listen_hostname,daemon.listen_port,auth)
115
+ @ssl_server=OpenSSL::SSL::SSLServer.new(@tcp_server,@context)
116
+
117
+ @server_thread=Thread.new { server_proc }
118
+
119
+ end
120
+
121
+ ############################################################################
122
+ #
123
+ #
124
+ #
125
+ ############################################################################
126
+
127
+ def stop_server()
128
+ @ssl_server.close
129
+ @server_thread.join
130
+ c=@clients.clone
131
+ c.each do |c|
132
+ c.disconnect()
133
+ end
134
+ end
135
+
136
+ ############################################################################
137
+ #
138
+ #
139
+ #
140
+ ############################################################################
141
+
142
+ def verify_peer(preverify_ok,ssl_context)
143
+ if(!ssl_context.current_cert.verify(@ca_cert.public_key))
144
+ info("client certificate rejected")
145
+ return(false)
146
+ end
147
+ peer_name=ssl_context.current_cert.subject.to_a.select { |x| x[0]=="CN" }.map { |x| x[1] }[0]
148
+ info("verified identity of #{peer_name}")
149
+
150
+ if(@auth.accept_peers && !@auth.accept_peers[peer_name])
151
+ info("failed to accept peer #{peer_name}")
152
+ return(false)
153
+ end
154
+ if(@auth.reject_peers && @auth.reject_peers[peer_name])
155
+ info("rejected peer #{peer_name}")
156
+ return(false)
157
+ end
158
+
159
+ true
160
+ end
161
+
162
+ ############################################################################
163
+ #
164
+ #
165
+ #
166
+ ############################################################################
167
+
168
+ def server_proc
169
+
170
+ while(true)
171
+ begin
172
+ ssl_connection=@ssl_server.accept
173
+ rescue OpenSSL::SSL::SSLError => e
174
+ next
175
+ rescue Errno::EBADF
176
+ break
177
+ end
178
+
179
+ @mutex.synchronize do
180
+ nc=NetServerClient.new(ssl_connection,self)
181
+ info("new connection from #{nc.user}")
182
+ @clients << nc
183
+ end
184
+ end
185
+ info("server stopped")
186
+
187
+ end
188
+
189
+ ############################################################################
190
+ #
191
+ #
192
+ #
193
+ ############################################################################
194
+
195
+ def client_closed(client)
196
+ @mutex.synchronize do
197
+ @clients.delete(client)
198
+ end
199
+ end
200
+
201
+ ############################################################################
202
+ #
203
+ #
204
+ #
205
+ ############################################################################
206
+
207
+ def post_fork()
208
+ c=nil
209
+ @mutex.synchronize do
210
+ c=@clients.clone
211
+ end
212
+ c.each do |client|
213
+ client.close_rudely()
214
+ end
215
+ ProcessWanker::with_logged_rescue("post_fork - stop_server") do
216
+ stop_server()
217
+ end
218
+ end
219
+
220
+ ############################################################################
221
+ #
222
+ #
223
+ #
224
+ ############################################################################
225
+
226
+ def self.instance
227
+ @@instance
228
+ end
229
+
230
+ end
231
+
232
+ end
@@ -0,0 +1,84 @@
1
+ ############################################################################
2
+ #
3
+ # net_server_client.rb
4
+ #
5
+ # server's view of a client connection
6
+ #
7
+ ############################################################################
8
+
9
+ require 'openssl'
10
+ require 'config'
11
+ require 'net_util'
12
+ require 'socket'
13
+ require 'net_connection'
14
+ require 'thread'
15
+
16
+ module ProcessWanker
17
+
18
+ ############################################################################
19
+ #
20
+ #
21
+ #
22
+ ############################################################################
23
+
24
+ class NetServerClient < NetConnection
25
+
26
+ ############################################################################
27
+ #
28
+ #
29
+ #
30
+ ############################################################################
31
+
32
+ def initialize(ssl_connection,server)
33
+ @server=server
34
+ super(ssl_connection)
35
+ end
36
+
37
+ ############################################################################
38
+ #
39
+ #
40
+ #
41
+ ############################################################################
42
+
43
+ def on_msg(msg)
44
+ super(msg)
45
+ ProcessWanker::with_logged_rescue("NetServerClient::on_msg") do
46
+ resp=NetApi::execute(msg,self)
47
+ if(resp)
48
+ debug("send resp #{resp.inspect}")
49
+ resp[:done]=true
50
+ send_msg(resp)
51
+ end
52
+ end
53
+ end
54
+
55
+ ############################################################################
56
+ #
57
+ #
58
+ #
59
+ ############################################################################
60
+
61
+ def inform(msg)
62
+ send_msg( { :info => msg } )
63
+ end
64
+
65
+ ############################################################################
66
+ #
67
+ #
68
+ #
69
+ ############################################################################
70
+
71
+ def on_close()
72
+ super()
73
+ @server.client_closed(self)
74
+ end
75
+
76
+ ############################################################################
77
+ #
78
+ #
79
+ #
80
+ ############################################################################
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,205 @@
1
+ ############################################################################
2
+ #
3
+ # net_util.rb
4
+ #
5
+ # handles the physical TCP/SSL connection between client(s) and daemon(s)
6
+ #
7
+ ############################################################################
8
+
9
+ require 'openssl'
10
+ require 'fileutils'
11
+
12
+ module ProcessWanker
13
+
14
+ ############################################################################
15
+ #
16
+ #
17
+ #
18
+ ############################################################################
19
+
20
+ module NetUtil
21
+
22
+ DEFAULT_PORT = 45231
23
+
24
+ ############################################################################
25
+ #
26
+ #
27
+ #
28
+ ############################################################################
29
+
30
+ def make_filename(prefix,type)
31
+ ext={ :key => "key", :cert => "crt" }[type]
32
+ "#{prefix}.#{ext}"
33
+ end
34
+ module_function :make_filename
35
+
36
+ ############################################################################
37
+ #
38
+ # generate_ca
39
+ #
40
+ # create a new CA certificate and private key
41
+ #
42
+ ############################################################################
43
+
44
+ def generate_ca(prefix,passphrase=nil)
45
+
46
+ outdir=File.expand_path(File.dirname("#{prefix}a.b"))
47
+ FileUtils.mkdir_p(outdir)
48
+
49
+ #
50
+ # write key file
51
+ #
52
+
53
+ puts "generating CA key..."
54
+ key = OpenSSL::PKey::RSA.new(2048)
55
+ cipher = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
56
+ exp = passphrase ? key.export(cipher,passphrase) : key.export
57
+ puts "saving CA key..."
58
+ File.open(make_filename(prefix,:key),"w") do |f|
59
+ f.write(exp)
60
+ end
61
+
62
+ #
63
+ # generate certificate
64
+ #
65
+
66
+ puts "generating CA cert..."
67
+ ca_name = OpenSSL::X509::Name.parse('CN=ca')
68
+ ca_cert = OpenSSL::X509::Certificate.new
69
+ ca_cert.serial = 0
70
+ ca_cert.version = 2
71
+ ca_cert.not_before = Time.at(0)
72
+ ca_cert.not_after = Time.at(0x7fffffff)
73
+ ca_cert.public_key = key.public_key
74
+ ca_cert.subject = ca_name
75
+ ca_cert.issuer = ca_name
76
+
77
+ extension_factory = OpenSSL::X509::ExtensionFactory.new
78
+ extension_factory.subject_certificate = ca_cert
79
+ extension_factory.issuer_certificate = ca_cert
80
+
81
+ extension_factory.create_extension 'subjectKeyIdentifier', 'hash'
82
+ extension_factory.create_extension 'basicConstraints', 'CA:TRUE', true
83
+ extension_factory.create_extension 'keyUsage', 'cRLSign,keyCertSign', true
84
+
85
+ puts "signing CA cert..."
86
+ ca_cert.sign(key, OpenSSL::Digest::SHA1.new)
87
+
88
+ puts "saving CA cert..."
89
+ File.open(make_filename(prefix,:cert),"w") do |f|
90
+ f.write(ca_cert.to_pem)
91
+ end
92
+
93
+ puts "wrote #{make_filename(prefix,:key)} and #{make_filename(prefix,:cert)}"
94
+
95
+ end
96
+
97
+ module_function :generate_ca
98
+
99
+ ############################################################################
100
+ #
101
+ #
102
+ #
103
+ ############################################################################
104
+
105
+ def generate_cert(ca_prefix,cert_prefix,name,passphrase=nil)
106
+
107
+ outdir=File.expand_path(File.dirname("#{cert_prefix}a.b"))
108
+ FileUtils.mkdir_p(outdir)
109
+
110
+ #
111
+ # load ca key and cert
112
+ #
113
+
114
+ puts "loading CA key and cert..."
115
+ ca_key=OpenSSL::PKey::RSA.new( File.read(make_filename(ca_prefix,:key)) )
116
+ ca_cert=OpenSSL::X509::Certificate.new( File.read(make_filename(ca_prefix,:cert)) )
117
+
118
+ #
119
+ # write key file
120
+ #
121
+
122
+ puts "generating key for #{name}..."
123
+ key = OpenSSL::PKey::RSA.new(2048)
124
+ cipher = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
125
+ exp = passphrase ? key.export(cipher,passphrase) : key.export
126
+ puts "saving key for #{name}..."
127
+ File.open(make_filename(cert_prefix,:key),"w") do |f|
128
+ f.write(exp)
129
+ end
130
+
131
+ #
132
+ # generate CSR
133
+ #
134
+
135
+ puts "generating CSR for #{name}..."
136
+ csr = OpenSSL::X509::Request.new
137
+ csr.version = 0
138
+ csr.subject = OpenSSL::X509::Name.parse("CN=#{name}")
139
+ csr.public_key = key.public_key
140
+ csr.sign(key,OpenSSL::Digest::SHA1.new)
141
+
142
+ #
143
+ # create certificate
144
+ #
145
+
146
+ puts "creating cert for #{name}..."
147
+ csr_cert = OpenSSL::X509::Certificate.new
148
+ csr_cert.serial = 0
149
+ csr_cert.version = 2
150
+ csr_cert.not_before = Time.at(0)
151
+ csr_cert.not_after = Time.at(0x7fffffff)
152
+
153
+ csr_cert.subject = csr.subject
154
+ csr_cert.public_key = csr.public_key
155
+ csr_cert.issuer = ca_cert.subject
156
+
157
+ extension_factory = OpenSSL::X509::ExtensionFactory.new
158
+ extension_factory.subject_certificate = csr_cert
159
+ extension_factory.issuer_certificate = ca_cert
160
+
161
+ extension_factory.create_extension 'basicConstraints', 'CA:FALSE'
162
+ extension_factory.create_extension 'keyUsage','keyEncipherment,dataEncipherment,digitalSignature'
163
+ extension_factory.create_extension 'subjectKeyIdentifier', 'hash'
164
+
165
+ puts "signing cert for #{name}..."
166
+ csr_cert.sign(ca_key,OpenSSL::Digest::SHA1.new)
167
+
168
+ #
169
+ # save it
170
+ #
171
+
172
+ puts "saving cert for #{name}..."
173
+ File.open(make_filename(cert_prefix,:cert),"w") do |f|
174
+ f.write(csr_cert.to_pem)
175
+ end
176
+
177
+ puts "wrote #{make_filename(cert_prefix,:key)} and #{make_filename(cert_prefix,:cert)}"
178
+
179
+ end
180
+ module_function :generate_cert
181
+
182
+ ############################################################################
183
+ #
184
+ #
185
+ #
186
+ ############################################################################
187
+
188
+ def post_fork()
189
+
190
+ if(NetServer.instance())
191
+ NetServer.instance().post_fork()
192
+ end
193
+
194
+ end
195
+ module_function :post_fork
196
+
197
+ ############################################################################
198
+ #
199
+ #
200
+ #
201
+ ############################################################################
202
+
203
+ end
204
+
205
+ end