1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22
23 from __future__ import with_statement
24 import os
25 import shutil
26 import time
27 from entropy.const import etpConst, ETP_LOGLEVEL_NORMAL, ETP_LOGPRI_INFO, \
28 const_setup_perms
29 from entropy.exceptions import *
30 from entropy.services.skel import SocketAuthenticator, SocketCommands
31 from entropy.i18n import _
32 from entropy.output import blue, red, darkgreen
33
35
36 import socket
37 import SocketServer
38 from threading import Thread
39
41
42 import entropy.tools as entropyTools
43
44 - def __init__(self, HostInterface, *args, **kwargs):
47
49
50
51 if not arguments or (len(arguments) != 3):
52 return False,None,None,'wrong arguments'
53
54 user = arguments[0]
55 auth_type = arguments[1]
56 auth_string = arguments[2]
57
58
59 if auth_type not in self.valid_auth_types:
60 return False,user,None,'invalid auth type'
61
62 udata = self.__get_user_data(user)
63 if udata == None:
64 return False,user,None,'invalid user'
65
66 uid = udata[2]
67
68 if not self.entropyTools.is_user_in_entropy_group(uid):
69 return False,user,uid,'user not in %s group' % (etpConst['sysgroup'],)
70
71
72 valid = self.__validate_auth(user,auth_type,auth_string)
73 if not valid:
74 return False,user,uid,'auth failed'
75
76 if not uid:
77 self.HostInterface.sessions[self.session]['admin'] = True
78 else:
79 self.HostInterface.sessions[self.session]['user'] = True
80 return True,user,uid,"ok"
81
82
84
85 auth_uid = self.HostInterface.sessions[self.session]['auth_uid']
86 mydata = {}
87 udata = self.__get_uid_data(auth_uid)
88 if udata:
89 mydata['username'] = udata[0]
90 mydata['uid'] = udata[2]
91 mydata['gid'] = udata[3]
92 mydata['references'] = udata[4]
93 mydata['home'] = udata[5]
94 mydata['shell'] = udata[6]
95 return True,mydata,'ok'
96
98 import pwd
99
100 try:
101 udata = pwd.getpwuid(user_id)
102 except KeyError:
103 return None
104 return udata
105
107 import pwd
108
109 try:
110 udata = pwd.getpwnam(user)
111 except KeyError:
112 return None
113 return udata
114
116 valid = False
117 if auth_type == "plain":
118 valid = self.__do_auth(user, auth_string)
119 elif auth_type == "shadow":
120 valid = self.__do_auth(user, auth_string, auth_type = "shadow")
121 elif auth_type == "md5":
122 valid = self.__do_auth(user, auth_string, auth_type = "md5")
123 return valid
124
125 - def __do_auth(self, user, password, auth_type = None):
126 import spwd
127
128 try:
129 enc_pass = spwd.getspnam(user)[1]
130 except KeyError:
131 return False
132
133 if auth_type == None:
134 import crypt
135 generated_pass = crypt.crypt(str(password), enc_pass)
136 elif auth_type == "shadow":
137 generated_pass = password
138 elif auth_type == "md5":
139 import hashlib
140 m = hashlib.md5()
141 m.update(enc_pass)
142 enc_pass = m.hexdigest()
143 generated_pass = str(password)
144 else:
145 generated_pass = None
146
147 if generated_pass == enc_pass:
148 return True
149 return False
150
152
153
154 if (len(myargs) < 1) or (len(myargs) > 1):
155 return False,None,'wrong arguments'
156
157 user = myargs[0]
158
159 if not user or not isinstance(user,basestring):
160 return False,None,"wrong user"
161
162 return True,user,"ok"
163
165 if gid != None:
166 os.setgid(gid)
167 if uid != None:
168 os.setuid(uid)
169
171 myargs = args[:]
172 myargs[-1] = 'hidden'
173 return myargs
174
177
178 - class HostServerMixin(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
179
181 '''
182 Base class for implementing the rest of the wrappers in this module.
183 Operates by taking a connection argument which is used when 'self' doesn't
184 provide the functionality being requested.
185 '''
187 self.connection = connection
188
190 return getattr(self.connection, function)
191
192 import entropy.tools as entropyTools
193 import socket as socket_mod
194 import select
195 import SocketServer
196
197
198
199 daemon_threads = True
200
201
202
203
204
205 allow_reuse_address = True
206
207 - def __init__(self, server_address, RequestHandlerClass, processor, HostInterface, authorized_clients_only = False):
208
209 self.alive = True
210 self.socket = self.socket_mod
211 self.processor = processor
212 self.server_address = server_address
213 self.HostInterface = HostInterface
214 self.SSL = self.HostInterface.SSL
215 self.real_sock = None
216 self.ssl_authorized_clients_only = authorized_clients_only
217
218 if self.SSL:
219 self.SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
220 self.load_ssl_context()
221 self.make_ssl_connection_alive()
222 else:
223 try:
224 self.SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
225 except self.socket_mod.error, e:
226 if e[0] == 13:
227 raise ConnectionError('ConnectionError: %s' % (_("Cannot bind the service"),))
228 raise
229
231
232 self.context = self.SSL['m'].Context(self.SSL['m'].SSLv23_METHOD)
233 self.context.set_verify(self.SSL['m'].VERIFY_PEER, self.verify_ssl_cb)
234 self.context.set_options(self.SSL['m'].OP_NO_SSLv2)
235
236 self.context.use_privatekey_file(self.SSL['key'])
237 self.context.use_certificate_file(self.SSL['cert'])
238 self.context.load_verify_locations(self.SSL['ca_cert'])
239 self.context.load_client_ca(self.SSL['ca_cert'])
240 self.HostInterface.updateProgress('SSL context loaded, key: %s - cert: %s, CA cert: %s, CA pkey: %s' % (
241 self.SSL['key'],
242 self.SSL['cert'],
243 self.SSL['ca_cert'],
244 self.SSL['ca_pkey']
245 )
246 )
247
249 self.real_sock = self.socket_mod.socket(self.address_family, self.socket_type)
250 self.socket = self.ConnWrapper(self.SSL['m'].Connection(self.context, self.real_sock))
251 self.server_bind()
252 self.server_activate()
253
254
255
258
260
261 self.do_ssl = self.HostInterface.SSL
262 if self.do_ssl: self.do_ssl = True
263 else: self.do_ssl = False
264
265 allowed = self.ip_blacklist_check(client_address[0])
266 if allowed: allowed = self.ip_max_connections_check(client_address[0])
267 if not allowed:
268 self.HostInterface.updateProgress(
269 '[from: %s | SSL: %s] connection refused, ip blacklisted or maximum connections per IP reached' % (
270 client_address,
271 self.do_ssl,
272 )
273 )
274 return False
275
276 allowed = self.max_connections_check(request)
277 if not allowed:
278 self.HostInterface.updateProgress(
279 '[from: %s | SSL: %s] connection refused (max connections reached: %s)' % (
280 client_address,
281 self.do_ssl,
282 self.HostInterface.max_connections,
283 )
284 )
285 return False
286
287
288 self.HostInterface.connections += 1
289 self.HostInterface.updateProgress(
290 '[from: %s | SSL: %s] connection established (%s of %s max connections)' % (
291 client_address,
292 self.do_ssl,
293 self.HostInterface.connections,
294 self.HostInterface.max_connections,
295 )
296 )
297 return True
298
300 if client_addr in self.HostInterface.ip_blacklist:
301 return False
302 return True
303
305 max_conn_per_ip = self.HostInterface.max_connections_per_host
306 max_conn_per_ip_barrier = self.HostInterface.max_connections_per_host_barrier
307 per_host_connections = self.HostInterface.per_host_connections
308 conn_data = per_host_connections.get(ip_address)
309 if conn_data == None:
310 per_host_connections[ip_address] = 1
311 else:
312 conn_data += 1
313 per_host_connections[ip_address] += 1
314 if conn_data > max_conn_per_ip:
315 self.HostInterface.updateProgress(
316 '[from: %s] ------- :EEK: !! connection closed too many simultaneous connections from host (current: %s | limit: %s) -------' % (
317 ip_address,
318 conn_data,
319 max_conn_per_ip,
320 )
321 )
322 return False
323 elif conn_data > max_conn_per_ip_barrier:
324 times = [5,6,7,8]
325 self.HostInterface.updateProgress(
326 '[from: %s] ------- :EEEK: !! connection warning simultaneous connection barrier reached from host (current: %s | soft limit: %s) -------' % (
327 ip_address,
328 conn_data,
329 max_conn_per_ip_barrier,
330 )
331 )
332 rnd_num = self.entropyTools.get_random_number()
333 time.sleep(times[abs(hash(rnd_num))%len(times)])
334
335 return True
336
338 current = self.HostInterface.connections
339 maximum = self.HostInterface.max_connections
340 if current >= maximum:
341 try:
342 self.HostInterface.transmit(
343 request,
344 self.HostInterface.answers['mcr']
345 )
346 except:
347 pass
348 return False
349 else:
350 return True
351
353 while self.alive:
354
355
356 self.handle_request()
357
358
360 """Finish one request by instantiating RequestHandlerClass."""
361 self.RequestHandlerClass(request, client_address, self)
362
363 self.HostInterface.updateProgress(
364 '[from: %s] connection closed (%s of %s max connections)' % (
365 client_address,
366 self.HostInterface.connections - 1,
367 self.HostInterface.max_connections,
368 )
369 )
370 per_host_connections = self.HostInterface.per_host_connections
371 conn_data = per_host_connections.get(client_address[0])
372 if conn_data != None:
373 if conn_data < 1:
374 del per_host_connections[client_address[0]]
375 else:
376 per_host_connections[client_address[0]] -= 1
377
379 if self.HostInterface.connections > 0:
380 self.HostInterface.connections -= 1
381
383
384 import SocketServer
385 import select
386 import socket
387 import entropy.tools as entropyTools
388 import gc
389 timed_out = False
390
391 - def __init__(self, request, client_address, server):
392
393
394 self.__buffered_data = None
395 self.__inst_token = self.entropyTools.get_random_number()
396 self.server = None
397 self.request = None
398 self.client_address = None
399 self.SocketServer.BaseRequestHandler.__init__(self, request,
400 client_address, server)
401 self.__data_counter = None
402
404
405 if self.timed_out:
406 return True
407 self.timed_out = True
408 try:
409 ready_to_read, ready_to_write, in_error = self.select.select(
410 [self.request], [], [], self.default_timeout)
411 except KeyboardInterrupt:
412 self.timed_out = True
413 return True
414
415 if len(ready_to_read) == 1 and ready_to_read[0] == self.request:
416
417 self.timed_out = False
418
419 data = None
420
421 self.server.processor.HostInterface.updateProgress(
422 '[from: %s] request arrived :: counter: %s | buf_data: %s' % (
423 self.client_address,
424 self.__data_counter,
425 len(self.__buffered_data),
426 )
427 )
428
429 try:
430
431 data = self.request.recv(1024)
432 if self.ssl:
433 while self.request.pending():
434 data += self.request.recv(1024)
435
436 if self.__data_counter is None:
437 if data == '':
438 return True
439 elif data == self.server.processor.HostInterface.answers['noop']:
440 return False
441 elif len(data) < len(self.myeos):
442 self.server.processor.HostInterface.updateProgress(
443 'interrupted: %s, reason: %s - from client: %s - data: "%s" - counter: %s' % (
444 self.server.server_address,
445 "malformed EOS",
446 self.client_address,
447 repr(data),
448 self.__data_counter,
449 )
450 )
451 self.__buffered_data = ''
452 return True
453 mystrlen = data.split(self.myeos)[0]
454 self.__data_counter = int(mystrlen)
455 data = data[len(mystrlen)+1:]
456 self.__data_counter -= len(data)
457 self.__buffered_data += data
458
459
460 if self.__data_counter > self.max_command_length:
461 raise InterruptError(
462 'InterruptError: command too long: %s, limit: %s' % (
463 self.__data_counter, self.max_command_length,))
464
465 buf_empty_watchdog_count = 50
466 buf_len = 1024
467 while self.__data_counter > 0:
468 data_buf = buf_len
469 if self.__data_counter < buf_len:
470 data_buf = self.__data_counter
471 if self.ssl:
472 x = self.request.recv(data_buf)
473 else:
474 x = self.request.recv(data_buf)
475 xlen = len(x)
476 self.__data_counter -= xlen
477 self.__buffered_data += x
478
479
480 if (xlen == 0) and (self.__data_counter > 0):
481 buf_empty_watchdog_count -= 1
482 time.sleep(0.05)
483 if buf_empty_watchdog_count < 1:
484 raise ValueError(
485 "buffer counter watchdog trigger")
486
487 self.__data_counter = None
488 except ValueError:
489 tb = self.entropyTools.get_traceback()
490 print tb
491 self.server.processor.HostInterface.socketLog.write(tb)
492 self.server.processor.HostInterface.socketLog.write(repr(data))
493 self.server.processor.HostInterface.socketLog.write(str(self))
494 self.server.processor.HostInterface.socketLog.write(str(self.__inst_token))
495 self.server.processor.HostInterface.updateProgress(
496 'interrupted: %s, reason: %s - from client: %s' % (
497 self.server.server_address,
498 "malformed transmission",
499 self.client_address,
500 )
501 )
502 return True
503 except self.socket.timeout, e:
504 self.server.processor.HostInterface.updateProgress(
505 'interrupted: %s, reason: %s - from client: %s' % (
506 self.server.server_address,
507 e,
508 self.client_address,
509 )
510 )
511 return True
512 except self.socket.sslerror, e:
513 self.server.processor.HostInterface.updateProgress(
514 'interrupted: %s, SSL socket error reason: %s - from client: %s' % (
515 self.server.server_address,
516 e,
517 self.client_address,
518 )
519 )
520 return True
521 except (self.ssl_exceptions['WantReadError'], self.ssl_exceptions['WantX509LookupError'],):
522 return False
523 except self.ssl_exceptions['ZeroReturnError']:
524 return True
525 except self.ssl_exceptions['Error'], e:
526 self.server.processor.HostInterface.updateProgress(
527 'interrupted: SSL Error, reason: %s - from client: %s' % (
528 e,
529 self.client_address,
530 )
531 )
532 return True
533 except InterruptError, e:
534 self.server.processor.HostInterface.updateProgress(
535 'interrupted: Command Error, reason: %s - from client: %s' % (
536 e,
537 self.client_address,
538 )
539 )
540 return True
541
542 if not self.__buffered_data:
543 return True
544
545 cmd = self.server.processor.process(self.__buffered_data, self.request, self.client_address)
546 if cmd == 'close':
547
548 self.server.processor.transmit(self.server.processor.HostInterface.answers['cl'])
549 return True
550 self.__buffered_data = ''
551 return False
552
554 if hasattr(self.server.processor.HostInterface,'ForkLock'):
555 x = getattr(self.server.processor.HostInterface,'ForkLock')
556 if hasattr(x,'acquire') and hasattr(x,'release') and hasattr(x,'locked'):
557 x.acquire()
558
560 if hasattr(self.server.processor.HostInterface,'ForkLock'):
561 x = getattr(self.server.processor.HostInterface,'ForkLock')
562 if hasattr(x,'acquire') and hasattr(x,'release') and hasattr(x,'locked'):
563 if x.locked(): x.release()
564
566
567
568 if self.server.processor.HostInterface.fork_requests:
569 self.fork_lock_acquire()
570 try:
571 my_timeout = self.server.processor.HostInterface.fork_request_timeout_seconds
572 pid = os.fork()
573 seconds = 0
574 if pid > 0:
575
576 passed_away = False
577 while 1:
578 time.sleep(1)
579 seconds += 1
580 try:
581 dead = os.waitpid(pid, os.WNOHANG)[0]
582 except OSError, e:
583 if e.errno != 10: raise
584 dead = True
585 if passed_away:
586 break
587 if dead: break
588 if seconds > my_timeout:
589 self.server.processor.HostInterface.updateProgress(
590 'interrupted: forked request timeout: %s,%s from client: %s' % (
591 seconds,
592 dead,
593 self.client_address,
594 )
595 )
596 if not dead:
597 import signal
598 os.kill(pid,signal.SIGKILL)
599 passed_away = True
600 continue
601 break
602 else:
603 self.do_handle()
604 os._exit(0)
605 finally:
606 self.fork_lock_release()
607 else:
608 self.do_handle()
609
610
612
613 self.default_timeout = self.server.processor.HostInterface.timeout
614 self.ssl = self.server.processor.HostInterface.SSL
615 self.ssl_exceptions = self.server.processor.HostInterface.SSL_exceptions
616 self.myeos = self.server.processor.HostInterface.answers['eos']
617 self.max_command_length = self.server.processor.HostInterface.max_command_length
618
619 while 1:
620
621 try:
622 self.server.processor.HostInterface.updateProgress(
623 '[from: %s] calling data_receiver' % (
624 self.client_address,
625 )
626 )
627 dobreak = self.data_receiver()
628 self.server.processor.HostInterface.updateProgress(
629 '[from: %s] quitting data_receiver :: dobreak: %s' % (
630 self.client_address,
631 dobreak,
632 )
633 )
634 if dobreak: break
635 except Exception, e:
636 self.server.processor.HostInterface.updateProgress(
637 'interrupted: Unhandled exception: %s, error: %s - from client: %s' % (
638 Exception,
639 e,
640 self.client_address,
641 )
642 )
643
644 tb = self.entropyTools.get_traceback()
645 print tb
646 self.server.processor.HostInterface.socketLog.write(tb)
647 break
648
649 self.request.close()
650
652 self.__data_counter = None
653 self.__buffered_data = ''
654
655
657
658 import entropy.tools as entropyTools
659 import socket
660 import gc
661
663 self.HostInterface = HostInterface
664 self.channel = None
665
667 if data.strip() in self.HostInterface.termination_commands:
668 self.HostInterface.updateProgress('close: %s' % (self.client_address,))
669 self.transmit(self.HostInterface.answers['cl'])
670 return "close"
671
672 if not data.strip():
673 return "ignore"
674
676
677 args = string.strip().split(" ")
678 session = args[0]
679 if (session in self.HostInterface.initialization_commands) or \
680 (session in self.HostInterface.no_session_commands) or \
681 len(args) < 2:
682 cmd = args[0]
683 session = None
684 else:
685 cmd = args[1]
686 args = args[1:]
687
688 stream_enabled = False
689 if (session != None) and self.HostInterface.sessions.has_key(session):
690 stream_enabled = self.HostInterface.sessions[session].get('stream_mode')
691
692 if stream_enabled and (cmd not in self.HostInterface.config_commands):
693 session_len = 0
694 if session: session_len = len(session)+1
695 return cmd,[string[session_len+len(cmd)+1:]],session
696 else:
697 myargs = []
698 if len(args) > 1:
699 myargs = args[1:]
700
701 return cmd,myargs,session
702
704 if not valid_cmd:
705 self.transmit(self.HostInterface.answers['no'])
706 elif whoops:
707 self.transmit(self.HostInterface.answers['er'])
708 elif cmd not in self.HostInterface.no_acked_commands:
709 self.transmit(self.HostInterface.answers['ok'])
710
712
713
714 if (cmd not in self.HostInterface.valid_commands):
715 return False,"not a valid command"
716
717 if session == None:
718 if cmd not in self.HostInterface.no_session_commands:
719 return False,"need a valid session"
720 elif session not in self.HostInterface.sessions:
721 return False,"session is not alive"
722
723
724 if session != None:
725 auth = self.HostInterface.valid_commands[cmd]['auth']
726 if auth:
727
728 authed = self.HostInterface.sessions[session]['auth_uid']
729 if authed == None:
730
731 return False,"not authenticated"
732
733
734 if session != None:
735 self.HostInterface.set_session_running(session)
736 self.HostInterface.update_session_time(session)
737
738 return True,"all good"
739
741 f, args, kwargs = self.HostInterface.AuthenticatorInst
742 myinst = f(*args,**kwargs)
743 return myinst
744
746
747 uid = None
748 if session != None:
749 uid = self.HostInterface.sessions[session]['auth_uid']
750
751 intf = self.HostInterface.EntropyInstantiation[0]
752 args = self.HostInterface.EntropyInstantiation[1]
753 kwds = self.HostInterface.EntropyInstantiation[2]
754 return intf(*args, **kwds)
755
756 - def process(self, data, channel, client_address):
757
758 self.channel = channel
759 self.client_address = client_address
760
761 term = self.handle_termination_commands(data)
762 if term:
763 del authenticator
764 return term
765
766 cmd, args, session = self.handle_command_string(data)
767 valid_cmd, reason = self.validate_command(cmd, args, session)
768
769
770 authenticator = None
771 cmd_data = self.HostInterface.valid_commands.get(cmd)
772 if not isinstance(cmd_data,dict):
773 self.HostInterface.updateProgress(
774 '[from: %s] command error: invalid command: %s' % (
775 self.client_address,
776 cmd,
777 )
778 )
779 return "close"
780 elif (("authenticator" in cmd_data['args']) or (cmd in self.HostInterface.login_pass_commands)):
781 try:
782 authenticator = self.load_authenticator()
783 except ConnectionError, e:
784 self.HostInterface.updateProgress(
785 '[from: %s] authenticator error: cannot load: %s' % (
786 self.client_address,
787 e,
788 )
789 )
790 tb = self.entropyTools.get_traceback()
791 print tb
792 self.HostInterface.socketLog.write(tb)
793 return "close"
794 except Exception, e:
795 self.HostInterface.updateProgress(
796 '[from: %s] authenticator error: cannot load: %s - unknown error' % (
797 self.client_address,
798 e,
799 )
800 )
801 tb = self.entropyTools.get_traceback()
802 print tb
803 self.HostInterface.socketLog.write(tb)
804 return "close"
805
806 p_args = args
807 if (cmd in self.HostInterface.login_pass_commands) and authenticator != None:
808 p_args = authenticator.hide_login_data(p_args)
809 elif cmd in self.HostInterface.raw_commands:
810 p_args = ['raw data']
811 self.HostInterface.updateProgress(
812 '[from: %s] command validation :: called %s: length: %s, args: %s, session: %s, valid: %s, reason: %s' % (
813 self.client_address,
814 cmd,
815 len(data),
816 p_args,
817 session,
818 valid_cmd,
819 reason,
820 )
821 )
822
823 whoops = False
824 if valid_cmd:
825
826 if authenticator != None:
827
828 authenticator.set_session(session)
829
830 Entropy = None
831 if "Entropy" in cmd_data['args']:
832 Entropy = self.load_service_interface(session)
833 try:
834 self.run_task(cmd, args, session, Entropy, authenticator)
835 except self.socket.timeout:
836 self.HostInterface.updateProgress(
837 '[from: %s] command error: timeout, closing connection' % (
838 self.client_address,
839 )
840 )
841
842 del authenticator
843 del Entropy
844 return "close"
845 except self.socket.error, e:
846 self.HostInterface.updateProgress(
847 '[from: %s] command error: socket error: %s' % (
848 self.client_address,
849 e,
850 )
851 )
852
853 del authenticator
854 del Entropy
855 return "close"
856 except self.HostInterface.SSL_exceptions['SysCallError'], e:
857 self.HostInterface.updateProgress(
858 '[from: %s] command error: SSL SysCallError: %s' % (
859 self.client_address,
860 e,
861 )
862 )
863
864 del authenticator
865 del Entropy
866 return "close"
867 except Exception, e:
868
869 tb = self.entropyTools.get_traceback()
870 print tb
871 self.HostInterface.socketLog.write(tb)
872
873 self.HostInterface.updateProgress(
874 '[from: %s] command error: %s, type: %s' % (
875 self.client_address,
876 e,
877 type(e),
878 )
879 )
880 if session != None:
881 self.HostInterface.store_rc(str(e),session)
882 whoops = True
883
884 del Entropy
885
886 if session != None:
887 self.HostInterface.update_session_time(session)
888 self.HostInterface.unset_session_running(session)
889 rcmd = None
890 try:
891 self.handle_end_answer(cmd, whoops, valid_cmd)
892 except (self.socket.error, self.socket.timeout,self.HostInterface.SSL_exceptions['SysCallError'],):
893 rcmd = "close"
894
895 if authenticator != None:
896 authenticator.terminate_instance()
897 del authenticator
898 if not self.HostInterface.fork_requests:
899 self.gc.collect()
900 return rcmd
901
903 self.HostInterface.transmit(self.channel, data)
904
905 - def run_task(self, cmd, args, session, Entropy, authenticator):
906
907 p_args = args
908 if cmd in self.HostInterface.login_pass_commands:
909 p_args = authenticator.hide_login_data(p_args)
910 elif cmd in self.HostInterface.raw_commands:
911 p_args = ['raw data']
912 self.HostInterface.updateProgress(
913 '[from: %s] run_task :: called %s: args: %s, session: %s' % (
914 self.client_address,
915 cmd,
916 p_args,
917 session,
918 )
919 )
920
921 myargs = args
922 mykwargs = {}
923 if cmd not in self.HostInterface.raw_commands:
924 myargs, mykwargs = self._get_args_kwargs(args)
925
926 rc = self.spawn_function(cmd, myargs, mykwargs, session, Entropy, authenticator)
927 if session != None and self.HostInterface.sessions.has_key(session):
928 self.HostInterface.store_rc(rc, session)
929 return rc
930
932 myargs = []
933 mykwargs = {}
934
935 def is_int(x):
936 try:
937 int(x)
938 except ValueError:
939 return False
940 return True
941
942 for arg in args:
943 if (arg.find("=") != -1) and not arg.startswith("="):
944 x = arg.split("=")
945 a = x[0]
946 b = ''.join(x[1:])
947 if (b in ("True","False",)) or is_int(b):
948 mykwargs[a] = eval(b)
949 else:
950 myargs.append(arg)
951 else:
952 if (arg in ("True","False",)) or is_int(arg):
953 myargs.append(eval(arg))
954 else:
955 myargs.append(arg)
956 return myargs, mykwargs
957
958 - def spawn_function(self, cmd, myargs, mykwargs, session, Entropy, authenticator):
959
960 p_args = myargs
961 if cmd in self.HostInterface.login_pass_commands:
962 p_args = authenticator.hide_login_data(p_args)
963 elif cmd in self.HostInterface.raw_commands:
964 p_args = ['raw data']
965 self.HostInterface.updateProgress(
966 '[from: %s] called %s: args: %s, kwargs: %s' % (
967 self.client_address,
968 cmd,
969 p_args,
970 mykwargs,
971 )
972 )
973 return self.do_spawn(cmd, myargs, mykwargs, session, Entropy, authenticator)
974
975 - def do_spawn(self, cmd, myargs, mykwargs, session, Entropy, authenticator):
976
977 cmd_data = self.HostInterface.valid_commands.get(cmd)
978 do_fork = cmd_data['as_user']
979 f = cmd_data['cb']
980 func_args = []
981 for arg in cmd_data['args']:
982 try:
983 func_args.append(eval(arg))
984 except (NameError, SyntaxError):
985 func_args.append(str(arg))
986
987 if do_fork:
988 myfargs = func_args[:]
989 myfargs.extend(myargs)
990 return self.fork_task(f, session, authenticator, *myfargs, **mykwargs)
991 else:
992 return f(*func_args)
993
994 - def fork_task(self, f, session, authenticator, *args, **kwargs):
995 gid = None
996 uid = None
997 if session != None:
998 logged_in = self.HostInterface.sessions[session]['auth_uid']
999 if logged_in != None:
1000 uid = logged_in
1001 gid = etpConst['entropygid']
1002 return self.entropyTools.spawn_function(self._do_fork, f, authenticator, uid, gid, *args, **kwargs)
1003
1004 - def _do_fork(self, f, authenticator, uid, gid, *args, **kwargs):
1008
1010
1011 import entropy.dump as dumpTools
1012 import zlib
1013
1015
1016 SocketCommands.__init__(self, HostInterface, inst_name = "builtin")
1017
1018 self.valid_commands = {
1019 'begin': {
1020 'auth': False,
1021 'built_in': True,
1022 'cb': self.docmd_begin,
1023 'args': ["self.transmit", "self.client_address"],
1024 'as_user': False,
1025
1026 'desc': "instantiate a session",
1027 'syntax': "begin",
1028 'from': unicode(self),
1029 },
1030 'end': {
1031 'auth': False,
1032 'built_in': True,
1033 'cb': self.docmd_end,
1034 'args': ["self.transmit", "session"],
1035 'as_user': False,
1036 'desc': "end a session",
1037 'syntax': "<SESSION_ID> end",
1038 'from': unicode(self),
1039 },
1040 'session_config': {
1041 'auth': False,
1042 'built_in': True,
1043 'cb': self.docmd_session_config,
1044 'args': ["session","myargs"],
1045 'as_user': False,
1046 'desc': "set session configuration options",
1047 'syntax': "<SESSION_ID> session_config <option> [parameters]",
1048 'from': unicode(self),
1049 },
1050 'rc': {
1051 'auth': False,
1052 'built_in': True,
1053 'cb': self.docmd_rc,
1054 'args': ["self.transmit","session"],
1055 'as_user': False,
1056 'desc': "get data returned by the last valid command (streamed python object)",
1057 'syntax': "<SESSION_ID> rc",
1058 'from': unicode(self),
1059 },
1060 'hello': {
1061 'auth': False,
1062 'built_in': True,
1063 'cb': self.docmd_hello,
1064 'args': ["self.transmit"],
1065 'as_user': False,
1066 'desc': "get server status",
1067 'syntax': "hello",
1068 'from': unicode(self),
1069 },
1070 'alive': {
1071 'auth': True,
1072 'built_in': True,
1073 'cb': self.docmd_alive,
1074 'args': ["self.transmit","self.client_address","myargs"],
1075 'as_user': False,
1076 'desc': "check if a session is still alive",
1077 'syntax': "alive <SESSION_ID>",
1078 'from': unicode(self),
1079 },
1080 'login': {
1081 'auth': False,
1082 'built_in': True,
1083 'cb': self.docmd_login,
1084 'args': ["self.transmit", "authenticator", "session", "self.client_address", "myargs"],
1085 'as_user': False,
1086 'desc': "login on the running server (allows running extra commands)",
1087 'syntax': "<SESSION_ID> login <authenticator parameters, default: <user> <auth_type> <password> >",
1088 'from': unicode(self),
1089 },
1090 'user_data': {
1091 'auth': True,
1092 'built_in': True,
1093 'cb': self.docmd_userdata,
1094 'args': ["self.transmit", "authenticator", "session"],
1095 'as_user': False,
1096 'desc': "get general user information, user must be logged in",
1097 'syntax': "<SESSION_ID> user_data",
1098 'from': unicode(self),
1099 },
1100 'logout': {
1101 'auth': True,
1102 'built_in': True,
1103 'cb': self.docmd_logout,
1104 'args': ["self.transmit", "authenticator", "session", "self.client_address", "myargs"],
1105 'as_user': False,
1106 'desc': "logout on the running server",
1107 'syntax': "<SESSION_ID> logout <USER>",
1108 'from': unicode(self),
1109 },
1110 'help': {
1111 'auth': False,
1112 'built_in': True,
1113 'cb': self.docmd_help,
1114 'args': ["self.transmit"],
1115 'as_user': False,
1116 'desc': "this output",
1117 'syntax': "help",
1118 'from': unicode(self),
1119 },
1120 'available_commands': {
1121 'auth': False,
1122 'built_in': True,
1123 'cb': self.docmd_available_commands,
1124 'args': ["self.HostInterface"],
1125 'as_user': False,
1126 'desc': "get info about available commands (you must retrieve this using the 'rc' command)",
1127 'syntax': "available_commands",
1128 'from': unicode(self),
1129 },
1130 'stream': {
1131 'auth': True,
1132 'built_in': True,
1133 'cb': self.docmd_stream,
1134 'args': ["session", "myargs"],
1135 'as_user': False,
1136 'desc': "send a chunk of data to be saved on the session temp file path (will be removed on session expiration)",
1137 'syntax': "<SESSION_ID> stream <chunk of byte-string to write to file>",
1138 'from': unicode(self),
1139 },
1140 }
1141
1142 self.no_acked_commands = ["rc", "begin", "end", "hello", "alive", "login", "logout","help"]
1143 self.termination_commands = ["quit","close"]
1144 self.initialization_commands = ["begin"]
1145 self.login_pass_commands = ["login"]
1146 self.no_session_commands = ["begin","hello","alive","help"]
1147 self.raw_commands = ["stream"]
1148 self.config_commands = ["session_config"]
1149
1151
1152 if not myargs:
1153 return False,"not enough parameters"
1154
1155 option = myargs[0]
1156 myopts = myargs[1:]
1157
1158 if option == "compression":
1159 docomp = True
1160 do_zlib = False
1161 if "zlib" in myopts:
1162 do_zlib = True
1163 if myopts:
1164 if isinstance(myopts[0],bool):
1165 docomp = myopts[0]
1166 else:
1167 try:
1168 docomp = eval(myopts[0])
1169 except (NameError, TypeError,):
1170 pass
1171 if docomp and do_zlib:
1172 docomp = "zlib"
1173 elif docomp and not do_zlib:
1174 docomp = "gzip"
1175 else:
1176 docomp = None
1177 self.HostInterface.sessions[session]['compression'] = docomp
1178 return True,"compression now: %s" % (docomp,)
1179 elif option == "stream":
1180 dostream = True
1181 if "off" in myopts:
1182 dostream = False
1183 self.HostInterface.sessions[session]['stream_mode'] = dostream
1184 return True,'stream mode: %s' % (dostream,)
1185 else:
1186 return False,"invalid config option"
1187
1189
1190 def copy_obj(obj):
1191 if isinstance(obj,set) or isinstance(obj,dict):
1192 return obj.copy()
1193 elif isinstance(obj,list) or isinstance(obj,tuple):
1194 return obj[:]
1195 return obj
1196
1197 def can_be_streamed(obj):
1198 if isinstance(obj,(bool,basestring,int,float,list,tuple,set,dict,)):
1199 return True
1200 return False
1201
1202 mydata = {}
1203 mydata['disabled_commands'] = copy_obj(host_interface.disabled_commands)
1204 valid_cmds = copy_obj(host_interface.valid_commands)
1205 mydata['valid_commands'] = {}
1206 for cmd in valid_cmds:
1207 mydict = {}
1208 for item in valid_cmds[cmd]:
1209 param = valid_cmds[cmd][item]
1210 if not can_be_streamed(param):
1211 continue
1212 mydict[item] = param
1213 mydata['valid_commands'][cmd] = mydict.copy()
1214
1215 return mydata
1216
1218
1219 if not self.HostInterface.sessions[session]['stream_mode']:
1220 return False,'not in stream mode'
1221 if not myargs:
1222 return False,'no stream sent'
1223
1224 compression = self.HostInterface.sessions[session]['compression']
1225
1226 stream = myargs[0]
1227 stream_path = self.HostInterface.sessions[session]['stream_path']
1228 stream_dir = os.path.dirname(stream_path)
1229 if not os.path.isdir(os.path.dirname(stream_path)):
1230 try:
1231 os.makedirs(stream_dir)
1232 if etpConst['entropygid'] != None:
1233 const_setup_perms(stream_dir,etpConst['entropygid'])
1234 except OSError:
1235 return False,'cannot initialize stream directory'
1236
1237 f = open(stream_path,'abw')
1238 if compression:
1239 stream = self.zlib.decompress(stream)
1240 f.write(stream)
1241 f.flush()
1242 f.close()
1243
1244 return True,'ok'
1245
1246 - def docmd_login(self, transmitter, authenticator, session, client_address, myargs):
1247
1248
1249 auth_uid = self.HostInterface.sessions[session]['auth_uid']
1250 if auth_uid != None:
1251 return False,"already authenticated"
1252
1253 status, user, uid, reason = authenticator.docmd_login(myargs)
1254 if status:
1255 self.HostInterface.updateProgress(
1256 '[from: %s] user %s logged in successfully, session: %s' % (
1257 client_address,
1258 user,
1259 session,
1260 )
1261 )
1262 self.HostInterface.sessions[session]['auth_uid'] = uid
1263 transmitter(self.HostInterface.answers['ok'])
1264 return True,reason
1265 elif user == None:
1266 self.HostInterface.updateProgress(
1267 '[from: %s] user -not specified- login failed, session: %s, reason: %s' % (
1268 client_address,
1269 session,
1270 reason,
1271 )
1272 )
1273 transmitter(self.HostInterface.answers['no'])
1274 return False,reason
1275 else:
1276 self.HostInterface.updateProgress(
1277 '[from: %s] user %s login failed, session: %s, reason: %s' % (
1278 client_address,
1279 user,
1280 session,
1281 reason,
1282 )
1283 )
1284 transmitter(self.HostInterface.answers['no'])
1285 return False,reason
1286
1288
1289 auth_uid = self.HostInterface.sessions[session]['auth_uid']
1290 if auth_uid == None:
1291 return False,None,"not authenticated"
1292
1293 return authenticator.docmd_userdata()
1294
1295 - def docmd_logout(self, transmitter, authenticator, session, client_address, myargs):
1296 status, user, reason = authenticator.docmd_logout(myargs)
1297 if status:
1298 self.HostInterface.updateProgress(
1299 '[from: %s] user %s logged out successfully, session: %s, args: %s ' % (
1300 client_address,
1301 user,
1302 session,
1303 myargs,
1304 )
1305 )
1306 self.HostInterface.sessions[session]['auth_uid'] = None
1307 transmitter(self.HostInterface.answers['ok'])
1308 return True,reason
1309 elif user == None:
1310 self.HostInterface.updateProgress(
1311 '[from: %s] user -not specified- logout failed, session: %s, args: %s, reason: %s' % (
1312 client_address,
1313 session,
1314 myargs,
1315 reason,
1316 )
1317 )
1318 transmitter(self.HostInterface.answers['no'])
1319 return False,reason
1320 else:
1321 self.HostInterface.updateProgress(
1322 '[from: %s] user %s logout failed, session: %s, args: %s, reason: %s' % (
1323 client_address,
1324 user,
1325 session,
1326 myargs,
1327 reason,
1328 )
1329 )
1330 transmitter(self.HostInterface.answers['no'])
1331 return False,reason
1332
1333 - def docmd_alive(self, transmitter, client_address, myargs):
1334 cmd = self.HostInterface.answers['no']
1335 alive = False
1336 if myargs:
1337 session_data = self.HostInterface.sessions.get(myargs[0])
1338 if session_data != None:
1339 if client_address[0] == session_data.get('ip_address'):
1340 cmd = self.HostInterface.answers['ok']
1341 alive = True
1342 transmitter(cmd)
1343 return alive
1344
1346 from entropy.tools import getstatusoutput
1347 from entropy.core import SystemSettings
1348 sys_settings = SystemSettings()
1349 uname = os.uname()
1350 kern_string = uname[2]
1351 running_host = uname[1]
1352 running_arch = uname[4]
1353 load_stats = getstatusoutput('uptime')[1].split("\n")[0]
1354 text = "Entropy Server %s, connections: %s ~ running on: %s ~ host: %s ~ arch: %s, kernel: %s, stats: %s\n" % (
1355 etpConst['entropyversion'],
1356 self.HostInterface.connections,
1357 sys_settings['system']['name'],
1358 running_host,
1359 running_arch,
1360 kern_string,
1361 load_stats
1362 )
1363 transmitter(text)
1364
1366 text = '\nEntropy Socket Interface Help Menu\n' + \
1367 'Available Commands:\n\n'
1368 valid_cmds = sorted(self.HostInterface.valid_commands.keys())
1369 for cmd in valid_cmds:
1370 if self.HostInterface.valid_commands[cmd].has_key('desc'):
1371 desc = self.HostInterface.valid_commands[cmd]['desc']
1372 else:
1373 desc = 'no description available'
1374
1375 if self.HostInterface.valid_commands[cmd].has_key('syntax'):
1376 syntax = self.HostInterface.valid_commands[cmd]['syntax']
1377 else:
1378 syntax = 'no syntax available'
1379 if self.HostInterface.valid_commands[cmd].has_key('from'):
1380 myfrom = self.HostInterface.valid_commands[cmd]['from']
1381 else:
1382 myfrom = 'N/A'
1383 text += "[%s] %s\n %s: %s\n %s: %s\n" % (
1384 myfrom,
1385 blue(cmd),
1386 red("description"),
1387 desc.strip(),
1388 darkgreen("syntax"),
1389 syntax,
1390 )
1391 transmitter(text)
1392
1394 rc = self.HostInterface.destroy_session(session)
1395 cmd = self.HostInterface.answers['no']
1396 if rc: cmd = self.HostInterface.answers['ok']
1397 transmitter(cmd)
1398 return rc
1399
1401 session = self.HostInterface.get_new_session(client_address[0])
1402 transmitter(session)
1403 return session
1404
1405 - def docmd_rc(self, transmitter, session):
1406 rc = self.HostInterface.get_rc(session)
1407 comp = self.HostInterface.sessions[session]['compression']
1408 myserialized = self.dumpTools.serialize_string(rc)
1409 if comp == "zlib":
1410 myserialized = self.zlib.compress(myserialized, 7)
1411 elif comp == "gzip":
1412 import gzip
1413 try:
1414 import cStringIO as stringio
1415 except ImportError:
1416 import StringIO as stringio
1417 f = stringio.StringIO()
1418 self.dumpTools.serialize(rc, f)
1419 myf = stringio.StringIO()
1420 mygz = gzip.GzipFile(
1421 mode = 'wb',
1422 fileobj = myf
1423 )
1424 f.seek(0)
1425 chunk = f.read(8192)
1426 while chunk:
1427 mygz.write(chunk)
1428 chunk = f.read(8192)
1429 mygz.flush()
1430 mygz.close()
1431 myserialized = myf.getvalue()
1432 f.close()
1433 myf.close()
1434
1435
1436 transmitter(myserialized)
1437
1438 return rc
1439
1440 - def __init__(self, service_interface, *args, **kwds):
1441
1442 import gc
1443 self.gc = gc
1444 import threading
1445 self.threading = threading
1446 import entropy.tools as entropyTools
1447 from entropy.misc import TimeScheduled
1448 self.TimeScheduled = TimeScheduled
1449 self.entropyTools = entropyTools
1450 self.Server = None
1451 self.Gc = None
1452 self.PythonGarbageCollector = None
1453 self.AuthenticatorInst = None
1454
1455 self.args = args
1456 self.kwds = kwds
1457 from entropy.misc import LogFile
1458 self.socketLog = LogFile(
1459 level = etpConst['socketloglevel'],
1460 filename = etpConst['socketlogfile'],
1461 header = "[Socket]"
1462 )
1463
1464
1465 from entropy.core import SystemSettings
1466 import copy
1467 """
1468 SystemSettings is a singleton, and we just need to read
1469 socket configuration. we don't want to mess other instances
1470 so we pay attention to not use it more than what is needed.
1471 """
1472 sys_settings = SystemSettings()
1473 self.__socket_settings = copy.deepcopy(sys_settings['socket_service'])
1474
1475 self.SessionsLock = self.threading.Lock()
1476 self.fork_requests = True
1477 self.fork_request_timeout_seconds = self.__socket_settings['forked_requests_timeout']
1478 self.stdout_logging = True
1479 self.timeout = self.__socket_settings['timeout']
1480 self.hostname = self.__socket_settings['hostname']
1481 self.session_ttl = self.__socket_settings['session_ttl']
1482 if self.hostname == "*": self.hostname = ''
1483 self.port = self.__socket_settings['port']
1484 self.threads = self.__socket_settings['threads']
1485 self.max_connections = self.__socket_settings['max_connections']
1486 self.max_connections_per_host = self.__socket_settings['max_connections_per_host']
1487 self.max_connections_per_host_barrier = self.__socket_settings['max_connections_per_host_barrier']
1488 self.max_command_length = self.__socket_settings['max_command_length']
1489 self.disabled_commands = self.__socket_settings['disabled_cmds']
1490 self.ip_blacklist = self.__socket_settings['ip_blacklist']
1491 self.answers = self.__socket_settings['answers']
1492 self.connections = 0
1493 self.per_host_connections = {}
1494 self.sessions = {}
1495 self.__output = None
1496 self.SSL = {}
1497 self.SSL_exceptions = {}
1498 self.SSL_exceptions['WantReadError'] = None
1499 self.SSL_exceptions['WantWriteError'] = None
1500 self.SSL_exceptions['WantX509LookupError'] = None
1501 self.SSL_exceptions['ZeroReturnError'] = None
1502 self.SSL_exceptions['SysCallError'] = None
1503 self.SSL_exceptions['Error'] = []
1504 self.last_print = ''
1505 self.valid_commands = {}
1506 self.no_acked_commands = []
1507 self.raw_commands = []
1508 self.config_commands = []
1509 self.termination_commands = []
1510 self.initialization_commands = []
1511 self.login_pass_commands = []
1512 self.no_session_commands = []
1513 self.command_classes = [self.BuiltInCommands]
1514 self.command_instances = []
1515 self.EntropyInstantiation = (service_interface, self.args, self.kwds)
1516
1517 self.setup_external_command_classes()
1518 self.start_local_output_interface()
1519 self.setup_authenticator()
1520 self.setup_hostname()
1521 self.setup_commands()
1522 self.disable_commands()
1523 self.start_session_garbage_collector()
1524 self.setup_ssl()
1525 self.start_python_garbage_collector()
1526
1528 if hasattr(self,'socketLog'):
1529 self.socketLog.close()
1530 if self.Server != None:
1531 self.Server.alive = False
1532 if self.Gc != None:
1533 self.Gc.kill()
1534 if self.PythonGarbageCollector != None:
1535 self.PythonGarbageCollector.kill()
1536
1538 return str(len(data)) + \
1539 self.answers['eos'] + \
1540 data
1541
1543
1544 do_ssl = False
1545 if self.kwds.has_key('ssl'):
1546 do_ssl = self.kwds.pop('ssl')
1547
1548 if not do_ssl:
1549 return
1550
1551 try:
1552 from OpenSSL import SSL, crypto
1553 except ImportError, e:
1554 self.updateProgress('Unable to load OpenSSL, error: %s' % (repr(e),))
1555 return
1556 self.SSL_exceptions['WantReadError'] = SSL.WantReadError
1557 self.SSL_exceptions['Error'] = SSL.Error
1558 self.SSL_exceptions['WantWriteError'] = SSL.WantWriteError
1559 self.SSL_exceptions['WantX509LookupError'] = SSL.WantX509LookupError
1560 self.SSL_exceptions['ZeroReturnError'] = SSL.ZeroReturnError
1561 self.SSL_exceptions['SysCallError'] = SSL.SysCallError
1562 self.SSL['m'] = SSL
1563 self.SSL['crypto'] = crypto
1564 self.SSL['key'] = self.__socket_settings['ssl_key']
1565 self.SSL['cert'] = self.__socket_settings['ssl_cert']
1566 self.SSL['ca_cert'] = self.__socket_settings['ssl_ca_cert']
1567 self.SSL['ca_pkey'] = self.__socket_settings['ssl_ca_pkey']
1568
1569 self.port = self.__socket_settings['ssl_port']
1570 self.SSL['not_before'] = 0
1571 self.SSL['not_after'] = 60*60*24*365*5
1572 self.SSL['serial'] = 0
1573 self.SSL['digest'] = 'md5'
1574
1575 if not (os.path.isfile(self.SSL['ca_cert']) and \
1576 os.path.isfile(self.SSL['ca_pkey']) and \
1577 os.path.isfile(self.SSL['key']) and \
1578 os.path.isfile(self.SSL['cert'])):
1579 self.create_ca_server_certs(
1580 self.SSL['serial'],
1581 self.SSL['digest'],
1582 self.SSL['not_before'],
1583 self.SSL['not_after'],
1584 self.SSL['ca_pkey'],
1585 self.SSL['ca_cert'],
1586 self.SSL['key'],
1587 self.SSL['cert']
1588 )
1589 os.chmod(self.SSL['ca_cert'],0644)
1590 try:
1591 os.chown(self.SSL['ca_cert'],-1,0)
1592 except OSError:
1593 pass
1594 os.chmod(self.SSL['ca_pkey'],0600)
1595 try:
1596 os.chown(self.SSL['ca_pkey'],-1,0)
1597 except OSError:
1598 pass
1599
1600 os.chmod(self.SSL['key'],0600)
1601 try:
1602 os.chown(self.SSL['key'],-1,0)
1603 except OSError:
1604 pass
1605 os.chmod(self.SSL['cert'],0644)
1606 try:
1607 os.chown(self.SSL['cert'],-1,0)
1608 except OSError:
1609 pass
1610
1611 - def create_ca_server_certs(self, serial, digest, not_before, not_after, ca_pkey_dest, ca_cert_dest, server_key, server_cert):
1612
1613 mycn = 'Entropy Repository Service'
1614 cakey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1615 careq = self.create_ssl_certificate_request(cakey, digest, CN = mycn)
1616 cert = self.SSL['crypto'].X509()
1617 cert.set_serial_number(serial)
1618 cert.gmtime_adj_notBefore(not_before)
1619 cert.gmtime_adj_notAfter(not_after)
1620 cert.set_issuer(careq.get_subject())
1621 cert.set_subject(careq.get_subject())
1622 cert.sign(cakey, digest)
1623
1624
1625 s_pkey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1626 s_req = self.create_ssl_certificate_request(s_pkey, digest, CN = mycn)
1627 s_cert = self.SSL['crypto'].X509()
1628 s_cert.set_serial_number(serial+1)
1629 s_cert.gmtime_adj_notBefore(not_before)
1630 s_cert.gmtime_adj_notAfter(not_after)
1631 s_cert.set_issuer(cert.get_subject())
1632 s_cert.set_subject(s_req.get_subject())
1633 s_cert.set_pubkey(s_req.get_pubkey())
1634 s_cert.sign(cakey, digest)
1635
1636
1637 if os.path.isfile(ca_pkey_dest):
1638 shutil.move(ca_pkey_dest,ca_pkey_dest+".moved")
1639 f = open(ca_pkey_dest,"w")
1640 f.write(self.SSL['crypto'].dump_privatekey(self.SSL['crypto'].FILETYPE_PEM, cakey))
1641 f.flush()
1642 f.close()
1643 if os.path.isfile(ca_cert_dest):
1644 shutil.move(ca_cert_dest,ca_cert_dest+".moved")
1645 f = open(ca_cert_dest,"w")
1646 f.write(self.SSL['crypto'].dump_certificate(self.SSL['crypto'].FILETYPE_PEM, cert))
1647 f.flush()
1648 f.close()
1649
1650 if os.path.isfile(server_key):
1651 shutil.move(server_key,server_key+".moved")
1652
1653 f = open(server_key,"w")
1654 f.write(self.SSL['crypto'].dump_privatekey(self.SSL['crypto'].FILETYPE_PEM, s_pkey))
1655 f.flush()
1656 f.close()
1657 if os.path.isfile(server_cert):
1658 shutil.move(server_cert,server_cert+".moved")
1659 f = open(server_cert,"w")
1660 f.write(self.SSL['crypto'].dump_certificate(self.SSL['crypto'].FILETYPE_PEM, s_cert))
1661 f.flush()
1662 f.close()
1663
1665 pkey = self.SSL['crypto'].PKey()
1666 pkey.generate_key(keytype, bits)
1667 return pkey
1668
1670 req = self.SSL['crypto'].X509Req()
1671 subj = req.get_subject()
1672 for (key,value) in name.items():
1673 setattr(subj, key, value)
1674 req.set_pubkey(pkey)
1675 req.sign(pkey, digest)
1676 return req
1677
1679
1680 if self.kwds.has_key('external_cmd_classes'):
1681 ext_commands = self.kwds.pop('external_cmd_classes')
1682 if not isinstance(ext_commands,list):
1683 raise InvalidDataType("InvalidDataType: external_cmd_classes must be a list")
1684 self.command_classes += ext_commands
1685
1687
1688 identifiers = set()
1689 for myclass in self.command_classes:
1690
1691 myargs = []
1692 mykwargs = {}
1693 if isinstance(myclass,tuple) or isinstance(myclass,list):
1694 if len(myclass) > 2:
1695 mykwargs = myclass[2]
1696 if len(myclass) > 1:
1697 myargs = myclass[1]
1698 myclass = myclass[0]
1699
1700 myinst = myclass(self, *myargs, **mykwargs)
1701 if str(myinst) in identifiers:
1702 raise PermissionDenied("PermissionDenied: another command instance is owning this name")
1703 identifiers.add(str(myinst))
1704 self.command_instances.append(myinst)
1705
1706 myinst.register( self.valid_commands,
1707 self.no_acked_commands,
1708 self.termination_commands,
1709 self.initialization_commands,
1710 self.login_pass_commands,
1711 self.no_session_commands,
1712 self.raw_commands,
1713 self.config_commands
1714 )
1715
1717 for cmd in self.disabled_commands:
1718
1719 if cmd in self.valid_commands:
1720 self.valid_commands.pop(cmd)
1721
1722 if cmd in self.no_acked_commands:
1723 self.no_acked_commands.remove(cmd)
1724
1725 if cmd in self.termination_commands:
1726 self.termination_commands.remove(cmd)
1727
1728 if cmd in self.initialization_commands:
1729 self.initialization_commands.remove(cmd)
1730
1731 if cmd in self.login_pass_commands:
1732 self.login_pass_commands.remove(cmd)
1733
1734 if cmd in self.no_session_commands:
1735 self.no_session_commands.remove(cmd)
1736
1737 if cmd in self.raw_commands:
1738 self.raw_commands.remove(cmd)
1739
1740 if cmd in self.config_commands:
1741 self.config_commands.remove(cmd)
1742
1744 if self.kwds.has_key('sock_output'):
1745 outputIntf = self.kwds.pop('sock_output')
1746 self.__output = outputIntf
1747
1749
1750
1751 self.AuthenticatorLock = self.threading.Lock()
1752 auth_inst = (self.BasicPamAuthenticator, [self], {},)
1753
1754 if self.kwds.has_key('sock_auth'):
1755 authIntf = self.kwds.pop('sock_auth')
1756 if type(authIntf) is tuple:
1757 if len(authIntf) == 3:
1758 auth_inst = authIntf[:]
1759 else:
1760 raise IncorrectParameter("IncorrectParameter: wront authentication interface specified")
1761 else:
1762 raise IncorrectParameter("IncorrectParameter: wront authentication interface specified")
1763
1764 self.AuthenticatorInst = (auth_inst[0],[self]+auth_inst[1],auth_inst[2],)
1765
1770
1774
1776 self.gc.collect()
1777 self.gc.collect()
1778 self.gc.collect()
1779
1781 if not self.sessions:
1782 return
1783
1784 with self.SessionsLock:
1785 for session_id in self.sessions.keys():
1786 sess_time = self.sessions[session_id]['t']
1787 is_running = self.sessions[session_id]['running']
1788 auth_uid = self.sessions[session_id]['auth_uid']
1789 if (is_running) or (auth_uid == -1):
1790 if auth_uid == -1:
1791 self.updateProgress('not killing session %s, since it is kept alive by auth_uid=-1' % (session_id,) )
1792 continue
1793 cur_time = time.time()
1794 ttl = self.session_ttl
1795 check_time = sess_time + ttl
1796 if cur_time > check_time:
1797 self.updateProgress('killing session %s, ttl: %ss: no activity' % (session_id,ttl,) )
1798 self._destroy_session(session_id)
1799
1801 if self.hostname:
1802 try:
1803 self.hostname = self.get_ip_address(self.hostname)
1804 except IOError:
1805 pass
1806
1808 import fcntl
1809 import struct
1810 mysock = self.socket.socket ( self.socket.AF_INET, self.socket.SOCK_STREAM )
1811 return self.socket.inet_ntoa(fcntl.ioctl(mysock.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
1812
1814 import hashlib
1815 m = hashlib.md5()
1816 m.update(os.urandom(2))
1817 m.update(salt)
1818 return m.hexdigest()
1819
1821 with self.SessionsLock:
1822 if len(self.sessions) > self.threads:
1823
1824 return "0"
1825 rng = self.get_md5_hash(str(ip_address))
1826 while rng in self.sessions:
1827 rng = self.get_md5_hash(str(ip_address))
1828 self.sessions[rng] = {}
1829 self.sessions[rng]['running'] = False
1830 self.sessions[rng]['auth_uid'] = None
1831 self.sessions[rng]['admin'] = False
1832 self.sessions[rng]['moderator'] = False
1833 self.sessions[rng]['user'] = False
1834 self.sessions[rng]['developer'] = False
1835 self.sessions[rng]['compression'] = None
1836 self.sessions[rng]['stream_mode'] = False
1837 try:
1838 self.sessions[rng]['stream_path'] = self.entropyTools.get_random_temp_file()
1839 except (IOError,OSError,):
1840 self.sessions[rng]['stream_path'] = ''
1841 self.sessions[rng]['t'] = time.time()
1842 self.sessions[rng]['ip_address'] = ip_address
1843 return rng
1844
1846 with self.SessionsLock:
1847 if self.sessions.has_key(session):
1848 self.sessions[session]['t'] = time.time()
1849 self.updateProgress('session time updated for %s' % (session,) )
1850
1852 with self.SessionsLock:
1853 if self.sessions.has_key(session):
1854 self.sessions[session]['running'] = True
1855
1857 with self.SessionsLock:
1858 if self.sessions.has_key(session):
1859 self.sessions[session]['running'] = False
1860
1862 with self.SessionsLock:
1863 self._destroy_session(session)
1864
1866 if self.sessions.has_key(session):
1867 stream_path = self.sessions[session]['stream_path']
1868 del self.sessions[session]
1869 if os.path.isfile(stream_path) and os.access(stream_path,os.W_OK) and not os.path.islink(stream_path):
1870 try: os.remove(stream_path)
1871 except OSError: pass
1872 return True
1873 return False
1874
1876 self.socket.setdefaulttimeout(self.timeout)
1877 while 1:
1878 try:
1879 self.Server = self.HostServerMixin(
1880 (self.hostname, self.port),
1881 self.RequestHandler,
1882 self.CommandProcessor(self),
1883 self
1884 )
1885 break
1886 except self.socket.error, e:
1887 if e[0] == 98:
1888
1889 self.updateProgress('address already in use (%s, port: %s), waiting 5 seconds...' % (self.hostname,self.port,))
1890 time.sleep(5)
1891 continue
1892 else:
1893 raise
1894 self.updateProgress('server connected, listening on: %s, port: %s, timeout: %s' % (self.hostname,self.port,self.timeout,))
1895 self.Server.serve_forever()
1896 self.Gc.kill()
1897
1899 with self.SessionsLock:
1900 if session in self.sessions:
1901 if type(rc) in (list,tuple,):
1902 rc_item = rc[:]
1903 elif type(rc) in (set,frozenset,dict,):
1904 rc_item = rc.copy()
1905 else:
1906 rc_item = rc
1907 self.sessions[session]['rc'] = rc_item
1908
1910 with self.SessionsLock:
1911 if session in self.sessions:
1912 return self.sessions[session].get('rc')
1913
1915 if self.SSL:
1916 mydata = self.append_eos(data)
1917 encode_done = False
1918 while 1:
1919 try:
1920 sent = channel.send(mydata)
1921 if sent == len(mydata):
1922 break
1923 mydata = mydata[sent:]
1924 except (self.SSL_exceptions['WantWriteError'],self.SSL_exceptions['WantReadError']):
1925 time.sleep(0.2)
1926 continue
1927 except UnicodeEncodeError:
1928 if encode_done:
1929 raise
1930 mydata = mydata.encode('utf-8')
1931 encode_done = True
1932 continue
1933 else:
1934 channel.sendall(self.append_eos(data))
1935
1937 message = args[0]
1938 if message != self.last_print:
1939 self.socketLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,str(args[0]))
1940 if self.__output != None and self.stdout_logging:
1941 self.__output.updateProgress(*args,**kwargs)
1942 self.last_print = message
1943