# -*- coding: binary -*-

require 'msf/core/exploit/java/rmi/client/jmx/connection/builder'

module Msf
  class Exploit
    class Remote
      module Java
        module Rmi
          module Client
            module Jmx
              # This mixin provides methods to simulate calls to the Java
              # javax/management/remote/rmi/RMIConnectionImpl_Stub
              # interface
              module Connection

                include Msf::Exploit::Remote::Java::Rmi::Client::Jmx::Connection::Builder

                # Sends a call to the JMXRMI endpoint to retrieve an MBean instance. Simulates a call
                # to the Java javax/management/remote/rmi/RMIConnectionImpl_Stub#getObjectInstance()
                # method.
                #
                # @param opts [Hash]
                # @option opts [Rex::Socket::Tcp] :sock
                # @return [TrueClass, NilClass] true if success, nil otherwise
                # @raise [Rex::Proto::Rmi::Exception] if the endpoint raises a remote exception
                # @see Msf::Exploit::Remote::Java::Rmi::Client::Registry::Builder.build_jmx_get_object_instance
                def send_jmx_get_object_instance(opts = {})
                  send_call(
                    sock: opts[:sock] || sock,
                    call: build_jmx_get_object_instance(opts)
                  )

                  return_value = recv_return(
                    sock: opts[:sock] || sock
                  )

                  if return_value.nil?
                    return nil
                  end

                  if return_value.is_exception?
                    raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
                  end

                  unless return_value.get_class_name == 'javax.management.ObjectInstance'
                    return nil
                  end

                  true
                end

                # Sends a call to the JMXRMI endpoint to create an MBean instance. Simulates a call
                # to the Java javax/management/remote/rmi/RMIConnectionImpl_Stub#createMBean()
                # method.
                #
                # @param opts [Hash]
                # @option opts [Rex::Socket::Tcp] :sock
                # @return [TrueClass, NilClass] true if success, nil otherwise
                # @raise [Rex::Proto::Rmi::Exception] if the endpoint raises a remote exception
                # @see Msf::Exploit::Remote::Java::Rmi::Client::Registry::Builder.build_jmx_create_mbean
                def send_jmx_create_mbean(opts = {})
                  send_call(
                    sock: opts[:sock] || sock,
                    call: build_jmx_create_mbean(opts)
                  )

                  return_value = recv_return(
                    sock: opts[:sock] || sock
                  )

                  if return_value.nil?
                    return nil
                  end

                  if return_value.is_exception?
                    raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
                  end

                  unless return_value.get_class_name == 'javax.management.ObjectInstance'
                    return nil
                  end

                  true
                end

                # Sends a call to the JMXRMI endpoint to invoke an MBean method. Simulates a call
                # to the Java javax/management/remote/rmi/RMIConnectionImpl_Stub#invoke()
                # method.
                #
                # @param opts [Hash]
                # @option opts [Rex::Socket::Tcp] :sock
                # @return [TrueClass, NilClass] true if success, nil otherwise
                # @raise [Rex::Proto::Rmi::Exception] if the endpoint raises a remote exception
                # @see Msf::Exploit::Remote::Java::Rmi::Client::Registry::Builder.build_jmx_invoke
                def send_jmx_invoke(opts = {})
                  send_call(
                    sock: opts[:sock] || sock,
                    call: build_jmx_invoke(opts)
                  )

                  return_value = recv_return(
                    sock: opts[:sock] || sock
                  )

                  if return_value.nil?
                    return nil
                  end

                  if return_value.is_exception?
                    raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
                  end

                  unless return_value.get_class_name == 'java.util.HashSet'
                    return nil
                  end

                  true
                end

              end
            end
          end
        end
      end
    end
  end
end
