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.server = None
395 self.request = None
396 self.client_address = None
397 self.SocketServer.BaseRequestHandler.__init__(self, request,
398 client_address, server)
399
401
402 if self.timed_out:
403 return True
404 self.timed_out = True
405 try:
406 ready_to_read, ready_to_write, in_error = self.select.select(
407 [self.request], [], [], self.default_timeout)
408 except KeyboardInterrupt:
409 self.timed_out = True
410 return True
411
412 if len(ready_to_read) == 1 and ready_to_read[0] == self.request:
413
414 self.timed_out = False
415
416 try:
417
418 data = self.request.recv(1024)
419 if self.ssl:
420 while self.request.pending():
421 data += self.request.recv(1024)
422
423 if self.data_counter == None:
424 if data == '':
425 return True
426 elif data == self.server.processor.HostInterface.answers['noop']:
427 return False
428 elif len(data) < len(self.myeos):
429 self.server.processor.HostInterface.updateProgress(
430 'interrupted: %s, reason: %s - from client: %s - data: "%s" - counter: %s' % (
431 self.server.server_address,
432 "malformed EOS",
433 self.client_address,
434 repr(data),
435 self.data_counter,
436 )
437 )
438 self.buffered_data = ''
439 return True
440 mystrlen = data.split(self.myeos)[0]
441 self.data_counter = int(mystrlen)
442 data = data[len(mystrlen)+1:]
443 self.data_counter -= len(data)
444 self.buffered_data += data
445
446
447 if self.data_counter > self.max_command_length:
448 raise InterruptError('InterruptError: command too long: %s, limit: %s' % (self.data_counter,self.max_command_length,))
449
450 while self.data_counter > 0:
451 if self.ssl:
452 x = ''
453 while self.request.pending():
454 x += self.request.recv(1024)
455 else:
456 x = self.request.recv(1024)
457 xlen = len(x)
458 self.data_counter -= xlen
459 self.buffered_data += x
460 if not xlen:
461 break
462
463 self.data_counter = None
464 except ValueError:
465 self.entropyTools.print_traceback()
466 self.server.processor.HostInterface.updateProgress(
467 'interrupted: %s, reason: %s - from client: %s' % (
468 self.server.server_address,
469 "malformed transmission",
470 self.client_address,
471 )
472 )
473 return True
474 except self.socket.timeout, e:
475 self.server.processor.HostInterface.updateProgress(
476 'interrupted: %s, reason: %s - from client: %s' % (
477 self.server.server_address,
478 e,
479 self.client_address,
480 )
481 )
482 return True
483 except self.socket.sslerror, e:
484 self.server.processor.HostInterface.updateProgress(
485 'interrupted: %s, SSL socket error reason: %s - from client: %s' % (
486 self.server.server_address,
487 e,
488 self.client_address,
489 )
490 )
491 return True
492 except (self.ssl_exceptions['WantReadError'], self.ssl_exceptions['WantX509LookupError'],):
493 return False
494 except self.ssl_exceptions['ZeroReturnError']:
495 return True
496 except self.ssl_exceptions['Error'], e:
497 self.server.processor.HostInterface.updateProgress(
498 'interrupted: SSL Error, reason: %s - from client: %s' % (
499 e,
500 self.client_address,
501 )
502 )
503 return True
504 except InterruptError, e:
505 self.server.processor.HostInterface.updateProgress(
506 'interrupted: Command Error, reason: %s - from client: %s' % (
507 e,
508 self.client_address,
509 )
510 )
511 return True
512
513 if not self.buffered_data:
514 return True
515
516 cmd = self.server.processor.process(self.buffered_data, self.request, self.client_address)
517 if cmd == 'close':
518
519 self.server.processor.transmit(self.server.processor.HostInterface.answers['cl'])
520 return True
521 self.buffered_data = ''
522 return False
523
525 if hasattr(self.server.processor.HostInterface,'ForkLock'):
526 x = getattr(self.server.processor.HostInterface,'ForkLock')
527 if hasattr(x,'acquire') and hasattr(x,'release') and hasattr(x,'locked'):
528 x.acquire()
529
531 if hasattr(self.server.processor.HostInterface,'ForkLock'):
532 x = getattr(self.server.processor.HostInterface,'ForkLock')
533 if hasattr(x,'acquire') and hasattr(x,'release') and hasattr(x,'locked'):
534 if x.locked(): x.release()
535
537
538
539 if self.server.processor.HostInterface.fork_requests:
540 self.fork_lock_acquire()
541 try:
542 my_timeout = self.server.processor.HostInterface.fork_request_timeout_seconds
543 pid = os.fork()
544 seconds = 0
545 if pid > 0:
546
547 passed_away = False
548 while 1:
549 time.sleep(1)
550 seconds += 1
551 try:
552 dead = os.waitpid(pid, os.WNOHANG)[0]
553 except OSError, e:
554 if e.errno != 10: raise
555 dead = True
556 if passed_away:
557 break
558 if dead: break
559 if seconds > my_timeout:
560 self.server.processor.HostInterface.updateProgress(
561 'interrupted: forked request timeout: %s,%s from client: %s' % (
562 seconds,
563 dead,
564 self.client_address,
565 )
566 )
567 if not dead:
568 import signal
569 os.kill(pid,signal.SIGKILL)
570 passed_away = True
571 continue
572 break
573 else:
574 self.do_handle()
575 os._exit(0)
576 finally:
577 self.fork_lock_release()
578 else:
579 self.do_handle()
580
581
583
584 self.default_timeout = self.server.processor.HostInterface.timeout
585 self.ssl = self.server.processor.HostInterface.SSL
586 self.ssl_exceptions = self.server.processor.HostInterface.SSL_exceptions
587 self.myeos = self.server.processor.HostInterface.answers['eos']
588 self.max_command_length = self.server.processor.HostInterface.max_command_length
589
590 while 1:
591
592 try:
593 dobreak = self.data_receiver()
594 if dobreak: break
595 except Exception, e:
596 self.server.processor.HostInterface.updateProgress(
597 'interrupted: Unhandled exception: %s, error: %s - from client: %s' % (
598 Exception,
599 e,
600 self.client_address,
601 )
602 )
603
604 tb = self.entropyTools.get_traceback()
605 print tb
606 self.server.processor.HostInterface.socketLog.write(tb)
607 break
608
609 self.request.close()
610
612 self.data_counter = None
613 self.buffered_data = ''
614
615
617
618 import entropy.tools as entropyTools
619 import socket
620 import gc
621
623 self.HostInterface = HostInterface
624 self.channel = None
625
627 if data.strip() in self.HostInterface.termination_commands:
628 self.HostInterface.updateProgress('close: %s' % (self.client_address,))
629 self.transmit(self.HostInterface.answers['cl'])
630 return "close"
631
632 if not data.strip():
633 return "ignore"
634
636
637 args = string.strip().split(" ")
638 session = args[0]
639 if (session in self.HostInterface.initialization_commands) or \
640 (session in self.HostInterface.no_session_commands) or \
641 len(args) < 2:
642 cmd = args[0]
643 session = None
644 else:
645 cmd = args[1]
646 args = args[1:]
647
648 stream_enabled = False
649 if (session != None) and self.HostInterface.sessions.has_key(session):
650 stream_enabled = self.HostInterface.sessions[session].get('stream_mode')
651
652 if stream_enabled and (cmd not in self.HostInterface.config_commands):
653 session_len = 0
654 if session: session_len = len(session)+1
655 return cmd,[string[session_len+len(cmd)+1:]],session
656 else:
657 myargs = []
658 if len(args) > 1:
659 myargs = args[1:]
660
661 return cmd,myargs,session
662
664 if not valid_cmd:
665 self.transmit(self.HostInterface.answers['no'])
666 elif whoops:
667 self.transmit(self.HostInterface.answers['er'])
668 elif cmd not in self.HostInterface.no_acked_commands:
669 self.transmit(self.HostInterface.answers['ok'])
670
672
673
674 if (cmd not in self.HostInterface.valid_commands):
675 return False,"not a valid command"
676
677 if session == None:
678 if cmd not in self.HostInterface.no_session_commands:
679 return False,"need a valid session"
680 elif session not in self.HostInterface.sessions:
681 return False,"session is not alive"
682
683
684 if session != None:
685 auth = self.HostInterface.valid_commands[cmd]['auth']
686 if auth:
687
688 authed = self.HostInterface.sessions[session]['auth_uid']
689 if authed == None:
690
691 return False,"not authenticated"
692
693
694 if session != None:
695 self.HostInterface.set_session_running(session)
696 self.HostInterface.update_session_time(session)
697
698 return True,"all good"
699
701 f, args, kwargs = self.HostInterface.AuthenticatorInst
702 myinst = f(*args,**kwargs)
703 return myinst
704
706
707 uid = None
708 if session != None:
709 uid = self.HostInterface.sessions[session]['auth_uid']
710
711 intf = self.HostInterface.EntropyInstantiation[0]
712 args = self.HostInterface.EntropyInstantiation[1]
713 kwds = self.HostInterface.EntropyInstantiation[2]
714 return intf(*args, **kwds)
715
716 - def process(self, data, channel, client_address):
717
718 self.channel = channel
719 self.client_address = client_address
720
721 term = self.handle_termination_commands(data)
722 if term:
723 del authenticator
724 return term
725
726 cmd, args, session = self.handle_command_string(data)
727 valid_cmd, reason = self.validate_command(cmd, args, session)
728
729
730 authenticator = None
731 cmd_data = self.HostInterface.valid_commands.get(cmd)
732 if not isinstance(cmd_data,dict):
733 self.HostInterface.updateProgress(
734 '[from: %s] command error: invalid command: %s' % (
735 self.client_address,
736 cmd,
737 )
738 )
739 return "close"
740 elif (("authenticator" in cmd_data['args']) or (cmd in self.HostInterface.login_pass_commands)):
741 try:
742 authenticator = self.load_authenticator()
743 except ConnectionError, e:
744 self.HostInterface.updateProgress(
745 '[from: %s] authenticator error: cannot load: %s' % (
746 self.client_address,
747 e,
748 )
749 )
750 tb = self.entropyTools.get_traceback()
751 print tb
752 self.HostInterface.socketLog.write(tb)
753 return "close"
754 except Exception, e:
755 self.HostInterface.updateProgress(
756 '[from: %s] authenticator error: cannot load: %s - unknown error' % (
757 self.client_address,
758 e,
759 )
760 )
761 tb = self.entropyTools.get_traceback()
762 print tb
763 self.HostInterface.socketLog.write(tb)
764 return "close"
765
766 p_args = args
767 if (cmd in self.HostInterface.login_pass_commands) and authenticator != None:
768 p_args = authenticator.hide_login_data(p_args)
769 elif cmd in self.HostInterface.raw_commands:
770 p_args = ['raw data']
771 self.HostInterface.updateProgress(
772 '[from: %s] command validation :: called %s: length: %s, args: %s, session: %s, valid: %s, reason: %s' % (
773 self.client_address,
774 cmd,
775 len(data),
776 p_args,
777 session,
778 valid_cmd,
779 reason,
780 )
781 )
782
783 whoops = False
784 if valid_cmd:
785
786 if authenticator != None:
787
788 authenticator.set_session(session)
789
790 Entropy = None
791 if "Entropy" in cmd_data['args']:
792 Entropy = self.load_service_interface(session)
793 try:
794 self.run_task(cmd, args, session, Entropy, authenticator)
795 except self.socket.timeout:
796 self.HostInterface.updateProgress(
797 '[from: %s] command error: timeout, closing connection' % (
798 self.client_address,
799 )
800 )
801
802 del authenticator
803 del Entropy
804 return "close"
805 except self.socket.error, e:
806 self.HostInterface.updateProgress(
807 '[from: %s] command error: socket error: %s' % (
808 self.client_address,
809 e,
810 )
811 )
812
813 del authenticator
814 del Entropy
815 return "close"
816 except self.HostInterface.SSL_exceptions['SysCallError'], e:
817 self.HostInterface.updateProgress(
818 '[from: %s] command error: SSL SysCallError: %s' % (
819 self.client_address,
820 e,
821 )
822 )
823
824 del authenticator
825 del Entropy
826 return "close"
827 except Exception, e:
828
829 tb = self.entropyTools.get_traceback()
830 print tb
831 self.HostInterface.socketLog.write(tb)
832
833 self.HostInterface.updateProgress(
834 '[from: %s] command error: %s, type: %s' % (
835 self.client_address,
836 e,
837 type(e),
838 )
839 )
840 if session != None:
841 self.HostInterface.store_rc(str(e),session)
842 whoops = True
843
844 del Entropy
845
846 if session != None:
847 self.HostInterface.update_session_time(session)
848 self.HostInterface.unset_session_running(session)
849 rcmd = None
850 try:
851 self.handle_end_answer(cmd, whoops, valid_cmd)
852 except (self.socket.error, self.socket.timeout,self.HostInterface.SSL_exceptions['SysCallError'],):
853 rcmd = "close"
854
855 if authenticator != None:
856 authenticator.terminate_instance()
857 del authenticator
858 if not self.HostInterface.fork_requests:
859 self.gc.collect()
860 return rcmd
861
863 self.HostInterface.transmit(self.channel, data)
864
865 - def run_task(self, cmd, args, session, Entropy, authenticator):
866
867 p_args = args
868 if cmd in self.HostInterface.login_pass_commands:
869 p_args = authenticator.hide_login_data(p_args)
870 elif cmd in self.HostInterface.raw_commands:
871 p_args = ['raw data']
872 self.HostInterface.updateProgress(
873 '[from: %s] run_task :: called %s: args: %s, session: %s' % (
874 self.client_address,
875 cmd,
876 p_args,
877 session,
878 )
879 )
880
881 myargs = args
882 mykwargs = {}
883 if cmd not in self.HostInterface.raw_commands:
884 myargs, mykwargs = self._get_args_kwargs(args)
885
886 rc = self.spawn_function(cmd, myargs, mykwargs, session, Entropy, authenticator)
887 if session != None and self.HostInterface.sessions.has_key(session):
888 self.HostInterface.store_rc(rc, session)
889 return rc
890
892 myargs = []
893 mykwargs = {}
894
895 def is_int(x):
896 try:
897 int(x)
898 except ValueError:
899 return False
900 return True
901
902 for arg in args:
903 if (arg.find("=") != -1) and not arg.startswith("="):
904 x = arg.split("=")
905 a = x[0]
906 b = ''.join(x[1:])
907 if (b in ("True","False",)) or is_int(b):
908 mykwargs[a] = eval(b)
909 else:
910 myargs.append(arg)
911 else:
912 if (arg in ("True","False",)) or is_int(arg):
913 myargs.append(eval(arg))
914 else:
915 myargs.append(arg)
916 return myargs, mykwargs
917
918 - def spawn_function(self, cmd, myargs, mykwargs, session, Entropy, authenticator):
919
920 p_args = myargs
921 if cmd in self.HostInterface.login_pass_commands:
922 p_args = authenticator.hide_login_data(p_args)
923 elif cmd in self.HostInterface.raw_commands:
924 p_args = ['raw data']
925 self.HostInterface.updateProgress(
926 '[from: %s] called %s: args: %s, kwargs: %s' % (
927 self.client_address,
928 cmd,
929 p_args,
930 mykwargs,
931 )
932 )
933 return self.do_spawn(cmd, myargs, mykwargs, session, Entropy, authenticator)
934
935 - def do_spawn(self, cmd, myargs, mykwargs, session, Entropy, authenticator):
936
937 cmd_data = self.HostInterface.valid_commands.get(cmd)
938 do_fork = cmd_data['as_user']
939 f = cmd_data['cb']
940 func_args = []
941 for arg in cmd_data['args']:
942 try:
943 func_args.append(eval(arg))
944 except (NameError, SyntaxError):
945 func_args.append(str(arg))
946
947 if do_fork:
948 myfargs = func_args[:]
949 myfargs.extend(myargs)
950 return self.fork_task(f, session, authenticator, *myfargs, **mykwargs)
951 else:
952 return f(*func_args)
953
954 - def fork_task(self, f, session, authenticator, *args, **kwargs):
955 gid = None
956 uid = None
957 if session != None:
958 logged_in = self.HostInterface.sessions[session]['auth_uid']
959 if logged_in != None:
960 uid = logged_in
961 gid = etpConst['entropygid']
962 return self.entropyTools.spawn_function(self._do_fork, f, authenticator, uid, gid, *args, **kwargs)
963
964 - def _do_fork(self, f, authenticator, uid, gid, *args, **kwargs):
968
970
971 import entropy.dump as dumpTools
972 import zlib
973
975
976 SocketCommands.__init__(self, HostInterface, inst_name = "builtin")
977
978 self.valid_commands = {
979 'begin': {
980 'auth': False,
981 'built_in': True,
982 'cb': self.docmd_begin,
983 'args': ["self.transmit", "self.client_address"],
984 'as_user': False,
985
986 'desc': "instantiate a session",
987 'syntax': "begin",
988 'from': unicode(self),
989 },
990 'end': {
991 'auth': False,
992 'built_in': True,
993 'cb': self.docmd_end,
994 'args': ["self.transmit", "session"],
995 'as_user': False,
996 'desc': "end a session",
997 'syntax': "<SESSION_ID> end",
998 'from': unicode(self),
999 },
1000 'session_config': {
1001 'auth': False,
1002 'built_in': True,
1003 'cb': self.docmd_session_config,
1004 'args': ["session","myargs"],
1005 'as_user': False,
1006 'desc': "set session configuration options",
1007 'syntax': "<SESSION_ID> session_config <option> [parameters]",
1008 'from': unicode(self),
1009 },
1010 'rc': {
1011 'auth': False,
1012 'built_in': True,
1013 'cb': self.docmd_rc,
1014 'args': ["self.transmit","session"],
1015 'as_user': False,
1016 'desc': "get data returned by the last valid command (streamed python object)",
1017 'syntax': "<SESSION_ID> rc",
1018 'from': unicode(self),
1019 },
1020 'hello': {
1021 'auth': False,
1022 'built_in': True,
1023 'cb': self.docmd_hello,
1024 'args': ["self.transmit"],
1025 'as_user': False,
1026 'desc': "get server status",
1027 'syntax': "hello",
1028 'from': unicode(self),
1029 },
1030 'alive': {
1031 'auth': True,
1032 'built_in': True,
1033 'cb': self.docmd_alive,
1034 'args': ["self.transmit","self.client_address","myargs"],
1035 'as_user': False,
1036 'desc': "check if a session is still alive",
1037 'syntax': "alive <SESSION_ID>",
1038 'from': unicode(self),
1039 },
1040 'login': {
1041 'auth': False,
1042 'built_in': True,
1043 'cb': self.docmd_login,
1044 'args': ["self.transmit", "authenticator", "session", "self.client_address", "myargs"],
1045 'as_user': False,
1046 'desc': "login on the running server (allows running extra commands)",
1047 'syntax': "<SESSION_ID> login <authenticator parameters, default: <user> <auth_type> <password> >",
1048 'from': unicode(self),
1049 },
1050 'user_data': {
1051 'auth': True,
1052 'built_in': True,
1053 'cb': self.docmd_userdata,
1054 'args': ["self.transmit", "authenticator", "session"],
1055 'as_user': False,
1056 'desc': "get general user information, user must be logged in",
1057 'syntax': "<SESSION_ID> user_data",
1058 'from': unicode(self),
1059 },
1060 'logout': {
1061 'auth': True,
1062 'built_in': True,
1063 'cb': self.docmd_logout,
1064 'args': ["self.transmit", "authenticator", "session", "self.client_address", "myargs"],
1065 'as_user': False,
1066 'desc': "logout on the running server",
1067 'syntax': "<SESSION_ID> logout <USER>",
1068 'from': unicode(self),
1069 },
1070 'help': {
1071 'auth': False,
1072 'built_in': True,
1073 'cb': self.docmd_help,
1074 'args': ["self.transmit"],
1075 'as_user': False,
1076 'desc': "this output",
1077 'syntax': "help",
1078 'from': unicode(self),
1079 },
1080 'available_commands': {
1081 'auth': False,
1082 'built_in': True,
1083 'cb': self.docmd_available_commands,
1084 'args': ["self.HostInterface"],
1085 'as_user': False,
1086 'desc': "get info about available commands (you must retrieve this using the 'rc' command)",
1087 'syntax': "available_commands",
1088 'from': unicode(self),
1089 },
1090 'stream': {
1091 'auth': True,
1092 'built_in': True,
1093 'cb': self.docmd_stream,
1094 'args': ["session", "myargs"],
1095 'as_user': False,
1096 'desc': "send a chunk of data to be saved on the session temp file path (will be removed on session expiration)",
1097 'syntax': "<SESSION_ID> stream <chunk of byte-string to write to file>",
1098 'from': unicode(self),
1099 },
1100 }
1101
1102 self.no_acked_commands = ["rc", "begin", "end", "hello", "alive", "login", "logout","help"]
1103 self.termination_commands = ["quit","close"]
1104 self.initialization_commands = ["begin"]
1105 self.login_pass_commands = ["login"]
1106 self.no_session_commands = ["begin","hello","alive","help"]
1107 self.raw_commands = ["stream"]
1108 self.config_commands = ["session_config"]
1109
1111
1112 if not myargs:
1113 return False,"not enough parameters"
1114
1115 option = myargs[0]
1116 myopts = myargs[1:]
1117
1118 if option == "compression":
1119 docomp = True
1120 do_zlib = False
1121 if "zlib" in myopts:
1122 do_zlib = True
1123 if myopts:
1124 if isinstance(myopts[0],bool):
1125 docomp = myopts[0]
1126 else:
1127 try:
1128 docomp = eval(myopts[0])
1129 except (NameError, TypeError,):
1130 pass
1131 if docomp and do_zlib:
1132 docomp = "zlib"
1133 elif docomp and not do_zlib:
1134 docomp = "gzip"
1135 else:
1136 docomp = None
1137 self.HostInterface.sessions[session]['compression'] = docomp
1138 return True,"compression now: %s" % (docomp,)
1139 elif option == "stream":
1140 dostream = True
1141 if "off" in myopts:
1142 dostream = False
1143 self.HostInterface.sessions[session]['stream_mode'] = dostream
1144 return True,'stream mode: %s' % (dostream,)
1145 else:
1146 return False,"invalid config option"
1147
1149
1150 def copy_obj(obj):
1151 if isinstance(obj,set) or isinstance(obj,dict):
1152 return obj.copy()
1153 elif isinstance(obj,list) or isinstance(obj,tuple):
1154 return obj[:]
1155 return obj
1156
1157 def can_be_streamed(obj):
1158 if isinstance(obj,(bool,basestring,int,float,list,tuple,set,dict,)):
1159 return True
1160 return False
1161
1162 mydata = {}
1163 mydata['disabled_commands'] = copy_obj(host_interface.disabled_commands)
1164 valid_cmds = copy_obj(host_interface.valid_commands)
1165 mydata['valid_commands'] = {}
1166 for cmd in valid_cmds:
1167 mydict = {}
1168 for item in valid_cmds[cmd]:
1169 param = valid_cmds[cmd][item]
1170 if not can_be_streamed(param):
1171 continue
1172 mydict[item] = param
1173 mydata['valid_commands'][cmd] = mydict.copy()
1174
1175 return mydata
1176
1178
1179 if not self.HostInterface.sessions[session]['stream_mode']:
1180 return False,'not in stream mode'
1181 if not myargs:
1182 return False,'no stream sent'
1183
1184 compression = self.HostInterface.sessions[session]['compression']
1185
1186 stream = myargs[0]
1187 stream_path = self.HostInterface.sessions[session]['stream_path']
1188 stream_dir = os.path.dirname(stream_path)
1189 if not os.path.isdir(os.path.dirname(stream_path)):
1190 try:
1191 os.makedirs(stream_dir)
1192 if etpConst['entropygid'] != None:
1193 const_setup_perms(stream_dir,etpConst['entropygid'])
1194 except OSError:
1195 return False,'cannot initialize stream directory'
1196
1197 f = open(stream_path,'abw')
1198 if compression:
1199 stream = self.zlib.decompress(stream)
1200 f.write(stream)
1201 f.flush()
1202 f.close()
1203
1204 return True,'ok'
1205
1206 - def docmd_login(self, transmitter, authenticator, session, client_address, myargs):
1207
1208
1209 auth_uid = self.HostInterface.sessions[session]['auth_uid']
1210 if auth_uid != None:
1211 return False,"already authenticated"
1212
1213 status, user, uid, reason = authenticator.docmd_login(myargs)
1214 if status:
1215 self.HostInterface.updateProgress(
1216 '[from: %s] user %s logged in successfully, session: %s' % (
1217 client_address,
1218 user,
1219 session,
1220 )
1221 )
1222 self.HostInterface.sessions[session]['auth_uid'] = uid
1223 transmitter(self.HostInterface.answers['ok'])
1224 return True,reason
1225 elif user == None:
1226 self.HostInterface.updateProgress(
1227 '[from: %s] user -not specified- login failed, session: %s, reason: %s' % (
1228 client_address,
1229 session,
1230 reason,
1231 )
1232 )
1233 transmitter(self.HostInterface.answers['no'])
1234 return False,reason
1235 else:
1236 self.HostInterface.updateProgress(
1237 '[from: %s] user %s login failed, session: %s, reason: %s' % (
1238 client_address,
1239 user,
1240 session,
1241 reason,
1242 )
1243 )
1244 transmitter(self.HostInterface.answers['no'])
1245 return False,reason
1246
1248
1249 auth_uid = self.HostInterface.sessions[session]['auth_uid']
1250 if auth_uid == None:
1251 return False,None,"not authenticated"
1252
1253 return authenticator.docmd_userdata()
1254
1255 - def docmd_logout(self, transmitter, authenticator, session, client_address, myargs):
1256 status, user, reason = authenticator.docmd_logout(myargs)
1257 if status:
1258 self.HostInterface.updateProgress(
1259 '[from: %s] user %s logged out successfully, session: %s, args: %s ' % (
1260 client_address,
1261 user,
1262 session,
1263 myargs,
1264 )
1265 )
1266 self.HostInterface.sessions[session]['auth_uid'] = None
1267 transmitter(self.HostInterface.answers['ok'])
1268 return True,reason
1269 elif user == None:
1270 self.HostInterface.updateProgress(
1271 '[from: %s] user -not specified- logout failed, session: %s, args: %s, reason: %s' % (
1272 client_address,
1273 session,
1274 myargs,
1275 reason,
1276 )
1277 )
1278 transmitter(self.HostInterface.answers['no'])
1279 return False,reason
1280 else:
1281 self.HostInterface.updateProgress(
1282 '[from: %s] user %s logout failed, session: %s, args: %s, reason: %s' % (
1283 client_address,
1284 user,
1285 session,
1286 myargs,
1287 reason,
1288 )
1289 )
1290 transmitter(self.HostInterface.answers['no'])
1291 return False,reason
1292
1293 - def docmd_alive(self, transmitter, client_address, myargs):
1294 cmd = self.HostInterface.answers['no']
1295 alive = False
1296 if myargs:
1297 session_data = self.HostInterface.sessions.get(myargs[0])
1298 if session_data != None:
1299 if client_address[0] == session_data.get('ip_address'):
1300 cmd = self.HostInterface.answers['ok']
1301 alive = True
1302 transmitter(cmd)
1303 return alive
1304
1306 from entropy.tools import getstatusoutput
1307 from entropy.core import SystemSettings
1308 sys_settings = SystemSettings()
1309 uname = os.uname()
1310 kern_string = uname[2]
1311 running_host = uname[1]
1312 running_arch = uname[4]
1313 load_stats = getstatusoutput('uptime')[1].split("\n")[0]
1314 text = "Entropy Server %s, connections: %s ~ running on: %s ~ host: %s ~ arch: %s, kernel: %s, stats: %s\n" % (
1315 etpConst['entropyversion'],
1316 self.HostInterface.connections,
1317 sys_settings['system']['name'],
1318 running_host,
1319 running_arch,
1320 kern_string,
1321 load_stats
1322 )
1323 transmitter(text)
1324
1326 text = '\nEntropy Socket Interface Help Menu\n' + \
1327 'Available Commands:\n\n'
1328 valid_cmds = sorted(self.HostInterface.valid_commands.keys())
1329 for cmd in valid_cmds:
1330 if self.HostInterface.valid_commands[cmd].has_key('desc'):
1331 desc = self.HostInterface.valid_commands[cmd]['desc']
1332 else:
1333 desc = 'no description available'
1334
1335 if self.HostInterface.valid_commands[cmd].has_key('syntax'):
1336 syntax = self.HostInterface.valid_commands[cmd]['syntax']
1337 else:
1338 syntax = 'no syntax available'
1339 if self.HostInterface.valid_commands[cmd].has_key('from'):
1340 myfrom = self.HostInterface.valid_commands[cmd]['from']
1341 else:
1342 myfrom = 'N/A'
1343 text += "[%s] %s\n %s: %s\n %s: %s\n" % (
1344 myfrom,
1345 blue(cmd),
1346 red("description"),
1347 desc.strip(),
1348 darkgreen("syntax"),
1349 syntax,
1350 )
1351 transmitter(text)
1352
1354 rc = self.HostInterface.destroy_session(session)
1355 cmd = self.HostInterface.answers['no']
1356 if rc: cmd = self.HostInterface.answers['ok']
1357 transmitter(cmd)
1358 return rc
1359
1361 session = self.HostInterface.get_new_session(client_address[0])
1362 transmitter(session)
1363 return session
1364
1365 - def docmd_rc(self, transmitter, session):
1366 rc = self.HostInterface.get_rc(session)
1367 comp = self.HostInterface.sessions[session]['compression']
1368 myserialized = self.dumpTools.serialize_string(rc)
1369 if comp == "zlib":
1370 myserialized = self.zlib.compress(myserialized, 7)
1371 elif comp == "gzip":
1372 import gzip
1373 try:
1374 import cStringIO as stringio
1375 except ImportError:
1376 import StringIO as stringio
1377 f = stringio.StringIO()
1378 self.dumpTools.serialize(rc, f)
1379 myf = stringio.StringIO()
1380 mygz = gzip.GzipFile(
1381 mode = 'wb',
1382 fileobj = myf
1383 )
1384 f.seek(0)
1385 chunk = f.read(8192)
1386 while chunk:
1387 mygz.write(chunk)
1388 chunk = f.read(8192)
1389 mygz.flush()
1390 mygz.close()
1391 myserialized = myf.getvalue()
1392 f.close()
1393 myf.close()
1394
1395
1396 transmitter(myserialized)
1397
1398 return rc
1399
1400 - def __init__(self, service_interface, *args, **kwds):
1401
1402 import gc
1403 self.gc = gc
1404 import threading
1405 self.threading = threading
1406 import entropy.tools as entropyTools
1407 from entropy.misc import TimeScheduled
1408 self.TimeScheduled = TimeScheduled
1409 self.entropyTools = entropyTools
1410 self.Server = None
1411 self.Gc = None
1412 self.PythonGarbageCollector = None
1413 self.AuthenticatorInst = None
1414
1415 self.args = args
1416 self.kwds = kwds
1417 from entropy.misc import LogFile
1418 self.socketLog = LogFile(
1419 level = etpConst['socketloglevel'],
1420 filename = etpConst['socketlogfile'],
1421 header = "[Socket]"
1422 )
1423
1424
1425 from entropy.core import SystemSettings
1426 import copy
1427 """
1428 SystemSettings is a singleton, and we just need to read
1429 socket configuration. we don't want to mess other instances
1430 so we pay attention to not use it more than what is needed.
1431 """
1432 sys_settings = SystemSettings()
1433 self.__socket_settings = copy.deepcopy(sys_settings['socket_service'])
1434
1435 self.SessionsLock = self.threading.Lock()
1436 self.fork_requests = True
1437 self.fork_request_timeout_seconds = self.__socket_settings['forked_requests_timeout']
1438 self.stdout_logging = True
1439 self.timeout = self.__socket_settings['timeout']
1440 self.hostname = self.__socket_settings['hostname']
1441 self.session_ttl = self.__socket_settings['session_ttl']
1442 if self.hostname == "*": self.hostname = ''
1443 self.port = self.__socket_settings['port']
1444 self.threads = self.__socket_settings['threads']
1445 self.max_connections = self.__socket_settings['max_connections']
1446 self.max_connections_per_host = self.__socket_settings['max_connections_per_host']
1447 self.max_connections_per_host_barrier = self.__socket_settings['max_connections_per_host_barrier']
1448 self.max_command_length = self.__socket_settings['max_command_length']
1449 self.disabled_commands = self.__socket_settings['disabled_cmds']
1450 self.ip_blacklist = self.__socket_settings['ip_blacklist']
1451 self.answers = self.__socket_settings['answers']
1452 self.connections = 0
1453 self.per_host_connections = {}
1454 self.sessions = {}
1455 self.__output = None
1456 self.SSL = {}
1457 self.SSL_exceptions = {}
1458 self.SSL_exceptions['WantReadError'] = None
1459 self.SSL_exceptions['WantWriteError'] = None
1460 self.SSL_exceptions['WantX509LookupError'] = None
1461 self.SSL_exceptions['ZeroReturnError'] = None
1462 self.SSL_exceptions['SysCallError'] = None
1463 self.SSL_exceptions['Error'] = []
1464 self.last_print = ''
1465 self.valid_commands = {}
1466 self.no_acked_commands = []
1467 self.raw_commands = []
1468 self.config_commands = []
1469 self.termination_commands = []
1470 self.initialization_commands = []
1471 self.login_pass_commands = []
1472 self.no_session_commands = []
1473 self.command_classes = [self.BuiltInCommands]
1474 self.command_instances = []
1475 self.EntropyInstantiation = (service_interface, self.args, self.kwds)
1476
1477 self.setup_external_command_classes()
1478 self.start_local_output_interface()
1479 self.setup_authenticator()
1480 self.setup_hostname()
1481 self.setup_commands()
1482 self.disable_commands()
1483 self.start_session_garbage_collector()
1484 self.setup_ssl()
1485 self.start_python_garbage_collector()
1486
1488 if hasattr(self,'socketLog'):
1489 self.socketLog.close()
1490 if self.Server != None:
1491 self.Server.alive = False
1492 if self.Gc != None:
1493 self.Gc.kill()
1494 if self.PythonGarbageCollector != None:
1495 self.PythonGarbageCollector.kill()
1496
1498 return str(len(data)) + \
1499 self.answers['eos'] + \
1500 data
1501
1503
1504 do_ssl = False
1505 if self.kwds.has_key('ssl'):
1506 do_ssl = self.kwds.pop('ssl')
1507
1508 if not do_ssl:
1509 return
1510
1511 try:
1512 from OpenSSL import SSL, crypto
1513 except ImportError, e:
1514 self.updateProgress('Unable to load OpenSSL, error: %s' % (repr(e),))
1515 return
1516 self.SSL_exceptions['WantReadError'] = SSL.WantReadError
1517 self.SSL_exceptions['Error'] = SSL.Error
1518 self.SSL_exceptions['WantWriteError'] = SSL.WantWriteError
1519 self.SSL_exceptions['WantX509LookupError'] = SSL.WantX509LookupError
1520 self.SSL_exceptions['ZeroReturnError'] = SSL.ZeroReturnError
1521 self.SSL_exceptions['SysCallError'] = SSL.SysCallError
1522 self.SSL['m'] = SSL
1523 self.SSL['crypto'] = crypto
1524 self.SSL['key'] = self.__socket_settings['ssl_key']
1525 self.SSL['cert'] = self.__socket_settings['ssl_cert']
1526 self.SSL['ca_cert'] = self.__socket_settings['ssl_ca_cert']
1527 self.SSL['ca_pkey'] = self.__socket_settings['ssl_ca_pkey']
1528
1529 self.port = self.__socket_settings['ssl_port']
1530 self.SSL['not_before'] = 0
1531 self.SSL['not_after'] = 60*60*24*365*5
1532 self.SSL['serial'] = 0
1533 self.SSL['digest'] = 'md5'
1534
1535 if not (os.path.isfile(self.SSL['ca_cert']) and \
1536 os.path.isfile(self.SSL['ca_pkey']) and \
1537 os.path.isfile(self.SSL['key']) and \
1538 os.path.isfile(self.SSL['cert'])):
1539 self.create_ca_server_certs(
1540 self.SSL['serial'],
1541 self.SSL['digest'],
1542 self.SSL['not_before'],
1543 self.SSL['not_after'],
1544 self.SSL['ca_pkey'],
1545 self.SSL['ca_cert'],
1546 self.SSL['key'],
1547 self.SSL['cert']
1548 )
1549 os.chmod(self.SSL['ca_cert'],0644)
1550 try:
1551 os.chown(self.SSL['ca_cert'],-1,0)
1552 except OSError:
1553 pass
1554 os.chmod(self.SSL['ca_pkey'],0600)
1555 try:
1556 os.chown(self.SSL['ca_pkey'],-1,0)
1557 except OSError:
1558 pass
1559
1560 os.chmod(self.SSL['key'],0600)
1561 try:
1562 os.chown(self.SSL['key'],-1,0)
1563 except OSError:
1564 pass
1565 os.chmod(self.SSL['cert'],0644)
1566 try:
1567 os.chown(self.SSL['cert'],-1,0)
1568 except OSError:
1569 pass
1570
1571 - def create_ca_server_certs(self, serial, digest, not_before, not_after, ca_pkey_dest, ca_cert_dest, server_key, server_cert):
1572
1573 mycn = 'Entropy Repository Service'
1574 cakey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1575 careq = self.create_ssl_certificate_request(cakey, digest, CN = mycn)
1576 cert = self.SSL['crypto'].X509()
1577 cert.set_serial_number(serial)
1578 cert.gmtime_adj_notBefore(not_before)
1579 cert.gmtime_adj_notAfter(not_after)
1580 cert.set_issuer(careq.get_subject())
1581 cert.set_subject(careq.get_subject())
1582 cert.sign(cakey, digest)
1583
1584
1585 s_pkey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1586 s_req = self.create_ssl_certificate_request(s_pkey, digest, CN = mycn)
1587 s_cert = self.SSL['crypto'].X509()
1588 s_cert.set_serial_number(serial+1)
1589 s_cert.gmtime_adj_notBefore(not_before)
1590 s_cert.gmtime_adj_notAfter(not_after)
1591 s_cert.set_issuer(cert.get_subject())
1592 s_cert.set_subject(s_req.get_subject())
1593 s_cert.set_pubkey(s_req.get_pubkey())
1594 s_cert.sign(cakey, digest)
1595
1596
1597 if os.path.isfile(ca_pkey_dest):
1598 shutil.move(ca_pkey_dest,ca_pkey_dest+".moved")
1599 f = open(ca_pkey_dest,"w")
1600 f.write(self.SSL['crypto'].dump_privatekey(self.SSL['crypto'].FILETYPE_PEM, cakey))
1601 f.flush()
1602 f.close()
1603 if os.path.isfile(ca_cert_dest):
1604 shutil.move(ca_cert_dest,ca_cert_dest+".moved")
1605 f = open(ca_cert_dest,"w")
1606 f.write(self.SSL['crypto'].dump_certificate(self.SSL['crypto'].FILETYPE_PEM, cert))
1607 f.flush()
1608 f.close()
1609
1610 if os.path.isfile(server_key):
1611 shutil.move(server_key,server_key+".moved")
1612
1613 f = open(server_key,"w")
1614 f.write(self.SSL['crypto'].dump_privatekey(self.SSL['crypto'].FILETYPE_PEM, s_pkey))
1615 f.flush()
1616 f.close()
1617 if os.path.isfile(server_cert):
1618 shutil.move(server_cert,server_cert+".moved")
1619 f = open(server_cert,"w")
1620 f.write(self.SSL['crypto'].dump_certificate(self.SSL['crypto'].FILETYPE_PEM, s_cert))
1621 f.flush()
1622 f.close()
1623
1625 pkey = self.SSL['crypto'].PKey()
1626 pkey.generate_key(keytype, bits)
1627 return pkey
1628
1630 req = self.SSL['crypto'].X509Req()
1631 subj = req.get_subject()
1632 for (key,value) in name.items():
1633 setattr(subj, key, value)
1634 req.set_pubkey(pkey)
1635 req.sign(pkey, digest)
1636 return req
1637
1639
1640 if self.kwds.has_key('external_cmd_classes'):
1641 ext_commands = self.kwds.pop('external_cmd_classes')
1642 if not isinstance(ext_commands,list):
1643 raise InvalidDataType("InvalidDataType: external_cmd_classes must be a list")
1644 self.command_classes += ext_commands
1645
1647
1648 identifiers = set()
1649 for myclass in self.command_classes:
1650
1651 myargs = []
1652 mykwargs = {}
1653 if isinstance(myclass,tuple) or isinstance(myclass,list):
1654 if len(myclass) > 2:
1655 mykwargs = myclass[2]
1656 if len(myclass) > 1:
1657 myargs = myclass[1]
1658 myclass = myclass[0]
1659
1660 myinst = myclass(self, *myargs, **mykwargs)
1661 if str(myinst) in identifiers:
1662 raise PermissionDenied("PermissionDenied: another command instance is owning this name")
1663 identifiers.add(str(myinst))
1664 self.command_instances.append(myinst)
1665
1666 myinst.register( self.valid_commands,
1667 self.no_acked_commands,
1668 self.termination_commands,
1669 self.initialization_commands,
1670 self.login_pass_commands,
1671 self.no_session_commands,
1672 self.raw_commands,
1673 self.config_commands
1674 )
1675
1677 for cmd in self.disabled_commands:
1678
1679 if cmd in self.valid_commands:
1680 self.valid_commands.pop(cmd)
1681
1682 if cmd in self.no_acked_commands:
1683 self.no_acked_commands.remove(cmd)
1684
1685 if cmd in self.termination_commands:
1686 self.termination_commands.remove(cmd)
1687
1688 if cmd in self.initialization_commands:
1689 self.initialization_commands.remove(cmd)
1690
1691 if cmd in self.login_pass_commands:
1692 self.login_pass_commands.remove(cmd)
1693
1694 if cmd in self.no_session_commands:
1695 self.no_session_commands.remove(cmd)
1696
1697 if cmd in self.raw_commands:
1698 self.raw_commands.remove(cmd)
1699
1700 if cmd in self.config_commands:
1701 self.config_commands.remove(cmd)
1702
1704 if self.kwds.has_key('sock_output'):
1705 outputIntf = self.kwds.pop('sock_output')
1706 self.__output = outputIntf
1707
1709
1710
1711 self.AuthenticatorLock = self.threading.Lock()
1712 auth_inst = (self.BasicPamAuthenticator, [self], {},)
1713
1714 if self.kwds.has_key('sock_auth'):
1715 authIntf = self.kwds.pop('sock_auth')
1716 if type(authIntf) is tuple:
1717 if len(authIntf) == 3:
1718 auth_inst = authIntf[:]
1719 else:
1720 raise IncorrectParameter("IncorrectParameter: wront authentication interface specified")
1721 else:
1722 raise IncorrectParameter("IncorrectParameter: wront authentication interface specified")
1723
1724 self.AuthenticatorInst = (auth_inst[0],[self]+auth_inst[1],auth_inst[2],)
1725
1730
1734
1736 self.gc.collect()
1737 self.gc.collect()
1738 self.gc.collect()
1739
1741 if not self.sessions:
1742 return
1743
1744 with self.SessionsLock:
1745 for session_id in self.sessions.keys():
1746 sess_time = self.sessions[session_id]['t']
1747 is_running = self.sessions[session_id]['running']
1748 auth_uid = self.sessions[session_id]['auth_uid']
1749 if (is_running) or (auth_uid == -1):
1750 if auth_uid == -1:
1751 self.updateProgress('not killing session %s, since it is kept alive by auth_uid=-1' % (session_id,) )
1752 continue
1753 cur_time = time.time()
1754 ttl = self.session_ttl
1755 check_time = sess_time + ttl
1756 if cur_time > check_time:
1757 self.updateProgress('killing session %s, ttl: %ss: no activity' % (session_id,ttl,) )
1758 self._destroy_session(session_id)
1759
1761 if self.hostname:
1762 try:
1763 self.hostname = self.get_ip_address(self.hostname)
1764 except IOError:
1765 pass
1766
1768 import fcntl
1769 import struct
1770 mysock = self.socket.socket ( self.socket.AF_INET, self.socket.SOCK_STREAM )
1771 return self.socket.inet_ntoa(fcntl.ioctl(mysock.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
1772
1774 import hashlib
1775 m = hashlib.md5()
1776 m.update(os.urandom(2))
1777 return m.hexdigest()
1778
1780 with self.SessionsLock:
1781 if len(self.sessions) > self.threads:
1782
1783 return "0"
1784 rng = self.get_md5_hash()
1785 while rng in self.sessions:
1786 rng = self.get_md5_hash()
1787 self.sessions[rng] = {}
1788 self.sessions[rng]['running'] = False
1789 self.sessions[rng]['auth_uid'] = None
1790 self.sessions[rng]['admin'] = False
1791 self.sessions[rng]['moderator'] = False
1792 self.sessions[rng]['user'] = False
1793 self.sessions[rng]['developer'] = False
1794 self.sessions[rng]['compression'] = None
1795 self.sessions[rng]['stream_mode'] = False
1796 try:
1797 self.sessions[rng]['stream_path'] = self.entropyTools.get_random_temp_file()
1798 except (IOError,OSError,):
1799 self.sessions[rng]['stream_path'] = ''
1800 self.sessions[rng]['t'] = time.time()
1801 self.sessions[rng]['ip_address'] = ip_address
1802 return rng
1803
1805 with self.SessionsLock:
1806 if self.sessions.has_key(session):
1807 self.sessions[session]['t'] = time.time()
1808 self.updateProgress('session time updated for %s' % (session,) )
1809
1811 with self.SessionsLock:
1812 if self.sessions.has_key(session):
1813 self.sessions[session]['running'] = True
1814
1816 with self.SessionsLock:
1817 if self.sessions.has_key(session):
1818 self.sessions[session]['running'] = False
1819
1821 with self.SessionsLock:
1822 self._destroy_session(session)
1823
1825 if self.sessions.has_key(session):
1826 stream_path = self.sessions[session]['stream_path']
1827 del self.sessions[session]
1828 if os.path.isfile(stream_path) and os.access(stream_path,os.W_OK) and not os.path.islink(stream_path):
1829 try: os.remove(stream_path)
1830 except OSError: pass
1831 return True
1832 return False
1833
1835 self.socket.setdefaulttimeout(self.timeout)
1836 while 1:
1837 try:
1838 self.Server = self.HostServerMixin(
1839 (self.hostname, self.port),
1840 self.RequestHandler,
1841 self.CommandProcessor(self),
1842 self
1843 )
1844 break
1845 except self.socket.error, e:
1846 if e[0] == 98:
1847
1848 self.updateProgress('address already in use (%s, port: %s), waiting 5 seconds...' % (self.hostname,self.port,))
1849 time.sleep(5)
1850 continue
1851 else:
1852 raise
1853 self.updateProgress('server connected, listening on: %s, port: %s, timeout: %s' % (self.hostname,self.port,self.timeout,))
1854 self.Server.serve_forever()
1855 self.Gc.kill()
1856
1858 with self.SessionsLock:
1859 if session in self.sessions:
1860 if type(rc) in (list,tuple,):
1861 rc_item = rc[:]
1862 elif type(rc) in (set,frozenset,dict,):
1863 rc_item = rc.copy()
1864 else:
1865 rc_item = rc
1866 self.sessions[session]['rc'] = rc_item
1867
1869 with self.SessionsLock:
1870 if session in self.sessions:
1871 return self.sessions[session].get('rc')
1872
1874 if self.SSL:
1875 mydata = self.append_eos(data)
1876 encode_done = False
1877 while 1:
1878 try:
1879 sent = channel.send(mydata)
1880 if sent == len(mydata):
1881 break
1882 mydata = mydata[sent:]
1883 except (self.SSL_exceptions['WantWriteError'],self.SSL_exceptions['WantReadError']):
1884 time.sleep(0.2)
1885 continue
1886 except UnicodeEncodeError:
1887 if encode_done:
1888 raise
1889 mydata = mydata.encode('utf-8')
1890 encode_done = True
1891 continue
1892 else:
1893 channel.sendall(self.append_eos(data))
1894
1896 message = args[0]
1897 if message != self.last_print:
1898 self.socketLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_NORMAL,str(args[0]))
1899 if self.__output != None and self.stdout_logging:
1900 self.__output.updateProgress(*args,**kwargs)
1901 self.last_print = message
1902