This file is indexed.

/usr/share/passenger/helper-scripts/meteor-loader.rb is in ruby-passenger 4.0.53-1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  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
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#!/usr/bin/env ruby
# encoding: binary
#  Phusion Passenger - https://www.phusionpassenger.com/
#  Copyright (c) 2010-2014 Phusion
#
#  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.

require 'socket'
require 'thread'
require 'logger'

module PhusionPassenger
module App
	def self.options
		return @@options
	end
	
	def self.exit_code_for_exception(e)
		if e.is_a?(SystemExit)
			return e.status
		else
			return 1
		end
	end
	
	def self.handshake_and_read_startup_request
		STDOUT.sync = true
		STDERR.sync = true
		puts "!> I have control 1.0"
		abort "Invalid initialization header" if STDIN.readline != "You have control 1.0\n"
		
		@@options = {}
		while (line = STDIN.readline) != "\n"
			name, value = line.strip.split(/: */, 2)
			@@options[name] = value
		end
	end

	def self.init_passenger
		require "#{options["ruby_libdir"]}/phusion_passenger"
		PhusionPassenger.locate_directories(options["passenger_root"])
		PhusionPassenger.require_passenger_lib 'message_channel'
		PhusionPassenger.require_passenger_lib 'utils/tmpio'
	end

	def self.ping_port(port)
		socket_domain = Socket::Constants::AF_INET
		sockaddr = Socket.pack_sockaddr_in(port, '127.0.0.1')
		begin
			socket = Socket.new(socket_domain, Socket::Constants::SOCK_STREAM, 0)
			begin
				socket.connect_nonblock(sockaddr)
			rescue Errno::ENOENT, Errno::EINPROGRESS, Errno::EAGAIN, Errno::EWOULDBLOCK
				if select(nil, [socket], nil, 0.1)
					begin
						socket.connect_nonblock(sockaddr)
					rescue Errno::EISCONN
					end
				else
					raise Errno::ECONNREFUSED
				end
			end
			return true
		rescue Errno::ECONNREFUSED, Errno::ENOENT
			return false
		ensure
			socket.close if socket
		end
	end
	
	def self.create_control_server
		dir = Utils.mktmpdir('meteor')
		filename = "#{dir}/control"
		server = UNIXServer.new(filename)
		return [server, dir, filename]
	end

	def self.load_app(control_server)
		port = nil
		tries = 0
		while port.nil? && tries < 200
			port = 1024 + rand(9999)
			if ping_port(port) || ping_port(port + 1) || ping_port(port + 2)
				port = nil
				tries += 1
			end
		end
		if port.nil?
			abort "Cannot find a suitable port to start Meteor on"
		end

		production = options["environment"] == "production" ? "--production" : ""
		pid = fork do
			# Meteor is quite !@#$% here: if we kill its start script
			# with *any* signal, it'll leave a ton of garbage processes
			# around. Apparently it expects the user to press Ctrl-C in a
			# terminal which happens to send a signal to all processes
			# in the session. We emulate that behavior here by giving
			# Meteor its own process group, and sending signals to the
			# entire process group.
			Process.setpgrp
			control_server.close
			exec("meteor run -p #{port} #{production}")
		end
		$0 = options["process_title"] if options["process_title"]
		$0 = "#{$0} (#{pid})"
		return [pid, port]
	end

	class ExitFlag
		def initialize
			@mutex = Mutex.new
			@cond  = ConditionVariable.new
			@exit  = false
		end

		def set
			@mutex.synchronize do
				@exit = true
				@cond.broadcast
			end
		end

		def wait
			@mutex.synchronize do
				while !@exit
					@cond.wait(@mutex)
				end
			end
		end
	end

	# When the HelperAgent is shutting down, it first sends a message (A) to application
	# processes through the control socket that this is happening. The HelperAgent then
	# waits until all HTTP connections are closed, before sending another message
	# to application processes that they should shut down (B).
	# Because Meteor opens long-running connections (e.g. for WebSocket), we have to shut
	# down the Meteor app when A arrives, otherwise the HelperAgent will never send B.
	def self.wait_for_exit_message(control_server)
		exit_flag = ExitFlag.new
		start_control_server_thread(control_server, exit_flag)
		start_stdin_waiter_thread(exit_flag)
		exit_flag.wait
	end

	def self.start_control_server_thread(control_server, exit_flag)
		Thread.new do
			Thread.current.abort_on_exception = true
			while true
				process_next_control_client(control_server, exit_flag)
			end
		end
	end

	def self.process_next_control_client(control_server, exit_flag)
		logger = Logger.new(STDERR)
		begin
			client = control_server.accept
			channel = MessageChannel.new(client)
			while message = channel.read
				process_next_control_message(message, logger, exit_flag)
			end
		rescue Exception => e
			logger.error("#{e} (#{e.class})\n  " + e.backtrace.join("\n  "))
		ensure
			begin
				client.close if client
			rescue SystemCallError, IOError, SocketError
			end
		end
	end

	def self.process_next_control_message(message, logger, exit_flag)
		if message[0] == "abort_long_running_connections"
			logger.debug("Aborting long-running connections")
			exit_flag.set
		else
			logger.error("Invalid control message: #{message.inspect}")
		end
	end

	def self.start_stdin_waiter_thread(exit_flag)
		Thread.new do
			Thread.current.abort_on_exception = true
			begin
				STDIN.readline
			rescue EOFError
			ensure
				exit_flag.set
			end
		end
	end

	
	
	################## Main code ##################
	
	
	handshake_and_read_startup_request
	init_passenger
	begin
		control_server, control_dir, control_filename = create_control_server
		pid, port = load_app(control_server)
		while !ping_port(port)
			sleep 0.01
		end
		puts "!> Ready"
		puts "!> socket: main;tcp://127.0.0.1:#{port};http_session;0"
		puts "!> socket: control;unix:#{control_filename};control;0"
		puts "!> "
		wait_for_exit_message(control_server)
	ensure
		if pid
			Process.kill('INT', -pid) rescue nil
			Process.waitpid(pid) rescue nil
			Process.kill('INT', -pid) rescue nil
		end
		if control_server
			control_server.close
			begin
				File.unlink(control_filename)
			rescue SystemCallError
			end
			require 'fileutils'
			begin
				FileUtils.remove_entry_secure(control_dir)
			rescue SystemCallError
			end
		end
	end
	
end # module App
end # module PhusionPassenger