summaryrefslogtreecommitdiffstats
path: root/lib/puppet/network/xmlrpc/processor.rb
blob: dea8a02faa3aa9b60333e557c7ffbcdb68048d30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
require 'puppet/network/authorization'
require 'xmlrpc/server'

# Just silly.
class ::XMLRPC::FaultException
  def to_s
    self.message
  end
end

module Puppet::Network
  # Most of our subclassing is just so that we can get
  # access to information from the request object, like
  # the client name and IP address.
  module XMLRPCProcessor
    include Puppet::Network::Authorization

    ERR_UNAUTHORIZED = 30

    def add_handler(interface, handler)
      @loadedhandlers << interface.prefix
      super(interface, handler)
    end

    def handler_loaded?(handler)
      @loadedhandlers.include?(handler.to_s)
    end

    # Convert our data and client request into xmlrpc calls, and verify
    # they're authorized and such-like.  This method differs from the
    # default in that it expects a ClientRequest object in addition to the
    # data.
    def process(data, request)
      call, params = parser.parseMethodCall(data)
      params << request.name << request.ip
      handler, method = call.split(".")
      request.handler = handler
      request.method = method
      begin
        verify(request)
      rescue InvalidClientRequest => detail
        raise ::XMLRPC::FaultException.new(ERR_UNAUTHORIZED, detail.to_s)
      end
      handle(request.call, *params)
    end

    private

    # Provide error handling for method calls.
    def protect_service(obj, *args)
      begin
        obj.call(*args)
      rescue ::XMLRPC::FaultException
        raise
      rescue Puppet::AuthorizationError => detail
        Puppet.err "Permission denied: #{detail}"
        raise ::XMLRPC::FaultException.new(
          1, detail.to_s
        )
      rescue Puppet::Error => detail
        puts detail.backtrace if Puppet[:trace]
        Puppet.err detail.to_s
        error = ::XMLRPC::FaultException.new(
          1, detail.to_s
        )
        error.set_backtrace detail.backtrace
        raise error
      rescue => detail
        puts detail.backtrace if Puppet[:trace]
        Puppet.err "Could not call: #{detail}"
        error = ::XMLRPC::FaultException.new(1, detail.to_s)
        error.set_backtrace detail.backtrace
        raise error
      end
    end

    # Set up our service hook and init our handler list.
    def setup_processor
      @loadedhandlers = []
      self.set_service_hook do |obj, *args|
        protect_service(obj, *args)
      end
    end
  end
end