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