processwanker 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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