Example #1
0
 def check_auth_gssapi_keyex(self,
                             username,
                             gss_authenticated=paramiko.AUTH_FAILED,
                             cc_file=None):
     Logger.debug(9, f'SSH Server: check_auth_gssapi_keyex')
     # No real authenticatio, all users welcome
     return paramiko.AUTH_SUCCESSFUL
Example #2
0
 def from_trace_file(source_filename):
     parrot_filename = None
     if source_filename.endswith(".trace"):
         parrot_filename = NSO_Trace_Parrot_Builder(source_filename).build()
     if parrot_filename:
         return parrot_filename
     Logger.fatal(
         f"Parrot Builder, unrecognized trace file type: {source_filename}")
Example #3
0
    def match(self, xml_match_str):
        def match_nodes(matchpoint, payloadpoint):
            def matching_tags(matchtag, payloadtag):
                mpos = matchtag.find("}")
                if mpos != -1:
                    # If matchtag has namespace, namespaces and tags have to match
                    Logger.debug(
                        8, f'Match NS matching_tags({matchtag}, {payloadtag})')
                    return matchtag == payloadtag
                ppos = payloadtag.find("}")
                if ppos != -1:
                    # If matchtag has no namespace, only tags have to match
                    Logger.debug(
                        8, f'Match NO matching_tags({matchtag}, {payloadtag})')
                    return matchtag == payloadtag[ppos + 1:]
                # If neither has namespace, tags have to match
                Logger.debug(
                    8, f'Match NE matching_tags({matchtag}, {payloadtag})')
                return matchtag == payloadtag

            Logger.debug(
                8, f'Match 1 match_nodes_t({matchpoint}, {payloadpoint})')
            if matching_tags(matchpoint.tag, payloadpoint.tag):
                for mch in matchpoint:  # must match all
                    Logger.debug(8, f'Match 3 Trying match {mch}')
                    one_match = False
                    for pch in payloadpoint:  # needs to match one
                        Logger.debug(8, f'Match 4 Trying payload {pch}')
                        if match_nodes(mch, pch):
                            Logger.debug(
                                8,
                                f'Match M match_nodes_t({mch}, {pch}) = True')
                            one_match = True
                            break
                    if not one_match:
                        Logger.debug(
                            8,
                            f'Match O match_nodes_t({matchpoint}, {payloadpoint}) = False'
                        )
                        return False
                Logger.debug(
                    8,
                    f'Match N match_nodes_t({matchpoint}, {payloadpoint}) = True'
                )
                return True
            Logger.debug(
                8,
                f'Match E match_nodes_t({matchpoint}, {payloadpoint}) = False')
            return False

        match_root = ET.fromstring(
            f'''<parrot-root>{xml_match_str}</parrot-root>''')
        if match_nodes(match_root, self.get_xml_etree()):
            Logger.debug(5,
                         f"Incoming message template match '{xml_match_str}'")
            return True
        return False
Example #4
0
 def __init__(self, source_filename, target_filename=None):
     self.source_filename = pathlib.Path(source_filename)
     if not target_filename:
         target_filename = source_filename + ".parrot.xml"
     self.target_filename = pathlib.Path(target_filename)
     if not self.source_filename.exists():
         Logger.fatal(
             f"Parrot Builder, can't find trace file: {source_filename}")
     self.catalog = {}
     self.catalog_meta = {}
Example #5
0
 def __init__(self, channel, name, server, *largs, **kwargs):
     Logger.debug(
         9,
         f'NETCONFsubsys: init channel={channel} name={name} server={server}'
     )
     SubsystemHandler.__init__(self, channel, name, server)
     transport = channel.get_transport()
     self.ultra_debug = transport.get_hexdump()
     self.next_handle = 1
     Logger.debug(9, f'NETCONFsubsys: init done')
Example #6
0
 def reply(self, incoming_message):
     try:
         response_msg = self.template.render(
             request=incoming_message,
             message_id=incoming_message.get_message_id(),
             session_id="4711",  #FIXME str(self.session_id),
         )
         return response_msg.strip()
     except Exception as ex:
         Logger.fatal(
             f"Template rendering error, {self.template}, {incoming_message.get_xml_text()}: {ex}"
         )
Example #7
0
    def run(self, host, port, parrot_file):
        Logger.info(f"Parroting {parrot_file}")
        try:
            parrot_path = pathlib.Path(parrot_file)
            env = Environment(loader=FileSystemLoader([parrot_path.parent],
                                                      followlinks=True),
                              autoescape=select_autoescape(['xml']))

            self.server.set_template(env.get_template(str(parrot_path.name)))
            self.server.set_host_port(host, port)
            self.server.serve()
        except Exception as e:
            traceback.print_exc()
            Logger.fatal(f"Top level exception: {str(e)}")
Example #8
0
    def build(self):
        if self.target_filename.exists():
            source_stat = self.source_filename.stat()
            target_stat = self.target_filename.stat()
            if source_stat.st_mtime <= target_stat.st_mtime:
                Logger.info(
                    f"Parrot Builder, {self.target_filename} up to date")
                return str(self.target_filename)

        with open(self.source_filename, "r") as source_file:
            with open(self.target_filename, "w") as target_file:
                self._make_messages(source_file)
                self._emit_messages(target_file)
        return str(self.target_filename)
Example #9
0
 def finish_subsystem(self):
     Logger.debug(9, f'NETCONFsubsys: finish_subsystem')
     threading.current_thread().daemon = True
     self.server.session_ended()
     Logger.debug(9, 'NETCONF subsys finished')
     super(NETCONFsubsys, self).finish_subsystem()
     Logger.debug(9, 'NETCONF subsys finished 2')
     Logger.debug(9, 'NETCONF subsys finished 3')
 def read_msg(self, netconf_ver=0):
   if netconf_ver == 0:
     netconf_ver = self.netconf_ver
   if netconf_ver == 11:
     msg = self.read_msg_11()
   else:
     msg = self.read_msg_10()
   try:
     if isinstance(msg, bytes):
       decoded_msg = msg.decode("utf-8")
     else:
       decoded_msg = msg
     Logger.debug(8,f'Received {len(decoded_msg)} byte message', payload=decoded_msg)
   except Exception as e:
     Logger.warning(f"Could not UTF-8 decode message", payload=msg)
     raise
   return decoded_msg
Example #11
0
    def run_command_line(self, sys_argv=sys.argv):
        def usage(sys_argv):
            print(f'{sys_argv[0]} --netconf=[host:]port parrot-file.xml')

        verbosity = 4
        host = "localhost"
        port = 8888
        template_dirs = []
        trace_files = []
        parrot_file = None
        try:
            opts, args = getopt.getopt(
                sys_argv[1:], "hd:vt:m:",
                ["help", "debug=", "verbose", "netconf=", "template-dir="])
        except getopt.GetoptError:
            usage(sys_argv)
            sys.exit(2)
        for opt, arg in opts:
            if opt in ('-h', '--help'):
                usage(sys_argv)
                sys.exit()
            elif opt in ("--netconf"):
                self.server = Parrot.NETCONF_Parrot()
                if ":" in arg:
                    (host, port_str) = arg.split(":")
                    port = int(port_str)
                else:
                    port = int(arg)
            elif opt in ("-t", "--template-dir"):
                template_dirs += [arg]
            elif opt in ("-d", "--debug"):
                verbosity = int(arg)
            elif opt in ("-m", "--make-parrot"):
                trace_files += [arg]
            elif opt in ("-v", "--verbose"):
                verbosity += 1
            else:
                Logger.fatal(f'Unknown option "{opt}".')
                sys.exit(2)

        for trace_file_name in trace_files:
            parrot_file = Parrot_Builder.from_trace_file(trace_file_name)

        if not parrot_file:
            if len(args) != 1:
                usage(sys_argv)
                Logger.fatal(f"{len(args)} parrot files given.", code=2)
            parrot_file = args[0]

        if not self.server:
            usage(sys_argv)
            Logger.fatal(f"{len(args)} server specified.", code=2)

        Logger.set_verbosity(verbosity)

        self.run(host, port, parrot_file)
 def send_msg(self, msg, netconf_ver=0):
   chunk_size = 10000
   if netconf_ver == 0:
     netconf_ver = self.netconf_ver
   msg_len = len(msg)
   while msg != "":
     chunk = msg[:chunk_size].encode('utf-8')
     chunk_len = len(chunk)
     if netconf_ver == 11:
       header = f"\n#{chunk_len}\n".encode('utf-8')
       Logger.debug(10, f'Sending NC11 header', payload=header)
       self.channel.send(header)
     Logger.debug(9, f'Sending {chunk_len} bytes chunk', payload=chunk)
     self.channel.send(chunk)
     msg = msg[chunk_size:]
   if netconf_ver == 11:
     Logger.debug(10, f'Sending NC11 delimiter', payload=self.delimiter11)
     self.channel.send(self.delimiter11)
   if netconf_ver == 10:
     Logger.debug(10, f'Sending NC10 delimiter', payload=self.delimiter10b)
     self.channel.send(self.delimiter10b)
   Logger.info(f"Sent {msg_len} bytes in NC{netconf_ver} message", payload=msg)
Example #13
0
 def start_subsystem(self, name, transport, channel):
     Logger.debug(
         8,
         f'NETCONFsubsys: start_subsystem name={name} transport={transport} channel={channel}'
     )
     self.sock = channel
     Logger.debug(9,
                  'Started NETCONF server on channel {!r}'.format(channel))
     try:
         self.handle_session()
     except Exception as e:
         Logger.error(f'NETCONFsubsys: callback exception {e}')
         ##raise
     Logger.debug(8,
                  'Stopped NETCONF server on channel {!r}'.format(channel))
Example #14
0
 def check_channel_request(self, kind, chanid):
     Logger.debug(
         9,
         f'SSH Server: check_channel_request kind={kind} chanid={chanid}')
     if kind == 'session':
         Logger.debug(9, f'SSH Server: check_channel_request accepted')
         return paramiko.OPEN_SUCCEEDED
     Logger.debug(9, f'SSH Server: check_channel_request rejected')
     return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
Example #15
0
 def _record_message(self, message, meta):
     # This method should maybe parse the XML properly, but since
     # we also want this to work with potentially malformed XML,
     # it is instead making some assumptions about the XML encoding
     direction = NSO_Trace_Parrot_Builder._meta_dir(meta)
     if not direction:
         Logger.fatal(f"Message meta malformed: {meta}")
     message_id_attr_str = "message-id="
     # Assume first occurrence of message-id is the NETCONF message-id
     pos = message.find(message_id_attr_str)
     if pos >= 0:
         pos += len(message_id_attr_str)
         delimiter = message[pos]
         # Assume message-id value is properly delimited
         if delimiter not in ['"', "'"]:
             Logger.fatal(f"Attribute message-id= malformed (1): {meta}")
         pos += 1
         endpos = message[pos:].find(delimiter)
         # Assume message-id value is at most 100 chars
         if endpos < 0 or endpos > 100:
             Logger.fatal(f"Attribute message-id= malformed (2): {meta}")
         message_id = message[pos:pos + endpos]
         self.catalog[(direction, message_id)] = message
         self.catalog_meta[(direction, message_id)] = meta
         print(
             f"Recorded message {direction} {message_id} = {message[:40]}..."
         )
     # Assume hello message is not namespaced, and has no redundant whitespace
     elif message.startswith("<hello "):
         self.catalog[(direction, "hello")] = message
         self.catalog_meta[(direction, "hello")] = meta
     elif direction == "meta":
         self.catalog[(direction, meta)] = message
         self.catalog_meta[(direction, meta)] = meta
         pass
     elif not message:
         pass
     else:
         Logger.fatal(f"Message not hello and lacks message-id: {meta}")
 def read_msg_10(self):
   chunk_size = 10000
   while True:
     if len(self.indata):
       Logger.debug(8, f"Reading message10, indata size so far {len(self.indata)}", payload=self.indata)
     eom = self.indata.find(self.delimiter10b)
     if eom >= 0:
       msg = self.indata[:eom]
       self.indata = self.indata[eom+len(self.delimiter10b):]
       Logger.debug(8, f"Message10 complete. Size {len(msg)}, remaining in indata {len(self.indata)}")
       return msg
     time.sleep(.5)
     next_chunk = self.channel.recv(chunk_size)
     Logger.debug(7, f"Read {len(next_chunk)} bytes NC10")
     if next_chunk:
       self.indata += next_chunk
     else:
       Logger.debug(8, f"Message10 EOF")
       msg = self.indata
       #self.indata = b""
       self.channel.close()
       return msg
Example #17
0
 def matching_tags(matchtag, payloadtag):
     mpos = matchtag.find("}")
     if mpos != -1:
         # If matchtag has namespace, namespaces and tags have to match
         Logger.debug(
             8, f'Match NS matching_tags({matchtag}, {payloadtag})')
         return matchtag == payloadtag
     ppos = payloadtag.find("}")
     if ppos != -1:
         # If matchtag has no namespace, only tags have to match
         Logger.debug(
             8, f'Match NO matching_tags({matchtag}, {payloadtag})')
         return matchtag == payloadtag[ppos + 1:]
     # If neither has namespace, tags have to match
     Logger.debug(
         8, f'Match NE matching_tags({matchtag}, {payloadtag})')
     return matchtag == payloadtag
Example #18
0
 def register_callback_object(cb_target):
     NETCONFsubsys.cb_target = cb_target
     Logger.debug(9, f'NETCONFsubsys: registered cb={cb_target}')
Example #19
0
        def match_nodes(matchpoint, payloadpoint):
            def matching_tags(matchtag, payloadtag):
                mpos = matchtag.find("}")
                if mpos != -1:
                    # If matchtag has namespace, namespaces and tags have to match
                    Logger.debug(
                        8, f'Match NS matching_tags({matchtag}, {payloadtag})')
                    return matchtag == payloadtag
                ppos = payloadtag.find("}")
                if ppos != -1:
                    # If matchtag has no namespace, only tags have to match
                    Logger.debug(
                        8, f'Match NO matching_tags({matchtag}, {payloadtag})')
                    return matchtag == payloadtag[ppos + 1:]
                # If neither has namespace, tags have to match
                Logger.debug(
                    8, f'Match NE matching_tags({matchtag}, {payloadtag})')
                return matchtag == payloadtag

            Logger.debug(
                8, f'Match 1 match_nodes_t({matchpoint}, {payloadpoint})')
            if matching_tags(matchpoint.tag, payloadpoint.tag):
                for mch in matchpoint:  # must match all
                    Logger.debug(8, f'Match 3 Trying match {mch}')
                    one_match = False
                    for pch in payloadpoint:  # needs to match one
                        Logger.debug(8, f'Match 4 Trying payload {pch}')
                        if match_nodes(mch, pch):
                            Logger.debug(
                                8,
                                f'Match M match_nodes_t({mch}, {pch}) = True')
                            one_match = True
                            break
                    if not one_match:
                        Logger.debug(
                            8,
                            f'Match O match_nodes_t({matchpoint}, {payloadpoint}) = False'
                        )
                        return False
                Logger.debug(
                    8,
                    f'Match N match_nodes_t({matchpoint}, {payloadpoint}) = True'
                )
                return True
            Logger.debug(
                8,
                f'Match E match_nodes_t({matchpoint}, {payloadpoint}) = False')
            return False
 def handle_session(self):
   Logger.debug(7, 'Session loop running')
   self.incoming_message('<?xml version="1.0" encoding="UTF-8"?><hello xmlns="parrot"/>')
   while True:
     try:
       Logger.debug(5,'NETCONF server ready, waiting for next message')
       msg = self.read_msg()
     except EOFError:
       Logger.debug(5,'EOF -- end of session')
       return
     except Exception as e:
       verdict = self.handle_read_exception(e)
       if verdict == "kill-session":
         return
       if verdict == "kill-server":
         Logger.info('Server terminating')
         sys.exit(1)
       # Else keep going
     try:
       if("" == msg):
         Logger.debug(5,'EOF ++ end of session')
         return
       if self.incoming_message(msg) == True:
         return
     except Exception as e:
       Logger.error('Exception in server processing: ' + str(e))
Example #21
0
 def check_channel_pty_request(self, channel, term, width, height,
                               pixelwidth, pixelheight, modes):
     Logger.debug(9, f'SSH Server: check_channel_pty_request')
     return True
Example #22
0
 def check_channel_shell_request(self, channel):
     Logger.debug(9, f'SSH Server: check_channel_shell_request')
     self.event.set()
     return True
Example #23
0
 def get_allowed_auths(self, username):
     Logger.debug(9, f'SSH Server: get_allowed_auths')
     return 'gssapi-keyex,gssapi-with-mic,password,publickey'
Example #24
0
 def enable_auth_gssapi(self):
     Logger.debug(9, f'SSH Server: enable_auth_gssapi')
     return True
Example #25
0
 def check_auth_publickey(self, username, key):
     Logger.debug(9, f'SSH Server: check_auth_publickey')
     # No real authenticatio, all users welcome
     return paramiko.AUTH_SUCCESSFUL
 def read_msg_11(self):
   chunk_size = 10000
   max_header_len = 15
   frame_len = -1
   msg = b""
   while True:
     Logger.debug(8,f'Read data, indata queue length {len(self.indata)} bytes')
     if frame_len >= 0: # We know the frame length
       # Read frame body until frame_len bytes available
       len_indata = len(self.indata)
       if len_indata >= frame_len: # We have the entire frame
         msg += self.indata[:frame_len]
         self.indata = self.indata[frame_len:]
         frame_len = -1
       else: # We got one more chunk of the frame, but not the entire frame
         msg += self.indata
         frame_len -= len_indata
         self.indata = self.channel.recv(chunk_size)
         if self.indata == b"":
           Logger.debug(8, f"Message11 EOF")
           ##self.channel.close()
           return b""
     if frame_len < 0: # Have not the frame length header yet
       nl0 = self.indata.find(b"\n")
       nl1 = self.indata.find(b"\n", nl0 + 1)
       Logger.debug(9, f"Header nl0={nl0}, nl1={nl1}, h={self.indata[1] if len(self.indata) >= 2 else None}")
       if nl0 == 0 and nl1 > nl0 and nl1 <= max_header_len and self.indata[1] == ord(b'#'): # Found header
         frame_len_str = self.indata[2:nl1]
         next_frame_start = nl1 + 1
         self.indata = self.indata[next_frame_start:]
         if frame_len_str == b"#": # We got the entire message
           return msg
         try:
           frame_len = int(frame_len_str.decode('utf-8'))
         except:
           Logger.warning(f'Framing error, invalid frame length value: """{frame_len_str}"""')
           return b""
       else:
         if (nl0 == 0 and nl1 > nl0) or (len(self.indata) > max_header_len):
           # Definitely should have a complete header, something is wrong
           Logger.warning(f'Framing error, invalid frame header', payload = self.indata)
           return b""
         # No header in sight, better read some more
         data = self.channel.recv(chunk_size)
         self.indata += data
         if data == b"":
           Logger.debug(8, f"Message11 header EOF")
           ##self.channel.close()
           return b""
  def listen(self):
    NETCONF_Server.set_instance(self)
    try:
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      #sock.bind(('', self.port))
      sock.bind((self.host, self.port))
    except Exception as e:
      Logger.fatal('Bind failed: ' + str(e))

    try:
      sock.listen(100)
    except Exception as e:
      Logger.fatal('Listen failed: ' + str(e))
    Logger.info(f'Listening for connections on port {self.port}...')

    host_key = None
    try:
      host_key = RSAKey(filename=self.host_key_filename)
    except:
      pass
    if not host_key:
      Logger.info(f'Generating new host key')
      host_key = RSAKey.generate(2048)
      if self.host_key_filename:
        host_key.write_private_key_file(self.host_key_filename, password=None)
        Logger.info(f"Wrote host key to file, '{self.host_key_filename}'")

    while True:
      try:
        Logger.info(f'Waiting for client to connect')
        client, addr = sock.accept()
      except Exception as e:
        Logger.fatal('Accept failed: ' + str(e))
      self.sock = client
      (ip, port) = addr
      Logger.info(f'Client {ip}:{port} connected')
      self.handle_connection(host_key)
      Logger.info(f'Client {ip}:{port} disconnected')
Example #28
0
 def __init__(self):
     Logger.debug(9, f'SSH Server: init')
     self.event = threading.Event()
Example #29
0
 def handle_session(self):
     Logger.debug(9, 'NETCONF subsys session started')
     NETCONFsubsys.cb_target.handle_session()
     Logger.debug(9, 'NETCONF subsys session ended')
Example #30
0
 def check_auth_password(self, username, password):
     Logger.debug(9, f'SSH Server: check_auth_password')
     # No real authenticatio, all users welcome
     return paramiko.AUTH_SUCCESSFUL