~lynxman/ubuntu/precise/puppet/puppetlabsfixbug12844

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-3872.patch/lib/puppet/network/http_server/webrick.rb

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-10-24 15:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20111024150512-yxqwfdp6hcs6of5l
Tags: 2.7.1-1ubuntu3.2
* SECURITY UPDATE: puppet master impersonation via incorrect certificates
  - debian/patches/CVE-2011-3872.patch: refactor certificate handling.
  - Thanks to upstream for providing the patch.
  - CVE-2011-3872

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'puppet'
 
2
require 'webrick'
 
3
require 'webrick/https'
 
4
require 'fcntl'
 
5
 
 
6
require 'puppet/sslcertificates/support'
 
7
require 'puppet/network/xmlrpc/webrick_servlet'
 
8
require 'puppet/network/http_server'
 
9
require 'puppet/network/client'
 
10
require 'puppet/network/handler'
 
11
 
 
12
module Puppet
 
13
  class ServerError < RuntimeError; end
 
14
  module Network
 
15
    # The old-school, pure ruby webrick server, which is the default serving
 
16
    # mechanism.
 
17
    class HTTPServer::WEBrick < WEBrick::HTTPServer
 
18
      include Puppet::SSLCertificates::Support
 
19
 
 
20
      # Read the CA cert and CRL and populate an OpenSSL::X509::Store
 
21
      # with them, with flags appropriate for checking client
 
22
      # certificates for revocation
 
23
      def x509store
 
24
        unless File.exist?(Puppet[:cacrl])
 
25
          # No CRL, no store needed
 
26
          return nil
 
27
        end
 
28
        crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
 
29
        store = OpenSSL::X509::Store.new
 
30
        store.purpose = OpenSSL::X509::PURPOSE_ANY
 
31
        store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
 
32
        raise Puppet::Error, "Could not find CA certificate" unless self.ca_cert
 
33
 
 
34
        store.add_file(Puppet[:localcacert])
 
35
        store.add_crl(crl)
 
36
        store
 
37
      end
 
38
 
 
39
      # Set up the http log.
 
40
      def httplog
 
41
        args = []
 
42
 
 
43
        # yuck; separate http logs
 
44
        file = nil
 
45
        Puppet.settings.use(:main, :ssl, Puppet[:name])
 
46
        if Puppet.run_mode.master?
 
47
          file = Puppet[:masterhttplog]
 
48
        else
 
49
          file = Puppet[:httplog]
 
50
        end
 
51
 
 
52
        # open the log manually to prevent file descriptor leak
 
53
        file_io = open(file, "a+")
 
54
        file_io.sync
 
55
        file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
 
56
 
 
57
        args << file_io
 
58
        args << WEBrick::Log::DEBUG if Puppet[:debug]
 
59
 
 
60
        log = WEBrick::Log.new(*args)
 
61
 
 
62
 
 
63
        log
 
64
      end
 
65
 
 
66
      # Create our server, yo.
 
67
      def initialize(hash = {})
 
68
        Puppet.info "Starting server for Puppet version #{Puppet.version}"
 
69
 
 
70
        if handlers = hash[:Handlers]
 
71
          handler_instances = setup_handlers(handlers)
 
72
        else
 
73
          raise ServerError, "A server must have handlers"
 
74
        end
 
75
 
 
76
        unless self.read_cert
 
77
          if ca = handler_instances.find { |handler| handler.is_a?(Puppet::Network::Handler.ca) }
 
78
            request_cert(ca)
 
79
          else
 
80
            raise Puppet::Error, "No certificate and no CA; cannot get cert"
 
81
          end
 
82
        end
 
83
 
 
84
        setup_webrick(hash)
 
85
 
 
86
        begin
 
87
          super(hash)
 
88
        rescue => detail
 
89
          puts detail.backtrace if Puppet[:trace]
 
90
          raise Puppet::Error, "Could not start WEBrick: #{detail}"
 
91
        end
 
92
 
 
93
        # make sure children don't inherit the sockets
 
94
        listeners.each { |sock|
 
95
          sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
 
96
        }
 
97
 
 
98
        Puppet.info "Listening on port #{hash[:Port]}"
 
99
 
 
100
        # this creates a new servlet for every connection,
 
101
        # but all servlets have the same list of handlers
 
102
        # thus, the servlets can have their own state -- passing
 
103
        # around the requests and such -- but the handlers
 
104
        # have a global state
 
105
 
 
106
        # mount has to be called after the server is initialized
 
107
        servlet = Puppet::Network::XMLRPC::WEBrickServlet.new( handler_instances)
 
108
        self.mount("/RPC2", servlet)
 
109
      end
 
110
 
 
111
      # Create a ca client to set up our cert for us.
 
112
      def request_cert(ca)
 
113
        client = Puppet::Network::Client.ca.new(:CA => ca)
 
114
        raise Puppet::Error, "Could get certificate" unless client.request_cert
 
115
      end
 
116
 
 
117
      # Create all of our handler instances.
 
118
      def setup_handlers(handlers)
 
119
        raise ServerError, "Handlers must have arguments" unless handlers.is_a?(Hash)
 
120
 
 
121
        handlers.collect { |handler, args|
 
122
          hclass = nil
 
123
          unless hclass = Puppet::Network::Handler.handler(handler)
 
124
            raise ServerError, "Invalid handler #{handler}"
 
125
          end
 
126
          hclass.new(args)
 
127
        }
 
128
      end
 
129
 
 
130
      # Handle all of the many webrick arguments.
 
131
      def setup_webrick(hash)
 
132
        hash[:Port] ||= Puppet[:masterport]
 
133
        hash[:Logger] ||= self.httplog
 
134
        hash[:AccessLog] ||= [
 
135
          [ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
 
136
          [ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
 
137
        ]
 
138
 
 
139
        hash[:SSLCertificateStore] = x509store
 
140
        hash[:SSLCertificate] = self.cert
 
141
        hash[:SSLPrivateKey] = self.key
 
142
        hash[:SSLStartImmediately] = true
 
143
        hash[:SSLEnable] = true
 
144
        hash[:SSLCACertificateFile] = Puppet[:localcacert]
 
145
        hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
 
146
        hash[:SSLCertName] = nil
 
147
 
 
148
        if addr = Puppet[:bindaddress] and addr != ""
 
149
          hash[:BindAddress] = addr
 
150
        end
 
151
      end
 
152
    end
 
153
  end
 
154
end
 
155