示例#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
示例#2
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
示例#3
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')
 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))
示例#5
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
 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""
示例#8
0
  def process_instructions(self, reply_msg):
    def split_processing_instructions(reply_msg):
      instructions = []
      pi_start_marker = '<?parrot '
      pi_end_marker = '?>'
      while True:
        pi_start = reply_msg.find(pi_start_marker)
        if pi_start < 0:
          break
        pi_end = reply_msg[pi_start:].find(pi_end_marker)
        if pi_end < 0:
          return ('bad-processing-instruction', reply_msg[pi_start:pi_start+20])
        pi = reply_msg[pi_start+len(pi_start_marker):pi_end]
        if pi_start:
          instructions += [('send', reply_msg[:pi_start])]
        reply_msg = reply_msg[pi_end+len(pi_end_marker):]
        cmd = pi.split(" ")[0]
        data = pi[len(cmd)+1:]
        instructions += [(cmd, data)]
      if reply_msg:
        instructions += [('send', reply_msg)]
      if not instructions:
        instructions = [('empty-response', None)]
      return instructions

    instructions = split_processing_instructions(reply_msg)
    end_session = False
    for (cmd, data) in instructions:
      if cmd == "send":
        Logger.debug(6, f'Sending {len(data)} bytes', payload=data)
        self.send_message(data)
      elif cmd == "ignore":
        Logger.debug(5, f'Not sending any response')
      elif cmd == "netconf11":
        Logger.debug(5, f'Switching to NETCONF 1.1')
        self.choose_netconf_ver([11])
      elif cmd == "netconf10":
        Logger.debug(5, f'Switching to NETCONF 1.0')
        self.choose_netconf_ver([10])
      elif cmd == "empty-response":
        Logger.warning(f'Template did not provide any response. Ending the session.')
        end_session = True
      elif cmd == "end-session":
        Logger.info(f'Ending session')
        end_session = True
      else:
        Logger.error(f'Unknown processing instruction "{cmd}" in template. Ending the session.')
        end_session = True
    return end_session
示例#9
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
示例#10
0
  def handle_connection(self, host_key):
    try:
      DoGSSAPIKeyExchange = False
      t = Transport(self.sock, gss_kex=DoGSSAPIKeyExchange)
      t.set_subsystem_handler('netconf', self.subsys)
      t.set_gss_host(socket.getfqdn(""))
      try:
        t.load_server_moduli()
      except:
        Logger.warning('Failed to load moduli -- gex will be unsupported.')
      t.add_server_key(host_key)
      server = Server()
      t.start_server(server=server)

      # wait for auth
      self.channel = t.accept(20)
      if self.channel is None:
        Logger.error('No SSH channel')
        return

      Logger.info('Waiting for message')
      server.event.wait(10)
      Logger.info('Closing')
      ##self.channel.close()
      Logger.info('Client connection closed')
    except ConnectionResetError as e:
      Logger.debug(5,'Connection reset by peer')
    except SSHException:
      Logger.error('SSH negotiation failed, client connection dropped')
    except Exception as e:
      Logger.error('Caught exception: ' + str(e.__class__) + ': ' + str(e))
      traceback.print_exc()
      try:
        t.close()
      except:
        pass
示例#11
0
 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)
示例#12
0
 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
示例#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))
示例#14
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
示例#15
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
示例#16
0
 def __init__(self):
     Logger.debug(9, f'SSH Server: init')
     self.event = threading.Event()
示例#17
0
 def register_callback_object(cb_target):
     NETCONFsubsys.cb_target = cb_target
     Logger.debug(9, f'NETCONFsubsys: registered cb={cb_target}')
示例#18
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
示例#19
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
示例#20
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
示例#21
0
 def check_channel_shell_request(self, channel):
     Logger.debug(9, f'SSH Server: check_channel_shell_request')
     self.event.set()
     return True
示例#22
0
 def get_allowed_auths(self, username):
     Logger.debug(9, f'SSH Server: get_allowed_auths')
     return 'gssapi-keyex,gssapi-with-mic,password,publickey'
示例#23
0
 def enable_auth_gssapi(self):
     Logger.debug(9, f'SSH Server: enable_auth_gssapi')
     return True
示例#24
0
 def handle_session(self):
     Logger.debug(9, 'NETCONF subsys session started')
     NETCONFsubsys.cb_target.handle_session()
     Logger.debug(9, 'NETCONF subsys session ended')
示例#25
0
 def incoming_message(self, text):
   Logger.trace(1,text)
   Logger.debug(6, f'Incoming message {len(text)} bytes', payload=text)
   new_text = self.receive_raw_message(text)
   reply_msg = self.receive_message(new_text)
   return self.process_instructions(reply_msg)