passenger 5.0.9 → 5.0.10

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 (106) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +15 -0
  5. data/CONTRIBUTORS +6 -0
  6. data/README.md +1 -1
  7. data/bin/passenger-install-apache2-module +24 -11
  8. data/bin/passenger-status +29 -14
  9. data/build/agents.rb +12 -10
  10. data/build/cxx_tests.rb +30 -30
  11. data/doc/Design and Architecture.html +1 -10
  12. data/doc/Design and Architecture.txt +1 -6
  13. data/doc/Users guide Apache.html +1 -19
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +2 -20
  16. data/doc/Users guide Nginx.txt +2 -2
  17. data/doc/users_guide_snippets/tips.txt +0 -9
  18. data/ext/common/ApplicationPool2/ApiKey.h +158 -0
  19. data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
  20. data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
  21. data/ext/common/ApplicationPool2/Common.h +5 -44
  22. data/ext/common/ApplicationPool2/Context.h +94 -0
  23. data/ext/common/ApplicationPool2/Group.h +130 -1205
  24. data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
  25. data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
  26. data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
  27. data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
  28. data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
  29. data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
  30. data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
  31. data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
  32. data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
  33. data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
  34. data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
  35. data/ext/common/ApplicationPool2/Options.h +5 -5
  36. data/ext/common/ApplicationPool2/Pool.h +260 -815
  37. data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
  38. data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
  39. data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
  40. data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
  41. data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
  42. data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
  43. data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
  44. data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
  45. data/ext/common/ApplicationPool2/Process.h +399 -205
  46. data/ext/common/ApplicationPool2/Session.h +70 -28
  47. data/ext/common/ApplicationPool2/Socket.h +1 -0
  48. data/ext/common/Constants.h +11 -3
  49. data/ext/common/Exceptions.h +1 -1
  50. data/ext/common/Logging.cpp +9 -4
  51. data/ext/common/Logging.h +6 -0
  52. data/ext/common/ServerKit/HttpServer.h +225 -215
  53. data/ext/common/ServerKit/Server.h +57 -57
  54. data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
  55. data/ext/common/SpawningKit/Config.h +107 -0
  56. data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
  57. data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
  58. data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
  59. data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
  60. data/ext/common/SpawningKit/PipeWatcher.h +148 -0
  61. data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
  62. data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
  63. data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
  64. data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
  65. data/ext/common/Utils/BufferedIO.h +24 -0
  66. data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
  67. data/ext/common/Utils/IOUtils.cpp +70 -0
  68. data/ext/common/Utils/IOUtils.h +19 -0
  69. data/ext/common/Utils/JsonUtils.h +113 -0
  70. data/ext/common/Utils/StrIntUtils.h +29 -0
  71. data/ext/common/Utils/json.h +1 -1
  72. data/ext/common/agents/ApiServerUtils.h +941 -0
  73. data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
  74. data/ext/common/agents/HelperAgent/Main.cpp +86 -88
  75. data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
  76. data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
  77. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
  78. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
  79. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
  80. data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
  81. data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
  82. data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
  83. data/ext/common/agents/Watchdog/ApiServer.h +311 -0
  84. data/ext/common/agents/Watchdog/Main.cpp +91 -65
  85. data/helper-scripts/prespawn +2 -0
  86. data/lib/phusion_passenger.rb +1 -1
  87. data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
  88. data/lib/phusion_passenger/common_library.rb +27 -14
  89. data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
  90. data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
  91. data/lib/phusion_passenger/config/main.rb +3 -5
  92. data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
  93. data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
  94. data/lib/phusion_passenger/config/utils.rb +15 -8
  95. data/lib/phusion_passenger/constants.rb +6 -2
  96. data/lib/phusion_passenger/platform_info/apache.rb +4 -0
  97. data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
  98. data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
  99. metadata +42 -21
  100. metadata.gz.asc +7 -7
  101. data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
  102. data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
  103. data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
  104. data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
  105. data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
  106. data/ext/common/agents/Watchdog/AdminServer.h +0 -432
@@ -22,8 +22,8 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  * THE SOFTWARE.
24
24
  */
25
- #ifndef _PASSENGER_APPLICATION_POOL_SPAWNER_H_
26
- #define _PASSENGER_APPLICATION_POOL_SPAWNER_H_
25
+ #ifndef _PASSENGER_SPAWNING_KIT_SPAWNER_H_
26
+ #define _PASSENGER_SPAWNING_KIT_SPAWNER_H_
27
27
 
28
28
  /*
29
29
  * This file implements application spawning support. Several classes
@@ -77,11 +77,11 @@
77
77
  #include <pwd.h>
78
78
  #include <grp.h>
79
79
  #include <dirent.h>
80
- #include <ApplicationPool2/Common.h>
81
- #include <ApplicationPool2/Process.h>
82
- #include <ApplicationPool2/Options.h>
83
- #include <ApplicationPool2/SpawnObject.h>
84
- #include <ApplicationPool2/PipeWatcher.h>
80
+ #include <SpawningKit/Config.h>
81
+ #include <SpawningKit/Options.h>
82
+ #include <SpawningKit/Result.h>
83
+ #include <SpawningKit/BackgroundIOCapturer.h>
84
+ #include <SpawningKit/UserSwitchingRules.h>
85
85
  #include <FileDescriptor.h>
86
86
  #include <Exceptions.h>
87
87
  #include <StaticString.h>
@@ -100,7 +100,7 @@ namespace tut {
100
100
  }
101
101
 
102
102
  namespace Passenger {
103
- namespace ApplicationPool2 {
103
+ namespace SpawningKit {
104
104
 
105
105
  using namespace std;
106
106
  using namespace boost;
@@ -112,111 +112,6 @@ protected:
112
112
  friend struct tut::ApplicationPool2_DirectSpawnerTest;
113
113
  friend struct tut::ApplicationPool2_SmartSpawnerTest;
114
114
 
115
- /**
116
- * Given a file descriptor, captures its output in a background thread
117
- * and also forwards it immediately to a target file descriptor.
118
- * Call stop() to stop the background thread and to obtain the captured
119
- * output so far.
120
- */
121
- class BackgroundIOCapturer {
122
- private:
123
- FileDescriptor fd;
124
- pid_t pid;
125
- const char *channelName;
126
- boost::mutex dataSyncher;
127
- string data;
128
- oxt::thread *thr;
129
-
130
- void capture() {
131
- TRACE_POINT();
132
- while (!this_thread::interruption_requested()) {
133
- char buf[1024 * 8];
134
- ssize_t ret;
135
-
136
- UPDATE_TRACE_POINT();
137
- ret = syscalls::read(fd, buf, sizeof(buf));
138
- int e = errno;
139
- this_thread::disable_syscall_interruption dsi;
140
- if (ret == 0) {
141
- break;
142
- } else if (ret == -1) {
143
- if (e != EAGAIN && e != EWOULDBLOCK) {
144
- P_WARN("Background I/O capturer error: " <<
145
- strerror(e) << " (errno=" << e << ")");
146
- break;
147
- }
148
- } else {
149
- {
150
- boost::lock_guard<boost::mutex> l(dataSyncher);
151
- data.append(buf, ret);
152
- }
153
- UPDATE_TRACE_POINT();
154
- if (ret == 1 && buf[0] == '\n') {
155
- printAppOutput(pid, channelName, "", 0);
156
- } else {
157
- vector<StaticString> lines;
158
- if (ret > 0 && buf[ret - 1] == '\n') {
159
- ret--;
160
- }
161
- split(StaticString(buf, ret), '\n', lines);
162
- foreach (const StaticString line, lines) {
163
- printAppOutput(pid, channelName, line.data(), line.size());
164
- }
165
- }
166
- }
167
- }
168
- }
169
-
170
- public:
171
- BackgroundIOCapturer(const FileDescriptor &_fd, pid_t _pid, const char *_channelName)
172
- : fd(_fd),
173
- pid(_pid),
174
- channelName(_channelName),
175
- thr(NULL)
176
- { }
177
-
178
- ~BackgroundIOCapturer() {
179
- TRACE_POINT();
180
- if (thr != NULL) {
181
- this_thread::disable_interruption di;
182
- this_thread::disable_syscall_interruption dsi;
183
- thr->interrupt_and_join();
184
- delete thr;
185
- thr = NULL;
186
- }
187
- }
188
-
189
- const FileDescriptor &getFd() const {
190
- return fd;
191
- }
192
-
193
- void start() {
194
- assert(thr == NULL);
195
- thr = new oxt::thread(boost::bind(&BackgroundIOCapturer::capture, this),
196
- "Background I/O capturer", 64 * 1024);
197
- }
198
-
199
- string stop() {
200
- TRACE_POINT();
201
- assert(thr != NULL);
202
- this_thread::disable_interruption di;
203
- this_thread::disable_syscall_interruption dsi;
204
- thr->interrupt_and_join();
205
- delete thr;
206
- thr = NULL;
207
- boost::lock_guard<boost::mutex> l(dataSyncher);
208
- return data;
209
- }
210
-
211
- void appendToBuffer(const StaticString &dataToAdd) {
212
- TRACE_POINT();
213
- boost::lock_guard<boost::mutex> l(dataSyncher);
214
- data.append(dataToAdd.data(), dataToAdd.size());
215
- }
216
- };
217
-
218
- typedef boost::shared_ptr<BackgroundIOCapturer> BackgroundIOCapturerPtr;
219
-
220
115
  /**
221
116
  * A temporary directory for spawned child processes to write
222
117
  * debugging information to. It is removed after spawning has
@@ -311,16 +206,7 @@ protected:
311
206
  */
312
207
  vector<string> appRootPathsInsideChroot;
313
208
 
314
- // User switching
315
- bool switchUser;
316
- string username;
317
- string groupname;
318
- string home;
319
- string shell;
320
- uid_t uid;
321
- gid_t gid;
322
- int ngroups;
323
- shared_array<gid_t> gidset;
209
+ UserSwitchingInfo userSwitching;
324
210
 
325
211
  // Other information
326
212
  string codeRevision;
@@ -365,7 +251,6 @@ protected:
365
251
  }
366
252
  };
367
253
 
368
-
369
254
  private:
370
255
  /**
371
256
  * Appends key + "\0" + value + "\0" to 'output'.
@@ -389,10 +274,11 @@ private:
389
274
  "ruby_libdir: " + config->resourceLocator->getRubyLibDir() + "\n"
390
275
  "gupid: " + details.gupid + "\n"
391
276
  "UNIX_PATH_MAX: " + toString(UNIX_PATH_MAX) + "\n";
392
- if (!details.options->groupSecret.empty()) {
393
- data.append("connect_password: " + details.options->groupSecret + "\n");
277
+ if (!details.options->apiKey.empty()) {
278
+ data.append("connect_password: " + details.options->apiKey + "\n");
394
279
  }
395
280
  if (!config->instanceDir.empty()) {
281
+ data.append("instance_dir: " + config->instanceDir + "\n");
396
282
  data.append("socket_dir: " + config->instanceDir + "/apps.s\n");
397
283
  }
398
284
 
@@ -425,10 +311,10 @@ private:
425
311
  }
426
312
  }
427
313
 
428
- SpawnObject handleSpawnResponse(NegotiationDetails &details) {
314
+ Result handleSpawnResponse(NegotiationDetails &details) {
429
315
  TRACE_POINT();
430
- SocketList sockets;
431
- SpawnObject result;
316
+ Json::Value sockets;
317
+ Result result;
432
318
 
433
319
  while (true) {
434
320
  string line;
@@ -491,12 +377,12 @@ private:
491
377
  details);
492
378
  }
493
379
 
494
- StaticString name = psg_pstrdup(result.pool, args[0]);
495
- StaticString address = psg_pstrdup(result.pool,
496
- fixupSocketAddress(*details.options, args[1]));
497
- StaticString protocol = psg_pstrdup(result.pool, args[2]);
498
-
499
- sockets.add(details.pid, name, address, protocol, atoi(args[3]));
380
+ Json::Value socket;
381
+ socket["name"] = args[0];
382
+ socket["address"] = fixupSocketAddress(*details.options, args[1]);
383
+ socket["protocol"] = args[2];
384
+ socket["concurrency"] = atoi(args[3]);
385
+ sockets.append(socket);
500
386
  } else {
501
387
  throwAppSpawnException("An error occurred while starting the "
502
388
  "web application. It reported a wrongly formatted 'socket'"
@@ -512,7 +398,7 @@ private:
512
398
 
513
399
  pids.push_back(pid);
514
400
  ProcessMetricMap metrics = collector.collect(pids);
515
- if (metrics[pid].uid != details.preparation->uid) {
401
+ if (metrics[pid].uid != details.preparation->userSwitching.uid) {
516
402
  throwAppSpawnException("An error occurred while starting the "
517
403
  "web application. The PID that the loader has returned does "
518
404
  "not have the same UID as the loader itself.",
@@ -529,25 +415,39 @@ private:
529
415
  }
530
416
  }
531
417
 
532
- if (!sockets.hasSessionSockets()) {
418
+ if (!hasSessionSockets(sockets)) {
533
419
  throwAppSpawnException("An error occured while starting the web "
534
420
  "application. It did not advertise any session sockets.",
535
421
  SpawnException::APP_STARTUP_PROTOCOL_ERROR,
536
422
  details);
537
423
  }
538
424
 
539
- result.process = boost::make_shared<Process>(
540
- details.pid,
541
- details.gupid,
542
- details.adminSocket, details.errorPipe,
543
- sockets, creationTime, details.spawnStartTime);
544
- result.process->codeRevision = psg_pstrdup(result.pool,
545
- details.preparation->codeRevision);
546
- return boost::move(result);
425
+ result["type"] = "os_process";
426
+ result["pid"] = (int) details.pid;
427
+ result["gupid"] = details.gupid;
428
+ result["sockets"] = sockets;
429
+ result["code_revision"] = details.preparation->codeRevision;
430
+ result["spawner_creation_time"] = (Json::UInt64) creationTime;
431
+ result["spawn_start_time"] = (Json::UInt64) details.spawnStartTime;
432
+ result.adminSocket = details.adminSocket;
433
+ result.errorPipe = details.errorPipe;
434
+ return result;
435
+ }
436
+
437
+ bool hasSessionSockets(const Json::Value &sockets) const {
438
+ Json::Value::const_iterator it, end = sockets.end();
439
+
440
+ for (it = sockets.begin(); it != end; it++) {
441
+ const Json::Value &socket = *it;
442
+ if (socket["protocol"] == "session" || socket["protocol"] == "http_session") {
443
+ return true;
444
+ }
445
+ }
446
+ return false;
547
447
  }
548
448
 
549
449
  protected:
550
- SpawnerConfigPtr config;
450
+ ConfigPtr config;
551
451
 
552
452
  static void nonInterruptableKillAndWaitpid(pid_t pid) {
553
453
  this_thread::disable_syscall_interruption dsi;
@@ -646,9 +546,9 @@ protected:
646
546
  e << ": " << strerror(e) << ")";
647
547
  break;
648
548
  }
649
- if (buf.st_uid != details.preparation->uid) {
549
+ if (buf.st_uid != details.preparation->userSwitching.uid) {
650
550
  error << "It advertised a Unix domain socket that has a different " <<
651
- "owner than expected (should be UID " << details.preparation->uid <<
551
+ "owner than expected (should be UID " << details.preparation->userSwitching.uid <<
652
552
  ", but actual UID was " << buf.st_uid << ")";
653
553
  break;
654
554
  }
@@ -742,7 +642,9 @@ protected:
742
642
  }
743
643
 
744
644
  void throwSpawnException(SpawnException &e, const Options &options) {
745
- processAndLogNewSpawnException(e, options, config);
645
+ if (config->errorHandler != NULL) {
646
+ config->errorHandler(config, e, options);
647
+ }
746
648
  throw e;
747
649
  }
748
650
 
@@ -813,7 +715,7 @@ protected:
813
715
  TRACE_POINT();
814
716
  SpawnPreparationInfo info;
815
717
  prepareChroot(info, options);
816
- prepareUserSwitching(info, options);
718
+ info.userSwitching = prepareUserSwitching(options);
817
719
  prepareSwitchingWorkingDirectory(info, options);
818
720
  inferApplicationInfo(info);
819
721
  return info;
@@ -843,201 +745,6 @@ protected:
843
745
  }
844
746
  }
845
747
 
846
- void prepareUserSwitching(SpawnPreparationInfo &info, const Options &options) const {
847
- TRACE_POINT();
848
- if (geteuid() != 0) {
849
- struct passwd pwd, *userInfo;
850
- long bufSize;
851
- shared_array<char> strings;
852
-
853
- // _SC_GETPW_R_SIZE_MAX is not a maximum:
854
- // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
855
- bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
856
- strings.reset(new char[bufSize]);
857
-
858
- userInfo = (struct passwd *) NULL;
859
- if (getpwuid_r(geteuid(), &pwd, strings.get(), bufSize, &userInfo) != 0
860
- || userInfo == (struct passwd *) NULL)
861
- {
862
- throw RuntimeException("Cannot get user database entry for user " +
863
- getProcessUsername() + "; it looks like your system's " +
864
- "user database is broken, please fix it.");
865
- }
866
-
867
- info.switchUser = false;
868
- info.username = userInfo->pw_name;
869
- info.groupname = getGroupName(userInfo->pw_gid);
870
- info.home = userInfo->pw_dir;
871
- info.shell = userInfo->pw_shell;
872
- info.uid = geteuid();
873
- info.gid = getegid();
874
- info.ngroups = 0;
875
- return;
876
- }
877
-
878
- UPDATE_TRACE_POINT();
879
- string defaultGroup;
880
- string startupFile = absolutizePath(options.getStartupFile(), info.appRoot);
881
- struct passwd pwd, *userInfo;
882
- struct group grp;
883
- gid_t groupId = (gid_t) -1;
884
- long pwdBufSize, grpBufSize;
885
- shared_array<char> pwdBuf, grpBuf;
886
- int ret;
887
-
888
- // _SC_GETPW_R_SIZE_MAX/_SC_GETGR_R_SIZE_MAX are not maximums:
889
- // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
890
- pwdBufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
891
- pwdBuf.reset(new char[pwdBufSize]);
892
- grpBufSize = std::max<long>(1024 * 128, sysconf(_SC_GETGR_R_SIZE_MAX));
893
- grpBuf.reset(new char[grpBufSize]);
894
-
895
- if (options.defaultGroup.empty()) {
896
- struct passwd *info;
897
- struct group *group;
898
-
899
- info = (struct passwd *) NULL;
900
- ret = getpwnam_r(options.defaultUser.c_str(), &pwd, pwdBuf.get(),
901
- pwdBufSize, &info);
902
- if (ret != 0) {
903
- info = (struct passwd *) NULL;
904
- }
905
- if (info == (struct passwd *) NULL) {
906
- throw RuntimeException("Cannot get user database entry for username '" +
907
- options.defaultUser + "'");
908
- }
909
-
910
- group = (struct group *) NULL;
911
- ret = getgrgid_r(info->pw_gid, &grp, grpBuf.get(), grpBufSize, &group);
912
- if (ret != 0) {
913
- group = (struct group *) NULL;
914
- }
915
- if (group == (struct group *) NULL) {
916
- throw RuntimeException(string("Cannot get group database entry for ") +
917
- "the default group belonging to username '" +
918
- options.defaultUser + "'");
919
- }
920
- defaultGroup = group->gr_name;
921
- } else {
922
- defaultGroup = options.defaultGroup;
923
- }
924
-
925
- UPDATE_TRACE_POINT();
926
- userInfo = (struct passwd *) NULL;
927
- if (!options.userSwitching) {
928
- // Keep userInfo at NULL so that it's set to defaultUser's UID.
929
- } else if (!options.user.empty()) {
930
- ret = getpwnam_r(options.user.c_str(), &pwd, pwdBuf.get(),
931
- pwdBufSize, &userInfo);
932
- if (ret != 0) {
933
- userInfo = (struct passwd *) NULL;
934
- }
935
- } else {
936
- struct stat buf;
937
- if (syscalls::lstat(startupFile.c_str(), &buf) == -1) {
938
- int e = errno;
939
- throw SystemException("Cannot lstat(\"" + startupFile +
940
- "\")", e);
941
- }
942
- ret = getpwuid_r(buf.st_uid, &pwd, pwdBuf.get(),
943
- pwdBufSize, &userInfo);
944
- if (ret != 0) {
945
- userInfo = (struct passwd *) NULL;
946
- }
947
- }
948
- if (userInfo == (struct passwd *) NULL || userInfo->pw_uid == 0) {
949
- userInfo = (struct passwd *) NULL;
950
- ret = getpwnam_r(options.defaultUser.c_str(), &pwd,
951
- pwdBuf.get(), pwdBufSize, &userInfo);
952
- if (ret != 0) {
953
- userInfo = (struct passwd *) NULL;
954
- }
955
- }
956
-
957
- UPDATE_TRACE_POINT();
958
- if (!options.userSwitching) {
959
- // Keep groupId at -1 so that it's set to defaultGroup's GID.
960
- } else if (!options.group.empty()) {
961
- struct group *groupInfo = (struct group *) NULL;
962
-
963
- if (options.group == "!STARTUP_FILE!") {
964
- struct stat buf;
965
-
966
- if (syscalls::lstat(startupFile.c_str(), &buf) == -1) {
967
- int e = errno;
968
- throw SystemException("Cannot lstat(\"" +
969
- startupFile + "\")", e);
970
- }
971
-
972
- ret = getgrgid_r(buf.st_gid, &grp, grpBuf.get(), grpBufSize,
973
- &groupInfo);
974
- if (ret != 0) {
975
- groupInfo = (struct group *) NULL;
976
- }
977
- if (groupInfo != NULL) {
978
- groupId = buf.st_gid;
979
- } else {
980
- groupId = (gid_t) -1;
981
- }
982
- } else {
983
- ret = getgrnam_r(options.group.c_str(), &grp, grpBuf.get(),
984
- grpBufSize, &groupInfo);
985
- if (ret != 0) {
986
- groupInfo = (struct group *) NULL;
987
- }
988
- if (groupInfo != NULL) {
989
- groupId = groupInfo->gr_gid;
990
- } else {
991
- groupId = (gid_t) -1;
992
- }
993
- }
994
- } else if (userInfo != (struct passwd *) NULL) {
995
- groupId = userInfo->pw_gid;
996
- }
997
- if (groupId == 0 || groupId == (gid_t) -1) {
998
- groupId = lookupGid(defaultGroup);
999
- }
1000
-
1001
- UPDATE_TRACE_POINT();
1002
- if (userInfo == (struct passwd *) NULL) {
1003
- throw RuntimeException("Cannot determine a user to lower privilege to");
1004
- }
1005
- if (groupId == (gid_t) -1) {
1006
- throw RuntimeException("Cannot determine a group to lower privilege to");
1007
- }
1008
-
1009
- UPDATE_TRACE_POINT();
1010
- #ifdef __APPLE__
1011
- int groups[1024];
1012
- info.ngroups = sizeof(groups) / sizeof(int);
1013
- #else
1014
- gid_t groups[1024];
1015
- info.ngroups = sizeof(groups) / sizeof(gid_t);
1016
- #endif
1017
- info.switchUser = true;
1018
- info.username = userInfo->pw_name;
1019
- info.groupname = getGroupName(groupId);
1020
- info.home = userInfo->pw_dir;
1021
- info.shell = userInfo->pw_shell;
1022
- info.uid = userInfo->pw_uid;
1023
- info.gid = groupId;
1024
- #if !defined(HAVE_GETGROUPLIST) && (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
1025
- #define HAVE_GETGROUPLIST
1026
- #endif
1027
- #ifdef HAVE_GETGROUPLIST
1028
- ret = getgrouplist(userInfo->pw_name, groupId,
1029
- groups, &info.ngroups);
1030
- if (ret == -1) {
1031
- int e = errno;
1032
- throw SystemException("getgrouplist() failed", e);
1033
- }
1034
- info.gidset = shared_array<gid_t>(new gid_t[info.ngroups]);
1035
- for (int i = 0; i < info.ngroups; i++) {
1036
- info.gidset[i] = groups[i];
1037
- }
1038
- #endif
1039
- }
1040
-
1041
748
  void prepareSwitchingWorkingDirectory(SpawnPreparationInfo &info, const Options &options) const {
1042
749
  vector<string> components;
1043
750
  split(info.appRootInsideChroot, '/', components);
@@ -1109,7 +816,7 @@ protected:
1109
816
 
1110
817
  bool shouldLoadShellEnvvars(const Options &options, const SpawnPreparationInfo &preparation) const {
1111
818
  if (options.loadShellEnvvars) {
1112
- string shellName = extractBaseName(preparation.shell);
819
+ string shellName = extractBaseName(preparation.userSwitching.shell);
1113
820
  return shellName == "bash" || shellName == "zsh" || shellName == "ksh";
1114
821
  } else {
1115
822
  return false;
@@ -1164,23 +871,27 @@ protected:
1164
871
  }
1165
872
 
1166
873
  void switchUser(const SpawnPreparationInfo &info) {
1167
- if (info.switchUser) {
874
+ if (info.userSwitching.enabled) {
1168
875
  bool setgroupsCalled = false;
1169
876
  #ifdef HAVE_GETGROUPLIST
1170
- if (info.ngroups <= NGROUPS_MAX) {
877
+ if (info.userSwitching.ngroups <= NGROUPS_MAX) {
1171
878
  setgroupsCalled = true;
1172
- if (setgroups(info.ngroups, info.gidset.get()) == -1) {
879
+ if (setgroups(info.userSwitching.ngroups,
880
+ info.userSwitching.gidset.get()) == -1)
881
+ {
1173
882
  int e = errno;
1174
883
  printf("!> Error\n");
1175
884
  printf("!> \n");
1176
885
  printf("setgroups(%d, ...) failed: %s (errno=%d)\n",
1177
- info.ngroups, strerror(e), e);
886
+ info.userSwitching.ngroups, strerror(e), e);
1178
887
  fflush(stdout);
1179
888
  _exit(1);
1180
889
  }
1181
890
  }
1182
891
  #endif
1183
- if (!setgroupsCalled && initgroups(info.username.c_str(), info.gid) == -1) {
892
+ if (!setgroupsCalled && initgroups(info.userSwitching.username.c_str(),
893
+ info.userSwitching.gid) == -1)
894
+ {
1184
895
  int e = errno;
1185
896
  printf("!> Error\n");
1186
897
  printf("!> \n");
@@ -1189,7 +900,7 @@ protected:
1189
900
  fflush(stdout);
1190
901
  _exit(1);
1191
902
  }
1192
- if (setgid(info.gid) == -1) {
903
+ if (setgid(info.userSwitching.gid) == -1) {
1193
904
  int e = errno;
1194
905
  printf("!> Error\n");
1195
906
  printf("!> \n");
@@ -1198,7 +909,7 @@ protected:
1198
909
  fflush(stdout);
1199
910
  _exit(1);
1200
911
  }
1201
- if (setuid(info.uid) == -1) {
912
+ if (setuid(info.userSwitching.uid) == -1) {
1202
913
  int e = errno;
1203
914
  printf("!> Error\n");
1204
915
  printf("!> \n");
@@ -1212,10 +923,10 @@ protected:
1212
923
  // in the SpawnPreparer because SpawnPreparer might
1213
924
  // be executed by bash, but these environment variables
1214
925
  // must be set before bash.
1215
- setenv("USER", info.username.c_str(), 1);
1216
- setenv("LOGNAME", info.username.c_str(), 1);
1217
- setenv("SHELL", info.shell.c_str(), 1);
1218
- setenv("HOME", info.home.c_str(), 1);
926
+ setenv("USER", info.userSwitching.username.c_str(), 1);
927
+ setenv("LOGNAME", info.userSwitching.username.c_str(), 1);
928
+ setenv("SHELL", info.userSwitching.shell.c_str(), 1);
929
+ setenv("HOME", info.userSwitching.home.c_str(), 1);
1219
930
  }
1220
931
  }
1221
932
 
@@ -1264,8 +975,8 @@ protected:
1264
975
  "However, the parent directory '%s' has wrong permissions, thereby "
1265
976
  "preventing this process from accessing its application root directory. "
1266
977
  "Please fix the permissions of the directory '%s' first.\n",
1267
- info.username.c_str(),
1268
- info.groupname.c_str(),
978
+ info.userSwitching.username.c_str(),
979
+ info.userSwitching.groupname.c_str(),
1269
980
  info.appRootPaths.back().c_str(),
1270
981
  parent,
1271
982
  parent);
@@ -1292,8 +1003,8 @@ protected:
1292
1003
  "and must be able to access its application root directory '%s'. "
1293
1004
  "However this directory is not accessible because it has wrong permissions. "
1294
1005
  "Please fix these permissions first.\n",
1295
- info.username.c_str(),
1296
- info.groupname.c_str(),
1006
+ info.userSwitching.username.c_str(),
1007
+ info.userSwitching.groupname.c_str(),
1297
1008
  info.appRootPaths.back().c_str());
1298
1009
  fflush(stdout);
1299
1010
  _exit(1);
@@ -1311,7 +1022,7 @@ protected:
1311
1022
  /**
1312
1023
  * Execute the process spawning negotiation protocol.
1313
1024
  */
1314
- SpawnObject negotiateSpawn(NegotiationDetails &details) {
1025
+ Result negotiateSpawn(NegotiationDetails &details) {
1315
1026
  TRACE_POINT();
1316
1027
  details.spawnStartTime = SystemTime::getUsec();
1317
1028
  details.gupid = integerToHex(SystemTime::get() / 60) + "-" +
@@ -1369,7 +1080,7 @@ protected:
1369
1080
  handleInvalidSpawnResponseType(result, details);
1370
1081
  }
1371
1082
  }
1372
- return SpawnObject(); // Never reached.
1083
+ return Result(); // Never reached.
1373
1084
  }
1374
1085
 
1375
1086
  void handleSpawnErrorResponse(NegotiationDetails &details) {
@@ -1454,34 +1165,35 @@ public:
1454
1165
  */
1455
1166
  const unsigned long long creationTime;
1456
1167
 
1457
- Spawner(const SpawnerConfigPtr &_config)
1168
+ Spawner(const ConfigPtr &_config)
1458
1169
  : config(_config),
1459
1170
  creationTime(SystemTime::getUsec())
1460
1171
  { }
1461
1172
 
1462
1173
  virtual ~Spawner() { }
1463
- virtual SpawnObject spawn(const Options &options) = 0;
1464
1174
 
1465
- /** Does not depend on the event loop. */
1175
+ virtual Result spawn(const Options &options) = 0;
1176
+
1466
1177
  virtual bool cleanable() const {
1467
1178
  return false;
1468
1179
  }
1469
1180
 
1470
- virtual void cleanup() { }
1181
+ virtual void cleanup() {
1182
+ // Do nothing.
1183
+ }
1471
1184
 
1472
- /** Does not depend on the event loop. */
1473
1185
  virtual unsigned long long lastUsed() const {
1474
1186
  return 0;
1475
1187
  }
1476
1188
 
1477
- SpawnerConfigPtr getConfig() const {
1189
+ ConfigPtr getConfig() const {
1478
1190
  return config;
1479
1191
  }
1480
1192
  };
1481
1193
  typedef boost::shared_ptr<Spawner> SpawnerPtr;
1482
1194
 
1483
1195
 
1484
- } // namespace ApplicationPool2
1196
+ } // namespace SpawningKit
1485
1197
  } // namespace Passenger
1486
1198
 
1487
- #endif /* _PASSENGER_APPLICATION_POOL2_SPAWNER_H_ */
1199
+ #endif /* _PASSENGER_SPAWNING_KIT_SPAWNER_H_ */