passenger 5.2.3 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (241) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +13 -0
  3. data/CONTRIBUTORS +5 -1
  4. data/build/agent.rb +22 -2
  5. data/build/cxx_tests.rb +41 -5
  6. data/build/misc.rb +4 -1
  7. data/build/support/cxx_dependency_map.rb +1746 -908
  8. data/build/support/vendor/cxx_hinted_parser/CxxHintedParser.sublime-project +8 -0
  9. data/build/support/vendor/cxx_hinted_parser/Gemfile +5 -0
  10. data/build/support/vendor/cxx_hinted_parser/Gemfile.lock +30 -0
  11. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core → build/support/vendor/cxx_hinted_parser}/LICENSE.md +1 -1
  12. data/build/support/vendor/cxx_hinted_parser/README.md +95 -0
  13. data/build/support/vendor/cxx_hinted_parser/Rakefile +4 -0
  14. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/initialize.rb → build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser.rb} +2 -9
  15. data/build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser/parser.rb +239 -0
  16. data/dev/ci/README.md +15 -2
  17. data/dev/ci/lib/set-container-envvars.sh +6 -0
  18. data/dev/ci/lib/setup-container.sh +4 -1
  19. data/dev/ci/scripts/debug-console-wrapper.sh +3 -1
  20. data/dev/ci/setup-host +5 -0
  21. data/dev/ci/tests/binaries/Jenkinsfile +105 -0
  22. data/dev/ci/tests/binaries/build-linux +38 -0
  23. data/dev/ci/tests/binaries/build-macos +40 -0
  24. data/dev/ci/tests/binaries/prepare-macos +38 -0
  25. data/dev/ci/tests/binaries/test-linux +45 -0
  26. data/dev/ci/tests/binaries/test-macos +38 -0
  27. data/dev/ci/tests/debian/Jenkinsfile +2 -2
  28. data/dev/ci/tests/rpm/Jenkinsfile +1 -1
  29. data/dev/configkit-schemas/index.json +3 -24
  30. data/dev/vagrant/nginx_rakefile +0 -1
  31. data/package.json +15 -5
  32. data/resources/templates/error_renderer/.editorconfig +19 -0
  33. data/resources/templates/error_renderer/with_details/README.md +9 -0
  34. data/resources/templates/error_renderer/with_details/dist/bundle.js +33 -0
  35. data/resources/templates/error_renderer/with_details/dist/styles.css +17 -0
  36. data/resources/templates/error_renderer/with_details/src/DetailsView.jsx +52 -0
  37. data/resources/templates/error_renderer/with_details/src/GetHelpView.jsx +61 -0
  38. data/resources/templates/error_renderer/with_details/src/JourneyView.css +50 -0
  39. data/resources/templates/error_renderer/with_details/src/JourneyView.jsx +621 -0
  40. data/resources/templates/error_renderer/with_details/src/PageMain.css +114 -0
  41. data/resources/templates/error_renderer/with_details/src/PageMain.jsx +136 -0
  42. data/resources/templates/error_renderer/with_details/src/ProblemDescriptionView.jsx +14 -0
  43. data/resources/templates/error_renderer/with_details/src/ProcessDetailsView.jsx +56 -0
  44. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.css +5 -0
  45. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.jsx +15 -0
  46. data/resources/templates/error_renderer/with_details/src/SummaryView.jsx +35 -0
  47. data/resources/templates/error_renderer/with_details/src/SystemComponentView.css +34 -0
  48. data/resources/templates/error_renderer/with_details/src/SystemComponentView.jsx +168 -0
  49. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.css +13 -0
  50. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.jsx +116 -0
  51. data/resources/templates/error_renderer/with_details/src/Tab.jsx +12 -0
  52. data/resources/templates/error_renderer/with_details/src/Tabs.jsx +104 -0
  53. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.css +3446 -0
  54. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.js +293 -0
  55. data/resources/templates/error_renderer/with_details/src/bootstrap/config.json +401 -0
  56. data/resources/templates/error_renderer/with_details/src/index.html.template +22 -0
  57. data/resources/templates/error_renderer/with_details/src/index.jsx +23 -0
  58. data/resources/templates/error_renderer/with_details/webpack.config.js +47 -0
  59. data/resources/templates/error_renderer/without_details/dist/bundle.js +1 -0
  60. data/resources/templates/error_renderer/without_details/dist/styles.css +1 -0
  61. data/resources/templates/{undisclosed_error.html.template → error_renderer/without_details/src/index.html.template} +7 -11
  62. data/resources/templates/error_renderer/without_details/src/index.js +1 -0
  63. data/resources/templates/{error_layout.css → error_renderer/without_details/src/main.css} +5 -2
  64. data/resources/templates/error_renderer/without_details/webpack.config.js +42 -0
  65. data/src/agent/AgentMain.cpp +3 -3
  66. data/src/agent/Core/ApplicationPool/BasicProcessInfo.h +13 -0
  67. data/src/agent/Core/ApplicationPool/Common.h +3 -4
  68. data/src/agent/Core/ApplicationPool/Context.h +27 -17
  69. data/src/agent/Core/ApplicationPool/Group.h +3 -1
  70. data/src/agent/Core/ApplicationPool/Group/InitializationAndShutdown.cpp +2 -12
  71. data/src/agent/Core/ApplicationPool/Group/InternalUtils.cpp +55 -10
  72. data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +1 -1
  73. data/src/agent/Core/ApplicationPool/Group/OutOfBandWork.cpp +1 -1
  74. data/src/agent/Core/ApplicationPool/Group/SpawningAndRestarting.cpp +13 -6
  75. data/src/agent/Core/ApplicationPool/Implementation.cpp +16 -100
  76. data/src/agent/Core/ApplicationPool/Options.h +8 -65
  77. data/src/agent/Core/ApplicationPool/Pool.h +4 -21
  78. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +1 -60
  79. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +10 -13
  80. data/src/agent/Core/ApplicationPool/Pool/InitializationAndShutdown.cpp +3 -8
  81. data/src/agent/Core/ApplicationPool/Pool/Miscellaneous.cpp +2 -34
  82. data/src/agent/Core/ApplicationPool/Pool/StateInspection.cpp +1 -1
  83. data/src/agent/Core/ApplicationPool/Process.cpp +17 -12
  84. data/src/agent/Core/ApplicationPool/Process.h +146 -93
  85. data/src/agent/Core/ApplicationPool/Session.h +2 -2
  86. data/src/agent/Core/ApplicationPool/Socket.h +28 -27
  87. data/src/agent/Core/Config.h +1 -3
  88. data/src/agent/Core/ConfigChange.cpp +2 -4
  89. data/src/agent/Core/Controller.h +2 -8
  90. data/src/agent/Core/Controller/BufferBody.cpp +0 -2
  91. data/src/agent/Core/Controller/CheckoutSession.cpp +12 -24
  92. data/src/agent/Core/Controller/Config.h +1 -9
  93. data/src/agent/Core/Controller/ForwardResponse.cpp +0 -34
  94. data/src/agent/Core/Controller/Hooks.cpp +0 -7
  95. data/src/agent/Core/Controller/InitRequest.cpp +0 -43
  96. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +0 -4
  97. data/src/agent/Core/Controller/Request.h +1 -35
  98. data/src/agent/Core/Controller/SendRequest.cpp +0 -32
  99. data/src/agent/Core/CoreMain.cpp +19 -32
  100. data/src/agent/Core/SpawningKit/Config.h +329 -55
  101. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h +369 -0
  102. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h.cxxcodebuilder +307 -0
  103. data/src/agent/Core/SpawningKit/Context.h +211 -0
  104. data/src/agent/Core/SpawningKit/DirectSpawner.h +112 -122
  105. data/src/agent/Core/SpawningKit/DummySpawner.h +59 -20
  106. data/src/agent/Core/SpawningKit/ErrorRenderer.h +117 -0
  107. data/src/agent/Core/SpawningKit/Exceptions.h +1157 -0
  108. data/src/agent/Core/SpawningKit/Factory.h +24 -17
  109. data/src/agent/Core/SpawningKit/{BackgroundIOCapturer.h → Handshake/BackgroundIOCapturer.h} +48 -18
  110. data/src/agent/Core/SpawningKit/Handshake/Perform.h +1650 -0
  111. data/src/agent/Core/SpawningKit/Handshake/Prepare.h +582 -0
  112. data/src/agent/Core/SpawningKit/Handshake/Session.h +91 -0
  113. data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +100 -0
  114. data/src/agent/Core/SpawningKit/Journey.h +561 -0
  115. data/src/agent/Core/SpawningKit/PipeWatcher.h +41 -18
  116. data/src/agent/Core/SpawningKit/README.md +534 -0
  117. data/src/agent/Core/SpawningKit/Result.h +182 -7
  118. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h +69 -0
  119. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h.cxxcodebuilder +110 -0
  120. data/src/agent/Core/SpawningKit/SmartSpawner.h +1027 -562
  121. data/src/agent/Core/SpawningKit/Spawner.h +70 -1134
  122. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +3 -33
  123. data/src/agent/README.md +2 -3
  124. data/src/agent/Shared/ApiServerUtils.h +2 -3
  125. data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +932 -0
  126. data/src/agent/Watchdog/Config.h +1 -3
  127. data/src/agent/Watchdog/WatchdogMain.cpp +2 -1
  128. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
  129. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  130. data/src/apache2_module/ConfigGeneral/ManifestGeneration.h +22 -13
  131. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +5 -0
  132. data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +3 -0
  133. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +13 -0
  134. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
  135. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +13 -0
  136. data/src/cxx_supportlib/Constants.h +3 -1
  137. data/src/cxx_supportlib/Exceptions.h +0 -121
  138. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +7 -6
  139. data/src/cxx_supportlib/LoggingKit/Logging.h +3 -1
  140. data/src/cxx_supportlib/Utils.cpp +42 -0
  141. data/src/cxx_supportlib/Utils.h +7 -0
  142. data/src/cxx_supportlib/Utils/IOUtils.cpp +58 -0
  143. data/src/cxx_supportlib/Utils/IOUtils.h +13 -0
  144. data/src/cxx_supportlib/Utils/JsonUtils.h +130 -23
  145. data/src/cxx_supportlib/Utils/ScopeGuard.h +9 -4
  146. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +7 -0
  147. data/src/cxx_supportlib/Utils/StrIntUtils.h +1 -0
  148. data/src/cxx_supportlib/Utils/SystemTime.h +1 -1
  149. data/src/cxx_supportlib/Utils/Timer.h +1 -1
  150. data/src/cxx_supportlib/WebSocketCommandReverseServer.h +6 -4
  151. data/src/cxx_supportlib/vendor-copy/adhoc_lve.h +1 -0
  152. data/src/helper-scripts/node-loader.js +54 -59
  153. data/src/helper-scripts/rack-loader.rb +63 -60
  154. data/src/helper-scripts/rack-preloader.rb +125 -72
  155. data/src/helper-scripts/wsgi-loader.py +100 -43
  156. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +120 -112
  157. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +15 -8
  158. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +142 -142
  159. data/src/nginx_module/ConfigGeneral/ManifestGeneration.c +26 -15
  160. data/src/nginx_module/ConfigGeneral/ManifestGeneration.h +3 -0
  161. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +76 -70
  162. data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +114 -99
  163. data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +170 -156
  164. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +38 -35
  165. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +5 -1
  166. data/src/ruby_supportlib/phusion_passenger.rb +5 -5
  167. data/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb +14 -1
  168. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +8 -0
  169. data/src/ruby_supportlib/phusion_passenger/common_library.rb +0 -3
  170. data/src/ruby_supportlib/phusion_passenger/config/nginx_engine_compiler.rb +0 -1
  171. data/src/ruby_supportlib/phusion_passenger/constants.rb +2 -0
  172. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +646 -238
  173. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +117 -95
  174. data/src/ruby_supportlib/phusion_passenger/packaging.rb +0 -1
  175. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +5 -1
  176. data/src/ruby_supportlib/phusion_passenger/preloader_shared_helpers.rb +92 -69
  177. data/src/ruby_supportlib/phusion_passenger/public_api.rb +0 -17
  178. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +0 -3
  179. data/src/ruby_supportlib/phusion_passenger/request_handler.rb +4 -5
  180. data/src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb +0 -22
  181. metadata +64 -67
  182. data/resources/templates/error_layout.html.template +0 -86
  183. data/resources/templates/general_error.html.template +0 -1
  184. data/resources/templates/general_error_with_html.html.template +0 -1
  185. data/src/agent/Core/ApplicationPool/ErrorRenderer.h +0 -131
  186. data/src/agent/Core/SpawningKit/Options.h +0 -41
  187. data/src/agent/Core/UnionStation/Connection.h +0 -173
  188. data/src/agent/Core/UnionStation/Context.h +0 -536
  189. data/src/agent/Core/UnionStation/StopwatchLog.h +0 -147
  190. data/src/agent/Core/UnionStation/Transaction.h +0 -249
  191. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +0 -208
  192. data/src/cxx_supportlib/UnionStationFilterSupport.cpp +0 -67
  193. data/src/cxx_supportlib/UnionStationFilterSupport.h +0 -1622
  194. data/src/nodejs_supportlib/phusion_passenger/log_express.js +0 -106
  195. data/src/nodejs_supportlib/phusion_passenger/log_mongodb.js +0 -202
  196. data/src/nodejs_supportlib/phusion_passenger/ustreporter.js +0 -227
  197. data/src/nodejs_supportlib/phusion_passenger/ustrouter_connector.js +0 -448
  198. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/CONFIG.md +0 -37
  199. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile +0 -17
  200. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile.lock +0 -59
  201. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README-API.md +0 -5
  202. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README.md +0 -117
  203. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Rakefile +0 -115
  204. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +0 -423
  205. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +0 -238
  206. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/connection.rb +0 -67
  207. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +0 -281
  208. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/lock.rb +0 -62
  209. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/log.rb +0 -66
  210. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/message_channel.rb +0 -157
  211. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +0 -150
  212. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/basics.rb +0 -199
  213. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/controllers.rb +0 -187
  214. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/misc.rb +0 -303
  215. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/view_rendering.rb +0 -91
  216. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +0 -396
  217. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +0 -279
  218. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +0 -39
  219. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +0 -173
  220. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +0 -177
  221. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version.rb +0 -32
  222. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version_data.rb +0 -44
  223. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.example +0 -16
  224. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis +0 -20
  225. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis-with-sudo +0 -18
  226. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/union_station_hooks_core.gemspec +0 -23
  227. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile +0 -14
  228. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile.lock +0 -45
  229. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/LICENSE.md +0 -19
  230. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/README.md +0 -104
  231. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Rakefile +0 -160
  232. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails.rb +0 -200
  233. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_controller_extension.rb +0 -45
  234. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_view_subscriber.rb +0 -55
  235. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_record_subscriber.rb +0 -41
  236. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_benchmarkable_extension.rb +0 -47
  237. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_cache_subscriber.rb +0 -79
  238. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/exception_logger.rb +0 -57
  239. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version.rb +0 -32
  240. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version_data.rb +0 -44
  241. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/union_station_hooks_rails.gemspec +0 -34
@@ -28,6 +28,7 @@
28
28
 
29
29
  #include <sys/types.h>
30
30
  #include <pwd.h>
31
+ #include <grp.h>
31
32
  #include <unistd.h>
32
33
  #include <string>
33
34
  #include <algorithm>
@@ -36,8 +37,8 @@
36
37
  #include <oxt/system_calls.hpp>
37
38
  #include <Exceptions.h>
38
39
  #include <Utils.h>
40
+ #include <Core/SpawningKit/Context.h>
39
41
  #include <FileTools/PathManip.h>
40
- #include <Core/SpawningKit/Options.h>
41
42
 
42
43
  namespace Passenger {
43
44
  namespace SpawningKit {
@@ -51,19 +52,15 @@ struct UserSwitchingInfo {
51
52
  bool enabled;
52
53
  string username;
53
54
  string groupname;
54
- string home;
55
- string shell;
56
55
  uid_t uid;
57
56
  gid_t gid;
58
- int ngroups;
59
- boost::shared_array<gid_t> gidset;
60
57
 
61
58
  struct passwd lveUserPwd, *lveUserPwdComplete;
62
59
  boost::shared_array<char> lveUserPwdStrBuf;
63
60
  };
64
61
 
65
62
  inline UserSwitchingInfo
66
- prepareUserSwitching(const Options &options) {
63
+ prepareUserSwitching(const AppPoolOptions &options) {
67
64
  TRACE_POINT();
68
65
  UserSwitchingInfo info;
69
66
 
@@ -90,11 +87,8 @@ prepareUserSwitching(const Options &options) {
90
87
  info.enabled = false;
91
88
  info.username = userInfo->pw_name;
92
89
  info.groupname = getGroupName(userInfo->pw_gid);
93
- info.home = userInfo->pw_dir;
94
- info.shell = userInfo->pw_shell;
95
90
  info.uid = geteuid();
96
91
  info.gid = getegid();
97
- info.ngroups = 0;
98
92
  return info;
99
93
  }
100
94
 
@@ -233,35 +227,11 @@ prepareUserSwitching(const Options &options) {
233
227
  }
234
228
 
235
229
  UPDATE_TRACE_POINT();
236
- #ifdef __APPLE__
237
- int groups[1024];
238
- info.ngroups = sizeof(groups) / sizeof(int);
239
- #else
240
- gid_t groups[1024];
241
- info.ngroups = sizeof(groups) / sizeof(gid_t);
242
- #endif
243
230
  info.enabled = true;
244
231
  info.username = userInfo->pw_name;
245
232
  info.groupname = getGroupName(groupId);
246
- info.home = userInfo->pw_dir;
247
- info.shell = userInfo->pw_shell;
248
233
  info.uid = userInfo->pw_uid;
249
234
  info.gid = groupId;
250
- #if !defined(HAVE_GETGROUPLIST) && (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
251
- #define HAVE_GETGROUPLIST
252
- #endif
253
- #ifdef HAVE_GETGROUPLIST
254
- ret = getgrouplist(userInfo->pw_name, groupId,
255
- groups, &info.ngroups);
256
- if (ret == -1) {
257
- int e = errno;
258
- throw SystemException("getgrouplist() failed", e);
259
- }
260
- info.gidset = boost::shared_array<gid_t>(new gid_t[info.ngroups]);
261
- for (int i = 0; i < info.ngroups; i++) {
262
- info.gidset[i] = groups[i];
263
- }
264
- #endif
265
235
 
266
236
  return info;
267
237
  }
@@ -6,13 +6,12 @@ This directory contains the source code of the Passenger agent. The Passenger ag
6
6
 
7
7
  The most important parts are:
8
8
 
9
- * The Watchdog is the main Passenger process. It starts the Passenger Core and the UstRouter, and restarts them when they crash. It also cleans everything up upon shut down.
9
+ * The Watchdog is the main Passenger process. It starts the Passenger Core, and restarts them when it crashes. It also cleans everything up upon shut down.
10
10
  * The Core performs most of the heavy lifting. It parses requests, spawns application processes, forwards requests to the correct process and forwards application responses back to the web server.
11
- * The UstRouter processes Union Station data and sends them to the Union Station server.
12
11
 
13
12
  ## Minor parts
14
13
 
15
- * SpawnPreparer is a tool used internally by the Core to spawn application processes.
14
+ * SpawnEnvSetupper is a tool used internally by `Core/SpawningKit/` to spawn application processes. See the README in that directory for more information.
16
15
  * SystemMetrics is a tool that shows system metrics such as CPU and memory usage. The main functionality is implemented in src/cxxUtils/SystemMetricsCollector.h. This tool is mainly useful for developing and debugging SystemMetricsCollector.h.
17
16
  * TempDirToucher is a tool used internally by Passenger Standalone to keep a temporary directory's timestamp up-to-date so that it doesn't get removed by /tmp cleaner daemons.
18
17
 
@@ -27,8 +27,8 @@
27
27
  #define _PASSENGER_API_SERVER_UTILS_H_
28
28
 
29
29
  /**
30
- * Utility code shared by agent/Core/ApiServer.h, agent/UstRouter/ApiServer.h
31
- * and agent/Watchdog/ApiServer.h. This code handles authentication and authorization
30
+ * Utility code shared by agent/Core/ApiServer.h and agent/Watchdog/ApiServer.h.
31
+ * This code handles authentication and authorization
32
32
  * of connected ApiServer clients.
33
33
  *
34
34
  * This file consists of the following items.
@@ -76,7 +76,6 @@
76
76
  #include <Utils/BufferedIO.h>
77
77
  #include <Utils/StrIntUtils.h>
78
78
  #include <Utils/VariantMap.h>
79
- #include <Core/ApplicationPool/Pool.h>
80
79
  #include <Shared/ApplicationPoolApiKey.h>
81
80
 
82
81
  namespace Passenger {
@@ -0,0 +1,932 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2012-2017 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ /*
28
+ * For an introduction see SpawningKit's README.md, section "The SpawnEnvSetupper".
29
+ */
30
+
31
+ #include <oxt/initialize.hpp>
32
+ #include <oxt/backtrace.hpp>
33
+ #include <boost/scoped_array.hpp>
34
+
35
+ #include <cstdio>
36
+ #include <cstdlib>
37
+ #include <cstring>
38
+ #include <cerrno>
39
+ #include <cassert>
40
+ #include <stdexcept>
41
+ #include <string>
42
+ #include <vector>
43
+
44
+ #include <sys/types.h>
45
+ #include <sys/param.h>
46
+ #include <sys/wait.h>
47
+ #include <sys/time.h>
48
+ #include <sys/resource.h>
49
+ #include <sys/stat.h>
50
+ #include <limits.h>
51
+ #include <unistd.h>
52
+ #include <pwd.h>
53
+ #include <grp.h>
54
+ #include <stdlib.h>
55
+ #include <string.h>
56
+
57
+ #include <jsoncpp/json.h>
58
+ #include <adhoc_lve.h>
59
+
60
+ #include <LoggingKit/LoggingKit.h>
61
+ #include <LoggingKit/Context.h>
62
+ #include <ProcessManagement/Spawn.h>
63
+ #include <FileTools/FileManip.h>
64
+ #include <FileTools/PathManip.h>
65
+ #include <Utils.h>
66
+ #include <Utils/IOUtils.h>
67
+ #include <Utils/StrIntUtils.h>
68
+ #include <Core/SpawningKit/Exceptions.h>
69
+
70
+ using namespace std;
71
+ using namespace Passenger;
72
+
73
+ extern "C" {
74
+ extern char **environ;
75
+ }
76
+
77
+
78
+ namespace Passenger {
79
+ namespace SpawnEnvSetupper {
80
+
81
+ enum Mode {
82
+ BEFORE_MODE,
83
+ AFTER_MODE
84
+ };
85
+
86
+ struct Context {
87
+ string workDir;
88
+ Mode mode;
89
+ Json::Value args;
90
+ SpawningKit::JourneyStep step;
91
+ };
92
+
93
+ } // namespace SpawnEnvSetupper
94
+ } // namespace Passenger
95
+
96
+ using namespace Passenger::SpawnEnvSetupper;
97
+
98
+
99
+ static Json::Value
100
+ readArgsJson(const string &workDir) {
101
+ Json::Reader reader;
102
+ Json::Value result;
103
+ string contents = readAll(workDir + "/args.json");
104
+ if (reader.parse(contents, result)) {
105
+ return result;
106
+ } else {
107
+ P_CRITICAL("Cannot parse " << workDir << "/args.json: "
108
+ << reader.getFormattedErrorMessages());
109
+ exit(1);
110
+ // Never reached
111
+ return Json::Value();
112
+ }
113
+ }
114
+
115
+ static void
116
+ initializeLogLevel(const Json::Value &args) {
117
+ if (args.isMember("log_level")) {
118
+ LoggingKit::setLevel(LoggingKit::Level(args["log_level"].asInt()));
119
+ }
120
+ }
121
+
122
+ static bool
123
+ tryWriteFile(const StaticString &path, const StaticString &value) {
124
+ try {
125
+ createFile(path.c_str(), value);
126
+ return true;
127
+ } catch (const FileSystemException &e) {
128
+ fprintf(stderr, "Warning: %s\n", e.what());
129
+ return false;
130
+ }
131
+ }
132
+
133
+ static void
134
+ recordJourneyStepBegin(const Context &context,
135
+ SpawningKit::JourneyStep step, SpawningKit::JourneyStepState state)
136
+ {
137
+ string stepString = journeyStepToStringLowerCase(step);
138
+ string stepDir = context.workDir + "/response/steps/" + stepString;
139
+ tryWriteFile(stepDir + "/state", SpawningKit::journeyStepStateToString(state));
140
+ tryWriteFile(stepDir + "/begin_time_monotonic", doubleToString(
141
+ SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_10MSEC>() / 1000000.0));
142
+ }
143
+
144
+ static void
145
+ recordJourneyStepEnd(const Context &context,
146
+ SpawningKit::JourneyStep step, SpawningKit::JourneyStepState state)
147
+ {
148
+ string stepString = journeyStepToStringLowerCase(step);
149
+ string stepDir = context.workDir + "/response/steps/" + stepString;
150
+ tryWriteFile(stepDir + "/state", SpawningKit::journeyStepStateToString(state));
151
+ if (!fileExists(stepDir + "/begin_time") && !fileExists(stepDir + "/begin_time_monotonic")) {
152
+ tryWriteFile(stepDir + "/begin_time_monotonic", doubleToString(
153
+ SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_10MSEC>() / 1000000.0));
154
+ }
155
+ tryWriteFile(stepDir + "/end_time_monotonic", doubleToString(
156
+ SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_10MSEC>() / 1000000.0));
157
+ }
158
+
159
+ static void
160
+ recordErrorCategory(const string &workDir, SpawningKit::ErrorCategory category) {
161
+ string path = workDir + "/response/error/category";
162
+ tryWriteFile(path, errorCategoryToString(category));
163
+ }
164
+
165
+ static void
166
+ recordAdvancedProblemDetails(const string &workDir, const string &message) {
167
+ string path = workDir + "/response/error/advanced_problem_details";
168
+ tryWriteFile(path, message);
169
+ }
170
+
171
+ static void
172
+ recordErrorSummary(const string &workDir, const string &message,
173
+ bool isAlsoAdvancedProblemDetails)
174
+ {
175
+ string path = workDir + "/response/error/summary";
176
+ tryWriteFile(path, message);
177
+ if (isAlsoAdvancedProblemDetails) {
178
+ recordAdvancedProblemDetails(workDir, message);
179
+ }
180
+ }
181
+
182
+ static void
183
+ recordAndPrintErrorSummary(const string &workDir, const string &message,
184
+ bool isAlsoAdvancedProblemDetails)
185
+ {
186
+ fprintf(stderr, "Error: %s\n", message.c_str());
187
+ recordErrorSummary(workDir, message, isAlsoAdvancedProblemDetails);
188
+ }
189
+
190
+ static void
191
+ recordProblemDescriptionHTML(const string &workDir, const string &message) {
192
+ string path = workDir + "/response/error/problem_description.html";
193
+ tryWriteFile(path, message);
194
+ }
195
+
196
+ static void
197
+ recordSolutionDescriptionHTML(const string &workDir, const string &message) {
198
+ string path = workDir + "/response/error/solution_description.html";
199
+ tryWriteFile(path, message);
200
+ }
201
+
202
+ static void
203
+ reopenStdout(int fd) {
204
+ dup2(fd, STDOUT_FILENO);
205
+ }
206
+
207
+ static void
208
+ dumpEnvvars(const string &workDir) {
209
+ FILE *f = fopen((workDir + "/envdump/envvars").c_str(), "w");
210
+ if (f == NULL) {
211
+ fprintf(stderr, "Warning: cannot open %s/envdump/envvars for writing\n",
212
+ workDir.c_str());
213
+ return;
214
+ }
215
+
216
+ const char *command[] = {
217
+ "env",
218
+ NULL
219
+ };
220
+ SubprocessInfo info;
221
+ runCommand(command, info, true, true,
222
+ boost::bind(reopenStdout, fileno(f)));
223
+ fclose(f);
224
+ }
225
+
226
+ static void
227
+ dumpUserInfo(const string &workDir) {
228
+ FILE *f = fopen((workDir + "/envdump/user_info").c_str(), "w");
229
+ if (f == NULL) {
230
+ fprintf(stderr, "Warning: cannot open %s/envdump/user_info for writing\n",
231
+ workDir.c_str());
232
+ return;
233
+ }
234
+
235
+ const char *command[] = {
236
+ "id",
237
+ NULL
238
+ };
239
+ SubprocessInfo info;
240
+ runCommand(command, info, true, true,
241
+ boost::bind(reopenStdout, fileno(f)));
242
+ fclose(f);
243
+ }
244
+
245
+ static void
246
+ dumpUlimits(const string &workDir) {
247
+ FILE *f = fopen((workDir + "/envdump/ulimits").c_str(), "w");
248
+ if (f == NULL) {
249
+ fprintf(stderr, "Warning: cannot open %s/envdump/ulimits for writing\n",
250
+ workDir.c_str());
251
+ return;
252
+ }
253
+
254
+ // On Linux, ulimit is a shell builtin and not a command.
255
+ const char *command[] = {
256
+ "/bin/sh",
257
+ "-c",
258
+ "ulimit -a",
259
+ NULL
260
+ };
261
+ SubprocessInfo info;
262
+ runCommand(command, info, true, true,
263
+ boost::bind(reopenStdout, fileno(f)));
264
+ fclose(f);
265
+ }
266
+
267
+ static void
268
+ dumpAllEnvironmentInfo(const string &workDir) {
269
+ dumpEnvvars(workDir);
270
+ dumpUserInfo(workDir);
271
+ dumpUlimits(workDir);
272
+ }
273
+
274
+ static bool
275
+ setUlimits(const Json::Value &args) {
276
+ if (!args.isMember("file_descriptor_ulimit")) {
277
+ return false;
278
+ }
279
+
280
+ rlim_t fdLimit = (rlim_t) args["file_descriptor_ulimit"].asUInt();
281
+ struct rlimit limit;
282
+ int ret;
283
+
284
+ limit.rlim_cur = fdLimit;
285
+ limit.rlim_max = fdLimit;
286
+ do {
287
+ ret = setrlimit(RLIMIT_NOFILE, &limit);
288
+ } while (ret == -1 && errno == EINTR);
289
+
290
+ if (ret == -1) {
291
+ int e = errno;
292
+ fprintf(stderr, "Error: unable to set file descriptor ulimit to %u: %s (errno=%d)",
293
+ (unsigned int) fdLimit, strerror(e), e);
294
+ }
295
+
296
+ return ret != -1;
297
+ }
298
+
299
+ static bool
300
+ canSwitchUser(const Json::Value &args) {
301
+ return args.isMember("user") && geteuid() == 0;
302
+ }
303
+
304
+ static void
305
+ lookupUserGroup(const Context &context, uid_t *uid, struct passwd **userInfo,
306
+ gid_t *gid)
307
+ {
308
+ const Json::Value &args = context.args;
309
+ errno = 0;
310
+ *userInfo = getpwnam(args["user"].asCString());
311
+ if (*userInfo == NULL) {
312
+ int e = errno;
313
+ if (looksLikePositiveNumber(args["user"].asString())) {
314
+ fprintf(stderr,
315
+ "Warning: error looking up system user database"
316
+ " entry for user '%s': %s (errno=%d)\n",
317
+ args["user"].asCString(), strerror(e), e);
318
+ *uid = (uid_t) atoi(args["user"].asString());
319
+ } else {
320
+ recordJourneyStepEnd(context, context.step,
321
+ SpawningKit::STEP_ERRORED);
322
+ recordErrorCategory(context.workDir,
323
+ SpawningKit::OPERATING_SYSTEM_ERROR);
324
+ recordAndPrintErrorSummary(context.workDir,
325
+ "Cannot lookup up system user database entry for user '"
326
+ + args["user"].asString() + "': " + strerror(e)
327
+ + " (errno=" + toString(e) + ")",
328
+ true);
329
+ exit(1);
330
+ }
331
+ } else {
332
+ *uid = (*userInfo)->pw_uid;
333
+ }
334
+
335
+ errno = 0;
336
+ struct group *groupInfo = getgrnam(args["group"].asCString());
337
+ if (groupInfo == NULL) {
338
+ int e = errno;
339
+ if (looksLikePositiveNumber(args["group"].asString())) {
340
+ fprintf(stderr,
341
+ "Warning: error looking up system group database entry for group '%s':"
342
+ " %s (errno=%d)\n",
343
+ args["group"].asCString(), strerror(e), e);
344
+ *gid = (gid_t) atoi(args["group"].asString());
345
+ } else {
346
+ recordJourneyStepEnd(context, context.step,
347
+ SpawningKit::STEP_ERRORED);
348
+ recordErrorCategory(context.workDir,
349
+ SpawningKit::OPERATING_SYSTEM_ERROR);
350
+ recordAndPrintErrorSummary(context.workDir,
351
+ "Cannot lookup up system group database entry for group '"
352
+ + args["group"].asString() + "': " + strerror(e)
353
+ + " (errno=" + toString(e) + ")",
354
+ true);
355
+ exit(1);
356
+ }
357
+ } else {
358
+ *gid = groupInfo->gr_gid;
359
+ }
360
+ }
361
+
362
+ void
363
+ chownNewWorkDirFiles(const Context &context, uid_t uid, gid_t gid) {
364
+ chown((context.workDir + "/response/steps/subprocess_before_first_exec/state").c_str(),
365
+ uid, gid);
366
+ chown((context.workDir + "/response/steps/subprocess_before_first_exec/duration").c_str(),
367
+ uid, gid);
368
+ chown((context.workDir + "/response/steps/subprocess_spawn_env_setupper_before_shell/state").c_str(),
369
+ uid, gid);
370
+ chown((context.workDir + "/response/steps/subprocess_spawn_env_setupper_before_shell/duration").c_str(),
371
+ uid, gid);
372
+ chown((context.workDir + "/envdump/envvars").c_str(),
373
+ uid, gid);
374
+ chown((context.workDir + "/envdump/user_info").c_str(),
375
+ uid, gid);
376
+ chown((context.workDir + "/envdump/ulimits").c_str(),
377
+ uid, gid);
378
+ }
379
+
380
+ static void
381
+ enterLveJail(const Context &context, const struct passwd *userInfo) {
382
+ string lveInitErr;
383
+ adhoc_lve::LibLve &liblve = adhoc_lve::LveInitSignleton::getInstance(&lveInitErr);
384
+
385
+ if (liblve.is_error()) {
386
+ if (!lveInitErr.empty()) {
387
+ lveInitErr = ": " + lveInitErr;
388
+ }
389
+ recordJourneyStepEnd(context, context.step,
390
+ SpawningKit::STEP_ERRORED);
391
+ recordErrorCategory(context.workDir,
392
+ SpawningKit::INTERNAL_ERROR);
393
+ recordAndPrintErrorSummary(context.workDir,
394
+ "Failed to initialize LVE library: " + lveInitErr,
395
+ true);
396
+ exit(1);
397
+ }
398
+
399
+ if (!liblve.is_lve_available()) {
400
+ return;
401
+ }
402
+
403
+ string jailErr;
404
+ int ret = liblve.jail(userInfo, jailErr);
405
+ if (ret < 0) {
406
+ recordJourneyStepEnd(context, context.step,
407
+ SpawningKit::STEP_ERRORED);
408
+ recordErrorCategory(context.workDir,
409
+ SpawningKit::INTERNAL_ERROR);
410
+ recordAndPrintErrorSummary(context.workDir,
411
+ "enterLve() failed: " + jailErr,
412
+ true);
413
+ exit(1);
414
+ }
415
+ }
416
+
417
+ static void
418
+ switchGroup(const Context &context, uid_t uid, const struct passwd *userInfo, gid_t gid) {
419
+ if (userInfo != NULL) {
420
+ bool setgroupsCalled = false;
421
+
422
+ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
423
+ #ifdef __APPLE__
424
+ int groups[1024];
425
+ int ngroups = sizeof(groups) / sizeof(int);
426
+ #else
427
+ gid_t groups[1024];
428
+ int ngroups = sizeof(groups) / sizeof(gid_t);
429
+ #endif
430
+ boost::scoped_array<gid_t> gidset;
431
+
432
+ int ret = getgrouplist(userInfo->pw_name, gid,
433
+ groups, &ngroups);
434
+ if (ret == -1) {
435
+ int e = errno;
436
+ recordJourneyStepEnd(context, context.step,
437
+ SpawningKit::STEP_ERRORED);
438
+ recordErrorCategory(context.workDir,
439
+ SpawningKit::OPERATING_SYSTEM_ERROR);
440
+ recordAndPrintErrorSummary(context.workDir,
441
+ "getgrouplist(" + string(userInfo->pw_name) + ", "
442
+ + toString(gid) + ") failed: " + strerror(e)
443
+ + " (errno=" + toString(e) + ")",
444
+ true);
445
+ exit(1);
446
+ }
447
+
448
+ if (ngroups <= NGROUPS_MAX) {
449
+ setgroupsCalled = true;
450
+ gidset.reset(new gid_t[ngroups]);
451
+ if (setgroups(ngroups, gidset.get()) == -1) {
452
+ int e = errno;
453
+ recordJourneyStepEnd(context, context.step,
454
+ SpawningKit::STEP_ERRORED);
455
+ recordErrorCategory(context.workDir,
456
+ SpawningKit::OPERATING_SYSTEM_ERROR);
457
+ recordAndPrintErrorSummary(context.workDir,
458
+ "setgroups(" + toString(ngroups)
459
+ + ", ...) failed: " + strerror(e) + " (errno="
460
+ + toString(e) + ")",
461
+ true);
462
+ exit(1);
463
+ }
464
+ }
465
+ #endif
466
+
467
+ if (!setgroupsCalled && initgroups(userInfo->pw_name, gid) == -1) {
468
+ int e = errno;
469
+ recordJourneyStepEnd(context, context.step,
470
+ SpawningKit::STEP_ERRORED);
471
+ recordErrorCategory(context.workDir,
472
+ SpawningKit::OPERATING_SYSTEM_ERROR);
473
+ recordAndPrintErrorSummary(context.workDir,
474
+ "initgroups(" + string(userInfo->pw_name)
475
+ + ", " + toString(gid) + ") failed: " + strerror(e)
476
+ + " (errno=" + toString(e) + ")",
477
+ true);
478
+ exit(1);
479
+ }
480
+ }
481
+
482
+ if (setgid(gid) == -1) {
483
+ int e = errno;
484
+ recordJourneyStepEnd(context, context.step,
485
+ SpawningKit::STEP_ERRORED);
486
+ recordErrorCategory(context.workDir,
487
+ SpawningKit::OPERATING_SYSTEM_ERROR);
488
+ recordAndPrintErrorSummary(context.workDir,
489
+ "setgid(" + toString(gid) + ") failed: "
490
+ + strerror(e) + " (errno=" + toString(e) + ")",
491
+ true);
492
+ exit(1);
493
+ }
494
+ }
495
+
496
+ static void
497
+ switchUser(const Context &context, uid_t uid, const struct passwd *userInfo) {
498
+ if (setuid(uid) == -1) {
499
+ int e = errno;
500
+ recordJourneyStepEnd(context, context.step,
501
+ SpawningKit::STEP_ERRORED);
502
+ recordErrorCategory(context.workDir,
503
+ SpawningKit::OPERATING_SYSTEM_ERROR);
504
+ recordAndPrintErrorSummary(context.workDir,
505
+ "setuid(" + toString(uid) + ") failed: " + strerror(e)
506
+ + " (errno=" + toString(e) + ")",
507
+ true);
508
+ exit(1);
509
+ }
510
+ if (userInfo != NULL) {
511
+ setenv("USER", userInfo->pw_name, 1);
512
+ setenv("LOGNAME", userInfo->pw_name, 1);
513
+ setenv("SHELL", userInfo->pw_shell, 1);
514
+ setenv("HOME", userInfo->pw_dir, 1);
515
+ } else {
516
+ unsetenv("USER");
517
+ unsetenv("LOGNAME");
518
+ unsetenv("SHELL");
519
+ unsetenv("HOME");
520
+ }
521
+ }
522
+
523
+ static string
524
+ lookupCurrentUserShell() {
525
+ struct passwd *userInfo = getpwuid(getuid());
526
+ if (userInfo == NULL) {
527
+ int e = errno;
528
+ fprintf(stderr, "Warning: cannot lookup system user database"
529
+ " entry for UID %d: %s (errno=%d)\n",
530
+ (int) getuid(), strerror(e), e);
531
+ return "/bin/sh";
532
+ } else {
533
+ return userInfo->pw_shell;
534
+ }
535
+ }
536
+
537
+ static vector<string>
538
+ inferAllParentDirectories(const string &path) {
539
+ vector<string> components, result;
540
+
541
+ split(path, '/', components);
542
+ P_ASSERT_EQ(components.front(), "");
543
+ components.erase(components.begin());
544
+
545
+ for (unsigned int i = 0; i < components.size(); i++) {
546
+ string path2;
547
+ for (unsigned int j = 0; j <= i; j++) {
548
+ path2.append("/");
549
+ path2.append(components[j]);
550
+ }
551
+ if (path2.empty()) {
552
+ path2 = "/";
553
+ }
554
+ result.push_back(path2);
555
+ }
556
+
557
+ P_ASSERT_EQ(result.back(), path);
558
+ return result;
559
+ }
560
+
561
+ static void
562
+ setCurrentWorkingDirectory(const Context &context) {
563
+ string appRoot = context.args["app_root"].asString(); // Already absolutized by HandshakePreparer
564
+ vector<string> appRootAndParentDirs = inferAllParentDirectories(appRoot);
565
+ vector<string>::const_iterator it;
566
+ int ret;
567
+
568
+ for (it = appRootAndParentDirs.begin(); it != appRootAndParentDirs.end(); it++) {
569
+ struct stat buf;
570
+ ret = stat(it->c_str(), &buf);
571
+ if (ret == -1 && errno == EACCES) {
572
+ char parent[PATH_MAX];
573
+ const char *end = strrchr(it->c_str(), '/');
574
+ memcpy(parent, it->c_str(), end - it->c_str());
575
+ parent[end - it->c_str()] = '\0';
576
+
577
+ recordJourneyStepEnd(context, context.step,
578
+ SpawningKit::STEP_ERRORED);
579
+ recordErrorCategory(context.workDir,
580
+ SpawningKit::OPERATING_SYSTEM_ERROR);
581
+ recordAndPrintErrorSummary(context.workDir,
582
+ "Directory '" + string(parent) + "' is inaccessible because of a"
583
+ " filesystem permission error.",
584
+ false);
585
+ recordProblemDescriptionHTML(context.workDir,
586
+ "<p>"
587
+ "The " PROGRAM_NAME " application server tried to start the"
588
+ " web application as user '" + escapeHTML(getProcessUsername())
589
+ + "' and group '" + escapeHTML(getGroupName(getgid()))
590
+ + "'. During this process, " SHORT_PROGRAM_NAME
591
+ " must be able to access its application root directory '"
592
+ + escapeHTML(appRoot) + "'. However, the parent directory '"
593
+ + escapeHTML(parent) + "' has wrong permissions, thereby preventing this"
594
+ " process from accessing its application root directory."
595
+ "</p>");
596
+ recordSolutionDescriptionHTML(context.workDir,
597
+ "<p class=\"sole-solution\">"
598
+ "Please fix the permissions of the directory '" + escapeHTML(appRoot)
599
+ + "' in such a way that the directory is accessible by user '"
600
+ + escapeHTML(getProcessUsername()) + "' and group '"
601
+ + escapeHTML(getGroupName(getgid())) + "'."
602
+ "</p>");
603
+ exit(1);
604
+ } else if (ret == -1) {
605
+ int e = errno;
606
+ recordJourneyStepEnd(context, context.step,
607
+ SpawningKit::STEP_ERRORED);
608
+ recordErrorCategory(context.workDir,
609
+ SpawningKit::OPERATING_SYSTEM_ERROR);
610
+ recordAndPrintErrorSummary(context.workDir,
611
+ "Unable to stat() directory '" + *it + "': "
612
+ + strerror(e) + " (errno=" + toString(e) + ")",
613
+ true);
614
+ exit(1);
615
+ }
616
+ }
617
+
618
+ ret = chdir(appRoot.c_str());
619
+ if (ret != 0) {
620
+ int e = errno;
621
+ recordJourneyStepEnd(context, context.step,
622
+ SpawningKit::STEP_ERRORED);
623
+ recordErrorCategory(context.workDir,
624
+ SpawningKit::OPERATING_SYSTEM_ERROR);
625
+ recordAndPrintErrorSummary(context.workDir,
626
+ "Unable to change working directory to '" + appRoot + "': "
627
+ + strerror(e) + " (errno=" + toString(e) + ")",
628
+ true);
629
+ if (e == EPERM || e == EACCES) {
630
+ recordProblemDescriptionHTML(context.workDir,
631
+ "<p>The " PROGRAM_NAME " application server tried to start the"
632
+ " web application as user " + escapeHTML(getProcessUsername())
633
+ + " and group " + escapeHTML(getGroupName(getgid()))
634
+ + ", with a working directory of "
635
+ + escapeHTML(appRoot) + ". However, it encountered a filesystem"
636
+ " permission error while doing this.</p>");
637
+ } else {
638
+ recordProblemDescriptionHTML(context.workDir,
639
+ "<p>The " PROGRAM_NAME " application server tried to start the"
640
+ " web application as user " + escapeHTML(getProcessUsername())
641
+ + " and group " + escapeHTML(getGroupName(getgid()))
642
+ + ", with a working directory of "
643
+ + escapeHTML(appRoot) + ". However, it encountered a filesystem"
644
+ " error while doing this.</p>");
645
+ }
646
+ exit(1);
647
+ }
648
+
649
+ // The application root may contain one or more symlinks
650
+ // in its path. If the application calls getcwd(), it will
651
+ // get the resolved path.
652
+ //
653
+ // It turns out that there is no such thing as a path without
654
+ // unresolved symlinks. The shell presents a working directory with
655
+ // unresolved symlinks (which it calls the "logical working directory"),
656
+ // but that is an illusion provided by the shell. The shell reports
657
+ // the logical working directory though the PWD environment variable.
658
+ //
659
+ // See also:
660
+ // https://github.com/phusion/passenger/issues/1596#issuecomment-138154045
661
+ // http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/pwd.c
662
+ // http://www.opensource.apple.com/source/shell_cmds/shell_cmds-170/pwd/pwd.c
663
+ setenv("PWD", appRoot.c_str(), 1);
664
+ }
665
+
666
+ static void
667
+ setDefaultEnvvars(const Json::Value &args) {
668
+ setenv("PYTHONUNBUFFERED", "1", 1);
669
+
670
+ setenv("NODE_PATH", args["node_libdir"].asCString(), 1);
671
+
672
+ setenv("RAILS_ENV", args["app_env"].asCString(), 1);
673
+ setenv("RACK_ENV", args["app_env"].asCString(), 1);
674
+ setenv("WSGI_ENV", args["app_env"].asCString(), 1);
675
+ setenv("NODE_ENV", args["app_env"].asCString(), 1);
676
+ setenv("PASSENGER_APP_ENV", args["app_env"].asCString(), 1);
677
+
678
+ if (args.isMember("expected_start_port")) {
679
+ setenv("PORT", toString(args["expected_start_port"].asInt()).c_str(), 1);
680
+ }
681
+
682
+ if (args["base_uri"].asString() != "/") {
683
+ setenv("RAILS_RELATIVE_URL_ROOT", args["base_uri"].asCString(), 1);
684
+ setenv("RACK_BASE_URI", args["base_uri"].asCString(), 1);
685
+ setenv("PASSENGER_BASE_URI", args["base_uri"].asCString(), 1);
686
+ } else {
687
+ unsetenv("RAILS_RELATIVE_URL_ROOT");
688
+ unsetenv("RACK_BASE_URI");
689
+ unsetenv("PASSENGER_BASE_URI");
690
+ }
691
+ }
692
+
693
+ static void
694
+ setGivenEnvVars(const Json::Value &args) {
695
+ const Json::Value &envvars = args["environment_variables"];
696
+ Json::Value::const_iterator it, end = envvars.end();
697
+
698
+ for (it = envvars.begin(); it != end; it++) {
699
+ string key = it.name();
700
+ setenv(key.c_str(), it->asCString(), 1);
701
+ }
702
+ }
703
+
704
+ static bool
705
+ shouldLoadShellEnvvars(const Json::Value &args, const string &shell) {
706
+ if (args["load_shell_envvars"].asBool()) {
707
+ string shellName = extractBaseName(shell);
708
+ bool result = shellName == "bash" || shellName == "zsh" || shellName == "ksh";
709
+ #if defined(__linux__) || defined(__APPLE__)
710
+ // On Linux, /bin/sh is usually either bash or dash, which
711
+ // supports -l.
712
+ // On macOS, it is not clear what /bin/sh is but
713
+ // it supports -l.
714
+ // This cannot be said of other platforms: for example on
715
+ // FreeBSD, /bin/sh does not support -l.
716
+ result = result || shellName == "sh";
717
+ #endif
718
+ P_DEBUG("shellName = '" << shellName << "' detected as supporting '-l': " << (result ? "true" : "false"));
719
+ return result;
720
+ } else {
721
+ return false;
722
+ }
723
+ }
724
+
725
+ static string
726
+ commandArgsToString(const vector<const char *> &commandArgs) {
727
+ vector<const char *>::const_iterator it;
728
+ string result;
729
+
730
+ for (it = commandArgs.begin(); it != commandArgs.end(); it++) {
731
+ if (*it != NULL) {
732
+ result.append(*it);
733
+ result.append(1, ' ');
734
+ }
735
+ }
736
+
737
+ return strip(result);
738
+ }
739
+
740
+ static bool
741
+ executedThroughShell(const Context &context) {
742
+ return fileExists(context.workDir + "/execute_through_os_shell");
743
+ }
744
+
745
+ static void
746
+ execNextCommand(const Context &context, const string &shell)
747
+ {
748
+ vector<const char *> commandArgs;
749
+ SpawningKit::JourneyStep nextJourneyStep;
750
+ string binShPath, binShParam;
751
+
752
+ // Note: do not try to set a process title in this function by messing with argv[0].
753
+ // https://code.google.com/p/phusion-passenger/issues/detail?id=855
754
+
755
+ if (context.mode == BEFORE_MODE) {
756
+ assert(!shell.empty());
757
+ if (shouldLoadShellEnvvars(context.args, shell)) {
758
+ nextJourneyStep = SpawningKit::SUBPROCESS_OS_SHELL;
759
+ commandArgs.push_back(shell.c_str());
760
+ if (LoggingKit::getLevel() >= LoggingKit::DEBUG3) {
761
+ commandArgs.push_back("-x");
762
+ }
763
+ commandArgs.push_back("-lc");
764
+ commandArgs.push_back("exec \"$@\"");
765
+ commandArgs.push_back("SpawnEnvSetupperShell");
766
+
767
+ // Will be used by 'spawn-env-setupper --after' to determine
768
+ // whether it should set the SUBPROCESS_OS_SHELL step to the
769
+ // PERFORMED state.
770
+ tryWriteFile(context.workDir + "/execute_through_os_shell", "");
771
+ } else {
772
+ nextJourneyStep = SpawningKit::SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL;
773
+ }
774
+ commandArgs.push_back(context.args["passenger_agent_path"].asCString());
775
+ commandArgs.push_back("spawn-env-setupper");
776
+ commandArgs.push_back(context.workDir.c_str());
777
+ commandArgs.push_back("--after");
778
+ } else {
779
+ if (context.args["starts_using_wrapper"].asBool()) {
780
+ nextJourneyStep = SpawningKit::SUBPROCESS_EXEC_WRAPPER;
781
+ } else {
782
+ nextJourneyStep = SpawningKit::SUBPROCESS_APP_LOAD_OR_EXEC;
783
+ }
784
+ if (context.args.isMember("_bin_sh_path")) {
785
+ // Used in unit tests
786
+ binShPath = context.args["_bin_sh_path"].asString();
787
+ } else {
788
+ binShPath = "/bin/sh";
789
+ }
790
+ binShParam = "exec " + context.args["start_command"].asString();
791
+ commandArgs.push_back(binShPath.c_str());
792
+ commandArgs.push_back("-c");
793
+ commandArgs.push_back(binShParam.c_str());
794
+ }
795
+ commandArgs.push_back(NULL);
796
+
797
+ recordJourneyStepEnd(context, context.step,
798
+ SpawningKit::STEP_PERFORMED);
799
+ recordJourneyStepBegin(context, nextJourneyStep,
800
+ SpawningKit::STEP_IN_PROGRESS);
801
+
802
+ execvp(commandArgs[0], (char * const *) &commandArgs[0]);
803
+
804
+ int e = errno;
805
+ recordJourneyStepEnd(context, nextJourneyStep,
806
+ SpawningKit::STEP_ERRORED);
807
+ recordErrorCategory(context.workDir, SpawningKit::OPERATING_SYSTEM_ERROR);
808
+ recordAndPrintErrorSummary(context.workDir,
809
+ "Unable to execute command '" + commandArgsToString(commandArgs)
810
+ + "': " + strerror(e) + " (errno=" + toString(e) + ")",
811
+ true);
812
+ exit(1);
813
+ }
814
+
815
+ int
816
+ spawnEnvSetupperMain(int argc, char *argv[]) {
817
+ setvbuf(stdout, NULL, _IONBF, 0);
818
+ setvbuf(stderr, NULL, _IONBF, 0);
819
+
820
+ if (argc != 4) {
821
+ fprintf(stderr, "Usage: PassengerAgent spawn-env-setupper <workdir> <--before|--after>\n");
822
+ exit(1);
823
+ }
824
+
825
+ oxt::initialize();
826
+ oxt::setup_syscall_interruption_support();
827
+ LoggingKit::initialize();
828
+ SystemTime::initialize();
829
+
830
+ Context context;
831
+ context.workDir = argv[2];
832
+ context.mode =
833
+ (strcmp(argv[3], "--before") == 0)
834
+ ? BEFORE_MODE
835
+ : AFTER_MODE;
836
+ context.step =
837
+ (context.mode == BEFORE_MODE)
838
+ ? SpawningKit::SUBPROCESS_SPAWN_ENV_SETUPPER_BEFORE_SHELL
839
+ : SpawningKit::SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL;
840
+
841
+ setenv("IN_PASSENGER", "1", 1);
842
+ setenv("PASSENGER_SPAWN_WORK_DIR", context.workDir.c_str(), 1);
843
+ if (context.mode == BEFORE_MODE) {
844
+ recordJourneyStepEnd(context, SpawningKit::SUBPROCESS_BEFORE_FIRST_EXEC,
845
+ SpawningKit::STEP_PERFORMED);
846
+ }
847
+ recordJourneyStepBegin(context, context.step,
848
+ SpawningKit::STEP_IN_PROGRESS);
849
+
850
+ try {
851
+ context.args = readArgsJson(context.workDir);
852
+ bool shouldTrySwitchUser = canSwitchUser(context.args);
853
+ string shell;
854
+
855
+ initializeLogLevel(context.args);
856
+ dumpAllEnvironmentInfo(context.workDir);
857
+
858
+ if (context.mode == BEFORE_MODE) {
859
+ struct passwd *userInfo = NULL;
860
+ uid_t uid;
861
+ gid_t gid;
862
+
863
+ setDefaultEnvvars(context.args);
864
+ dumpEnvvars(context.workDir);
865
+
866
+ if (shouldTrySwitchUser) {
867
+ lookupUserGroup(context, &uid, &userInfo, &gid);
868
+ shell = userInfo->pw_shell;
869
+ } else {
870
+ shell = lookupCurrentUserShell();
871
+ }
872
+ if (setUlimits(context.args)) {
873
+ dumpUlimits(context.workDir);
874
+ }
875
+ if (shouldTrySwitchUser) {
876
+ chownNewWorkDirFiles(context, uid, gid);
877
+
878
+ enterLveJail(context, userInfo);
879
+ switchGroup(context, uid, userInfo, gid);
880
+ dumpUserInfo(context.workDir);
881
+
882
+ switchUser(context, uid, userInfo);
883
+ dumpEnvvars(context.workDir);
884
+ dumpUserInfo(context.workDir);
885
+ }
886
+ } else if (executedThroughShell(context)) {
887
+ recordJourneyStepEnd(context, SpawningKit::SUBPROCESS_OS_SHELL,
888
+ SpawningKit::STEP_PERFORMED);
889
+ } else {
890
+ recordJourneyStepEnd(context, SpawningKit::SUBPROCESS_OS_SHELL,
891
+ SpawningKit::STEP_NOT_STARTED);
892
+ }
893
+
894
+ setCurrentWorkingDirectory(context);
895
+ dumpEnvvars(context.workDir);
896
+
897
+ if (context.mode == AFTER_MODE) {
898
+ setDefaultEnvvars(context.args);
899
+ setGivenEnvVars(context.args);
900
+ dumpEnvvars(context.workDir);
901
+ }
902
+
903
+ execNextCommand(context, shell);
904
+ } catch (const oxt::tracable_exception &e) {
905
+ fprintf(stderr, "Error: %s\n%s\n",
906
+ e.what(), e.backtrace().c_str());
907
+ recordJourneyStepEnd(context, context.step,
908
+ SpawningKit::STEP_ERRORED);
909
+ recordErrorCategory(context.workDir,
910
+ SpawningKit::inferErrorCategoryFromAnotherException(
911
+ e, context.step));
912
+ recordErrorSummary(context.workDir, e.what(), true);
913
+ return 1;
914
+ } catch (const std::exception &e) {
915
+ fprintf(stderr, "Error: %s\n", e.what());
916
+ recordJourneyStepEnd(context, context.step,
917
+ SpawningKit::STEP_ERRORED);
918
+ recordErrorCategory(context.workDir,
919
+ SpawningKit::inferErrorCategoryFromAnotherException(
920
+ e, context.step));
921
+ recordErrorSummary(context.workDir, e.what(), true);
922
+ return 1;
923
+ }
924
+
925
+ // Should never be reached
926
+ recordJourneyStepEnd(context, context.step,
927
+ SpawningKit::STEP_ERRORED);
928
+ recordAndPrintErrorSummary(context.workDir,
929
+ "*** BUG IN SpawnEnvSetupper ***: end of main() reached",
930
+ true);
931
+ return 1;
932
+ }