cmd-ctrld.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import http.server
  2. import urllib.parse
  3. import json
  4. import re
  5. import ssl, socket
  6. import ISC
  7. import pprint
  8. import select
  9. import csv
  10. import random
  11. from hashlib import sha1
  12. try:
  13. import threading
  14. except ImportError:
  15. import dummy_threading as threading
  16. URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
  17. class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
  18. '''
  19. Process GET and POST
  20. '''
  21. def parse_path(self, path):
  22. groups = URL_PATTERN.match(path)
  23. if not groups:
  24. return (NULL, NULL)
  25. return (groups.group(1), groups.group(2))
  26. def check_username(self,name):
  27. reader = csv.reader(open("passwd.csv"), delimiter="\t", quoting=csv.QUOTE_MINIMAL)
  28. for row in reader:
  29. if name==row[0]:
  30. self.user=[row[0],row[1],row[2]]
  31. return 1
  32. return 0
  33. def check(self):
  34. length = self.headers.get('content-length')
  35. nbytes = int(length)
  36. user_info = json.loads((self.rfile.read(nbytes)).decode())
  37. if not user_info:
  38. return ["error: invalid username or password"], http.client.UNAUTHORIZED
  39. if not self.check_username(user_info['username']):
  40. return ["error:the username doesn't exists"], http.client.UNAUTHORIZED
  41. if sha1((user_info['password'] + self.user[2]).encode()).hexdigest() != self.user[1] :
  42. return ["error:the username and passwd did not match!"], http.client.UNAUTHORIZED
  43. else :
  44. id = self.headers.get('cookie')
  45. self.server.session[id]['username'] = user_info['username']
  46. return ["login success !"], http.client.OK
  47. def do_GET(self):
  48. id = self.headers.get('cookie')
  49. if id not in self.server.session:
  50. self.server.session[id]={}
  51. reply_value = []
  52. if "username" not in self.server.session[id]:
  53. reply_value = ["please post username and passwd"]
  54. else:
  55. identifier, module = self.parse_path(self.path)
  56. if identifier != None:
  57. data = self.server.get_reply_data_for_GET(identifier, module)
  58. if data:
  59. reply_value = data
  60. self.send_response(200)
  61. self.end_headers()
  62. self.wfile.write(json.dumps(reply_value).encode())
  63. def do_POST(self):
  64. id = self.headers.get('cookie')
  65. if id not in self.server.session:
  66. self.server.session[id] = {}
  67. reply_msg = []
  68. rcode = 200
  69. if self.path == '/login':
  70. reply_msg, rcode = self.check()
  71. elif "username" not in self.server.session[id]:
  72. reply_msg, rcode = ["please login!"], http.client.UNAUTHORIZED
  73. else:
  74. mod, cmd = self.parse_path(self.path)
  75. param = None
  76. len = self.headers.get('Content-Length')
  77. if len:
  78. post_str = str(self.rfile.read(int(len)).decode())
  79. print("command parameter:%s" % post_str)
  80. param = json.loads(post_str)
  81. reply_msg = self.server.send_command_to_module(mod, cmd, param)
  82. print('cmd-ctrld finish send message \'%s\' to module %s' % (cmd, mod))
  83. #TODO, set proper rcode
  84. self.send_response(rcode)
  85. self.end_headers()
  86. self.wfile.write(json.dumps(reply_msg).encode())
  87. class CommandControl():
  88. def __init__(self):
  89. self.cc = ISC.CC.Session()
  90. self.cc.group_subscribe('Cmd-Ctrld')
  91. #self.cc.group_subscribe('Boss', 'Cmd-Ctrld')
  92. self.command_spec = self.get_cmd_specification()
  93. self.config_spec = self.get_data_specification()
  94. self.config_data = self.get_config_data()
  95. def get_cmd_specification(self):
  96. return self.send_command('ConfigManager', 'get_commands')
  97. def get_config_data(self):
  98. return self.send_command('ConfigManager', 'get_config')
  99. def update_config_data(self, module_name, command_name):
  100. if module_name == 'ConfigManager' and command_name == 'set_config':
  101. self.config_data = self.get_config_data()
  102. def get_data_specification(self):
  103. return self.send_command('ConfigManager', 'get_data_spec')
  104. def handle_recv_msg(self):
  105. # Handle received message, if 'shutdown' is received, return False
  106. (message, env) = self.cc.group_recvmsg(True)
  107. while message:
  108. if 'commands_update' in message:
  109. self.command_spec[message['commands_update'][0]] = message['commands_update'][1]
  110. elif 'specification_update' in message:
  111. msgvalue = message['specification_update']
  112. self.config_spec[msgvalue[0]] = msgvalue[1]
  113. elif 'command' in message and message['command'][0] == 'shutdown':
  114. return False;
  115. (message, env) = self.cc.group_recvmsg(True)
  116. return True
  117. def send_command(self, module_name, command_name, params = None):
  118. content = [command_name]
  119. if params:
  120. content.append(params)
  121. msg = {'command' : content}
  122. print('cmd-ctrld send command \'%s\' to %s' %(command_name, module_name))
  123. try:
  124. self.cc.group_sendmsg(msg, module_name)
  125. answer, env = self.cc.group_recvmsg(False)
  126. if answer and 'result' in answer.keys() and type(answer['result']) == list:
  127. # TODO: with the new cc implementation, replace "1" by 1
  128. if answer['result'][0] == "1":
  129. # todo: exception
  130. print("Error: " + str(answer['result'][1]))
  131. return {}
  132. else:
  133. self.update_config_data(module_name, command_name)
  134. if len(answer['result']) > 1:
  135. return answer['result'][1]
  136. return {}
  137. else:
  138. print("Error: unexpected answer from %s" % module_name)
  139. except Exception as e:
  140. print(e)
  141. print('cmd-ctrld fail send command \'%s\' to %s' % (command_name, module_name))
  142. return {}
  143. class SecureHTTPServer(http.server.HTTPServer):
  144. '''Make the server address can be reused.'''
  145. allow_reuse_address = True
  146. def __init__(self, server_address, RequestHandlerClass):
  147. http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
  148. self.session = {}
  149. self.cmdctrl = CommandControl()
  150. self.__is_shut_down = threading.Event()
  151. self.__serving = False
  152. def get_request(self):
  153. newsocket, fromaddr = self.socket.accept()
  154. try:
  155. connstream = ssl.wrap_socket(newsocket,
  156. server_side = True,
  157. certfile = 'create_your_cert.pem',
  158. keyfile = 'create_your_cert.pem',
  159. ssl_version = ssl.PROTOCOL_SSLv23)
  160. return (connstream, fromaddr)
  161. except ssl.SSLError as e :
  162. print("error happen***********")
  163. print(e)
  164. def get_reply_data_for_GET(self, id, module_name):
  165. if module_name is None:
  166. if id == 'command_spec':
  167. return self.cmdctrl.command_spec
  168. elif id == 'config_data':
  169. return self.cmdctrl.config_data
  170. elif id == 'config_spec':
  171. return self.cmdctrl.config_spec
  172. else:
  173. return None
  174. def serve_forever(self, poll_interval = 0.5):
  175. self.__serving = True
  176. self.__is_shut_down.clear()
  177. while self.__serving:
  178. if not self.cmdctrl.handle_recv_msg():
  179. break
  180. r, w, e = select.select([self], [], [], poll_interval)
  181. if r:
  182. self._handle_request_noblock()
  183. self.__is_shut_down.set()
  184. def shutdown(self):
  185. self.__serving = False
  186. self.__is_shut_down.wait()
  187. def send_command_to_module(self, module_name, command_name, params):
  188. return self.cmdctrl.send_command(module_name, command_name, params)
  189. def run(server_class = SecureHTTPServer, addr = 'localhost', port = 8080):
  190. print("cmd-ctrld module is starting on :%s port:%d" %(addr, port))
  191. httpd = server_class((addr, port), SecureHTTPRequestHandler)
  192. httpd.serve_forever()
  193. if __name__ == '__main__':
  194. try:
  195. run()
  196. except ISC.CC.SessionError as se:
  197. print("[cmd-ctrld] Error creating cmd-ctrld, "
  198. "is the command channel daemon running?")
  199. except KeyboardInterrupt:
  200. print("exit http server")