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