passenger 4.0.14 → 4.0.16
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.
- data.tar.gz.asc +7 -7
- data/NEWS +69 -0
- data/bin/passenger-install-apache2-module +7 -1
- data/bin/passenger-install-nginx-module +18 -1
- data/build/apache2.rb +25 -1
- data/build/basics.rb +7 -4
- data/build/debian.rb +72 -25
- data/build/nginx.rb +24 -0
- data/build/packaging.rb +45 -3
- data/debian.template/{control → control.template} +17 -8
- data/debian.template/ruby-passenger.install.template +1 -0
- data/debian.template/rules.template +9 -3
- data/dev/run_travis.sh +14 -0
- data/doc/Users guide Apache.idmap.txt +64 -48
- data/doc/Users guide Apache.txt +127 -93
- data/doc/Users guide Nginx.idmap.txt +46 -28
- data/doc/Users guide Nginx.txt +100 -12
- data/doc/images/{conservative_spawning.png → direct_spawning.png} +0 -0
- data/doc/images/{conservative_spawning.svg → direct_spawning.svg} +0 -0
- data/doc/users_guide_snippets/installation.txt +107 -66
- data/doc/users_guide_snippets/passenger_spawn_method.txt +1 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -12
- data/doc/users_guide_snippets/tips.txt +70 -3
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +2 -0
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +114 -0
- data/ext/apache2/Configuration.cpp +53 -101
- data/ext/apache2/Configuration.hpp +19 -41
- data/ext/apache2/ConfigurationCommands.cpp +95 -0
- data/ext/apache2/ConfigurationCommands.cpp.erb +91 -0
- data/ext/apache2/ConfigurationFields.hpp +59 -0
- data/ext/apache2/ConfigurationFields.hpp.erb +89 -0
- data/ext/apache2/ConfigurationSetters.cpp +223 -0
- data/ext/apache2/ConfigurationSetters.cpp.erb +126 -0
- data/ext/apache2/CreateDirConfig.cpp +50 -0
- data/ext/apache2/CreateDirConfig.cpp.erb +71 -0
- data/ext/apache2/Hooks.cpp +6 -0
- data/ext/apache2/MergeDirConfig.cpp +103 -0
- data/ext/apache2/MergeDirConfig.cpp.erb +81 -0
- data/ext/common/ApplicationPool2/AppTypes.cpp +2 -0
- data/ext/common/ApplicationPool2/AppTypes.h +2 -0
- data/ext/common/ApplicationPool2/Common.h +1 -1
- data/ext/common/ApplicationPool2/Group.h +56 -7
- data/ext/common/ApplicationPool2/Implementation.cpp +133 -31
- data/ext/common/ApplicationPool2/Options.h +23 -2
- data/ext/common/ApplicationPool2/Pool.h +8 -1
- data/ext/common/ApplicationPool2/Process.h +9 -0
- data/ext/common/ApplicationPool2/Session.h +1 -0
- data/ext/common/ApplicationPool2/Spawner.h +21 -19
- data/ext/common/ApplicationPool2/SuperGroup.h +1 -1
- data/ext/common/Constants.h +21 -17
- data/ext/common/Constants.h.erb +1 -1
- data/ext/common/Exceptions.h +19 -0
- data/ext/common/ServerInstanceDir.h +8 -4
- data/ext/common/Utils.cpp +33 -1
- data/ext/common/Utils.h +14 -0
- data/ext/common/Utils/StrIntUtils.cpp +16 -0
- data/ext/common/Utils/StrIntUtils.h +5 -0
- data/ext/common/agents/HelperAgent/Main.cpp +5 -5
- data/ext/common/agents/HelperAgent/RequestHandler.h +94 -45
- data/ext/common/agents/LoggingAgent/Main.cpp +10 -26
- data/ext/common/agents/Watchdog/Main.cpp +4 -15
- data/ext/nginx/CacheLocationConfig.c +501 -0
- data/ext/nginx/CacheLocationConfig.c.erb +140 -0
- data/ext/nginx/Configuration.c +29 -453
- data/ext/nginx/Configuration.h +3 -21
- data/ext/nginx/ConfigurationCommands.c +501 -0
- data/ext/nginx/ConfigurationCommands.c.erb +136 -0
- data/ext/nginx/ConfigurationFields.h +89 -0
- data/ext/nginx/ConfigurationFields.h.erb +85 -0
- data/ext/nginx/ContentHandler.c +3 -166
- data/ext/nginx/CreateLocationConfig.c +146 -0
- data/ext/nginx/CreateLocationConfig.c.erb +70 -0
- data/ext/nginx/MergeLocationConfig.c +166 -0
- data/ext/nginx/MergeLocationConfig.c.erb +72 -0
- data/ext/nginx/config +4 -0
- data/ext/oxt/detail/tracable_exception_disabled.hpp +21 -1
- data/ext/oxt/detail/tracable_exception_enabled.hpp +4 -1
- data/ext/oxt/implementation.cpp +7 -1
- data/ext/oxt/macros.hpp +9 -7
- data/helper-scripts/backtrace-sanitizer.rb +23 -0
- data/helper-scripts/classic-rails-loader.rb +23 -0
- data/helper-scripts/classic-rails-preloader.rb +23 -0
- data/helper-scripts/download_binaries/extconf.rb +10 -5
- data/helper-scripts/meteor-loader.rb +127 -0
- data/helper-scripts/node-loader.js +1 -1
- data/helper-scripts/rack-preloader.rb +23 -0
- data/helper-scripts/system-memory-stats.py +22 -0
- data/helper-scripts/touch-dir.sh +48 -0
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/apache2/config_options.rb +104 -0
- data/lib/phusion_passenger/constants.rb +8 -0
- data/lib/phusion_passenger/native_support.rb +9 -1
- data/lib/phusion_passenger/nginx/config_options.rb +328 -0
- data/lib/phusion_passenger/packaging.rb +2 -2
- data/lib/phusion_passenger/platform_info/apache.rb +8 -0
- data/lib/phusion_passenger/platform_info/compiler.rb +2 -2
- data/lib/phusion_passenger/rails3_extensions/init.rb +19 -4
- data/lib/phusion_passenger/ruby_core_enhancements.rb +4 -1
- data/lib/phusion_passenger/standalone/app_finder.rb +3 -2
- data/lib/phusion_passenger/standalone/command.rb +1 -0
- data/lib/phusion_passenger/standalone/runtime_installer.rb +1 -6
- data/lib/phusion_passenger/standalone/runtime_locator.rb +9 -2
- data/lib/phusion_passenger/standalone/start_command.rb +45 -9
- data/lib/phusion_passenger/utils.rb +4 -1
- data/resources/templates/{nginx → installer_common}/run_installer_as_root.txt.erb +3 -1
- data/resources/templates/nginx/nginx_module_sources_not_available.txt.erb +6 -0
- data/resources/templates/standalone/config.erb +8 -8
- data/test/cxx/ApplicationPool2/PoolTest.cpp +120 -3
- data/test/cxx/RequestHandlerTest.cpp +66 -3
- data/test/integration_tests/native_packaging_spec.rb +41 -0
- data/test/integration_tests/nginx_tests.rb +1 -0
- data/test/integration_tests/standalone_tests.rb +4 -0
- data/test/ruby/shared/rails/analytics_logging_extensions_sharedspec.rb +22 -0
- data/test/stub/rails3.0/config/initializers/passenger.rb +2 -1
- data/test/stub/rails3.1/config/initializers/passenger.rb +2 -1
- data/test/stub/rails3.2/config/initializers/passenger.rb +2 -1
- data/test/stub/rails4.0/config/initializers/passenger.rb +5 -1
- data/test/stub/wsgi/passenger_wsgi.py +5 -0
- metadata +32 -7
- metadata.gz.asc +7 -7
- data/resources/templates/apache2/run_installer_as_root.txt.erb +0 -8
@@ -297,6 +297,20 @@ public:
|
|
297
297
|
|
298
298
|
/** The number of seconds that preloader processes may stay alive idling. */
|
299
299
|
long maxPreloaderIdleTime;
|
300
|
+
|
301
|
+
/**
|
302
|
+
* The maximum number of processes inside a group that may be performing
|
303
|
+
* out-of-band work at the same time.
|
304
|
+
*/
|
305
|
+
unsigned int maxOutOfBandWorkInstances;
|
306
|
+
|
307
|
+
/**
|
308
|
+
* The maximum number of requests that may live in the Group.getWaitlist queue.
|
309
|
+
* A value of 0 means unlimited.
|
310
|
+
*/
|
311
|
+
unsigned int maxRequestQueueSize;
|
312
|
+
|
313
|
+
/*-----------------*/
|
300
314
|
|
301
315
|
|
302
316
|
/*********** Per-request options that should be set manually and that only matter to Pool ***********/
|
@@ -370,8 +384,8 @@ public:
|
|
370
384
|
baseURI = "/";
|
371
385
|
spawnMethod = "smart";
|
372
386
|
defaultUser = "nobody";
|
373
|
-
ruby =
|
374
|
-
python =
|
387
|
+
ruby = DEFAULT_RUBY;
|
388
|
+
python = DEFAULT_PYTHON;
|
375
389
|
rights = DEFAULT_BACKEND_ACCOUNT_RIGHTS;
|
376
390
|
debugger = false;
|
377
391
|
loadShellEnvvars = true;
|
@@ -380,6 +394,8 @@ public:
|
|
380
394
|
|
381
395
|
minProcesses = 1;
|
382
396
|
maxPreloaderIdleTime = -1;
|
397
|
+
maxOutOfBandWorkInstances = 1;
|
398
|
+
maxRequestQueueSize = 100;
|
383
399
|
|
384
400
|
statThrottleRate = 0;
|
385
401
|
maxRequests = 0;
|
@@ -528,6 +544,7 @@ public:
|
|
528
544
|
if (fields & PER_GROUP_POOL_OPTIONS) {
|
529
545
|
appendKeyValue3(vec, "min_processes", minProcesses);
|
530
546
|
appendKeyValue2(vec, "max_preloader_idle_time", maxPreloaderIdleTime);
|
547
|
+
appendKeyValue3(vec, "max_out_of_band_work_instances", maxOutOfBandWorkInstances);
|
531
548
|
}
|
532
549
|
|
533
550
|
/*********************************/
|
@@ -567,6 +584,10 @@ public:
|
|
567
584
|
return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/rack-loader.rb";
|
568
585
|
} else if (appType == "wsgi") {
|
569
586
|
return python + "\t" + resourceLocator.getHelperScriptsDir() + "/wsgi-loader.py";
|
587
|
+
} else if (appType == "node") {
|
588
|
+
return "node\t" + resourceLocator.getHelperScriptsDir() + "/node-loader.js";
|
589
|
+
} else if (appType == "meteor") {
|
590
|
+
return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/meteor-loader.rb";
|
570
591
|
} else {
|
571
592
|
return startCommand;
|
572
593
|
}
|
@@ -100,6 +100,7 @@ public:
|
|
100
100
|
bool spawning;
|
101
101
|
bool superGroup;
|
102
102
|
bool oobw;
|
103
|
+
bool testOverflowRequestQueue;
|
103
104
|
|
104
105
|
// The following fields may only be accessed by Pool.
|
105
106
|
boost::mutex syncher;
|
@@ -112,6 +113,7 @@ public:
|
|
112
113
|
spawning = true;
|
113
114
|
superGroup = false;
|
114
115
|
oobw = false;
|
116
|
+
testOverflowRequestQueue = false;
|
115
117
|
spawnLoopIteration = 0;
|
116
118
|
}
|
117
119
|
};
|
@@ -571,7 +573,8 @@ public:
|
|
571
573
|
process->lastUsed + maxIdleTime;
|
572
574
|
if (process->sessions == 0
|
573
575
|
&& state.now >= processGcTime
|
574
|
-
&& (unsigned long) group->
|
576
|
+
&& (unsigned long) group->getProcessCount() > group->options.minProcesses)
|
577
|
+
{
|
575
578
|
ProcessList::iterator prev = p_it;
|
576
579
|
prev--;
|
577
580
|
P_DEBUG("Garbage collect idle process: " << process->inspect() <<
|
@@ -1165,6 +1168,10 @@ public:
|
|
1165
1168
|
return result;
|
1166
1169
|
}
|
1167
1170
|
|
1171
|
+
/**
|
1172
|
+
* Returns the total number of processes in the pool, including all disabling and
|
1173
|
+
* disabled processes, but excluding processes that are shutting down.
|
1174
|
+
*/
|
1168
1175
|
unsigned int getProcessCount(bool lock = true) const {
|
1169
1176
|
DynamicScopedLock l(syncher, lock);
|
1170
1177
|
unsigned int result = 0;
|
@@ -465,6 +465,15 @@ public:
|
|
465
465
|
return false;
|
466
466
|
}
|
467
467
|
}
|
468
|
+
|
469
|
+
/** Kill the OS process with the given signal. */
|
470
|
+
int kill(int signo) {
|
471
|
+
if (osProcessExists()) {
|
472
|
+
return syscalls::kill(pid, signo);
|
473
|
+
} else {
|
474
|
+
return 0;
|
475
|
+
}
|
476
|
+
}
|
468
477
|
|
469
478
|
int utilization() const {
|
470
479
|
/* Different processes within a Group may have different
|
@@ -781,17 +781,10 @@ protected:
|
|
781
781
|
getProcessUsername() + "; it looks like your system's " +
|
782
782
|
"user database is broken, please fix it.");
|
783
783
|
}
|
784
|
-
struct group *groupInfo = getgrgid(userInfo->pw_gid);
|
785
|
-
if (groupInfo == NULL) {
|
786
|
-
throw RuntimeException(string("Cannot get group database entry for ") +
|
787
|
-
"the default group belonging to username '" +
|
788
|
-
getProcessUsername() + "'; it looks like your system's " +
|
789
|
-
"user database is broken, please fix it.");
|
790
|
-
}
|
791
784
|
|
792
785
|
info.switchUser = false;
|
793
786
|
info.username = userInfo->pw_name;
|
794
|
-
info.groupname =
|
787
|
+
info.groupname = getGroupName(userInfo->pw_gid);
|
795
788
|
info.home = userInfo->pw_dir;
|
796
789
|
info.shell = userInfo->pw_shell;
|
797
790
|
info.uid = geteuid();
|
@@ -804,7 +797,7 @@ protected:
|
|
804
797
|
string defaultGroup;
|
805
798
|
string startupFile = absolutizePath(options.getStartupFile(), info.appRoot);
|
806
799
|
struct passwd *userInfo = NULL;
|
807
|
-
|
800
|
+
gid_t groupId = (gid_t) -1;
|
808
801
|
|
809
802
|
if (options.defaultGroup.empty()) {
|
810
803
|
struct passwd *info = getpwnam(options.defaultUser.c_str());
|
@@ -848,22 +841,31 @@ protected:
|
|
848
841
|
throw SystemException("Cannot lstat(\"" +
|
849
842
|
startupFile + "\")", e);
|
850
843
|
}
|
851
|
-
|
844
|
+
if (getgrgid(buf.st_gid) != NULL) {
|
845
|
+
groupId = buf.st_gid;
|
846
|
+
} else {
|
847
|
+
groupId = (gid_t) -1;
|
848
|
+
}
|
852
849
|
} else {
|
853
|
-
groupInfo = getgrnam(options.group.c_str());
|
850
|
+
struct group *groupInfo = getgrnam(options.group.c_str());
|
851
|
+
if (groupInfo != NULL) {
|
852
|
+
groupId = groupInfo->gr_gid;
|
853
|
+
} else {
|
854
|
+
groupId = (gid_t) -1;
|
855
|
+
}
|
854
856
|
}
|
855
857
|
} else if (userInfo != NULL) {
|
856
|
-
|
858
|
+
groupId = userInfo->pw_gid;
|
857
859
|
}
|
858
|
-
if (
|
859
|
-
|
860
|
+
if (groupId == 0 || groupId == (gid_t) -1) {
|
861
|
+
groupId = lookupGid(defaultGroup);
|
860
862
|
}
|
861
|
-
|
863
|
+
|
862
864
|
UPDATE_TRACE_POINT();
|
863
865
|
if (userInfo == NULL) {
|
864
866
|
throw RuntimeException("Cannot determine a user to lower privilege to");
|
865
867
|
}
|
866
|
-
if (
|
868
|
+
if (groupId == (gid_t) -1) {
|
867
869
|
throw RuntimeException("Cannot determine a group to lower privilege to");
|
868
870
|
}
|
869
871
|
|
@@ -877,16 +879,16 @@ protected:
|
|
877
879
|
#endif
|
878
880
|
info.switchUser = true;
|
879
881
|
info.username = userInfo->pw_name;
|
880
|
-
info.groupname =
|
882
|
+
info.groupname = getGroupName(groupId);
|
881
883
|
info.home = userInfo->pw_dir;
|
882
884
|
info.shell = userInfo->pw_shell;
|
883
885
|
info.uid = userInfo->pw_uid;
|
884
|
-
info.gid =
|
886
|
+
info.gid = groupId;
|
885
887
|
#if !defined(HAVE_GETGROUPLIST) && (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
|
886
888
|
#define HAVE_GETGROUPLIST
|
887
889
|
#endif
|
888
890
|
#ifdef HAVE_GETGROUPLIST
|
889
|
-
int ret = getgrouplist(userInfo->pw_name,
|
891
|
+
int ret = getgrouplist(userInfo->pw_name, groupId,
|
890
892
|
groups, &info.ngroups);
|
891
893
|
if (ret == -1) {
|
892
894
|
int e = errno;
|
@@ -656,7 +656,7 @@ public:
|
|
656
656
|
vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
|
657
657
|
for (g_it = groups.begin(); g_it != g_end; g_it++) {
|
658
658
|
const GroupPtr &group = *g_it;
|
659
|
-
result += group->
|
659
|
+
result += group->getProcessCount();
|
660
660
|
}
|
661
661
|
return result;
|
662
662
|
}
|
data/ext/common/Constants.h
CHANGED
@@ -36,51 +36,55 @@
|
|
36
36
|
#define DEFAULT_BACKEND_ACCOUNT_RIGHTS Account::DETACH
|
37
37
|
|
38
38
|
|
39
|
-
#define
|
40
|
-
|
41
|
-
#define DEFAULT_RUBY "ruby"
|
39
|
+
#define DEFAULT_ANALYTICS_LOG_GROUP ""
|
42
40
|
|
43
|
-
#define
|
41
|
+
#define DEFAULT_ANALYTICS_LOG_PERMISSIONS "u=rwx,g=rx,o=rx"
|
44
42
|
|
45
|
-
#define
|
43
|
+
#define DEFAULT_ANALYTICS_LOG_USER "nobody"
|
46
44
|
|
47
|
-
#define
|
45
|
+
#define DEFAULT_LOG_LEVEL 0
|
48
46
|
|
49
47
|
#define DEFAULT_MAX_INSTANCES_PER_APP 0
|
50
48
|
|
51
|
-
#define
|
49
|
+
#define DEFAULT_MAX_POOL_SIZE 6
|
52
50
|
|
53
|
-
#define
|
51
|
+
#define DEFAULT_POOL_IDLE_TIME 300
|
54
52
|
|
55
|
-
#define
|
53
|
+
#define DEFAULT_PYTHON "python"
|
56
54
|
|
57
|
-
#define
|
55
|
+
#define DEFAULT_RUBY "ruby"
|
56
|
+
|
57
|
+
#define DEFAULT_START_TIMEOUT 90000
|
58
58
|
|
59
59
|
#define DEFAULT_UNION_STATION_GATEWAY_ADDRESS "gateway.unionstationapp.com"
|
60
60
|
|
61
61
|
#define DEFAULT_UNION_STATION_GATEWAY_PORT 443
|
62
62
|
|
63
|
-
#define
|
63
|
+
#define DEFAULT_WEB_APP_USER "nobody"
|
64
|
+
|
65
|
+
#define FEEDBACK_FD 3
|
64
66
|
|
65
67
|
#define MESSAGE_SERVER_MAX_PASSWORD_SIZE 100
|
66
68
|
|
69
|
+
#define MESSAGE_SERVER_MAX_USERNAME_SIZE 100
|
70
|
+
|
71
|
+
#define PASSENGER_VERSION "4.0.16"
|
72
|
+
|
67
73
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
68
74
|
|
69
75
|
#define PROCESS_SHUTDOWN_TIMEOUT 60
|
70
76
|
|
71
77
|
#define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
|
72
78
|
|
73
|
-
#define
|
79
|
+
#define SERVER_INSTANCE_DIR_GENERATION_STRUCTURE_MAJOR_VERSION 2
|
80
|
+
|
81
|
+
#define SERVER_INSTANCE_DIR_GENERATION_STRUCTURE_MINOR_VERSION 0
|
74
82
|
|
75
83
|
#define SERVER_INSTANCE_DIR_STRUCTURE_MAJOR_VERSION 1
|
76
84
|
|
77
85
|
#define SERVER_INSTANCE_DIR_STRUCTURE_MINOR_VERSION 0
|
78
86
|
|
79
|
-
#define
|
80
|
-
|
81
|
-
#define SERVER_INSTANCE_DIR_GENERATION_STRUCTURE_MINOR_VERSION 0
|
82
|
-
|
83
|
-
#define FEEDBACK_FD 3
|
87
|
+
#define STANDALONE_NGINX_CONFIGURE_OPTIONS "--with-cc-opt='-Wno-error' --without-http_fastcgi_module --without-http_scgi_module --without-http_uwsgi_module --with-http_gzip_static_module --with-http_stub_status_module"
|
84
88
|
|
85
89
|
|
86
90
|
#endif /* _PASSENGER_CONSTANTS_H */
|
data/ext/common/Constants.h.erb
CHANGED
@@ -35,7 +35,7 @@
|
|
35
35
|
|
36
36
|
#define DEFAULT_BACKEND_ACCOUNT_RIGHTS Account::DETACH
|
37
37
|
|
38
|
-
<% for constant_name in PhusionPassenger::SharedConstants.constants %>
|
38
|
+
<% for constant_name in PhusionPassenger::SharedConstants.constants.sort %>
|
39
39
|
#define <%= constant_name %> <%=PhusionPassenger::SharedConstants.const_get(constant_name).inspect %>
|
40
40
|
<% end %>
|
41
41
|
|
data/ext/common/Exceptions.h
CHANGED
@@ -316,6 +316,10 @@ public:
|
|
316
316
|
: msg(message)
|
317
317
|
{ }
|
318
318
|
|
319
|
+
GetAbortedException(const oxt::tracable_exception::no_backtrace &tag)
|
320
|
+
: oxt::tracable_exception(tag)
|
321
|
+
{ }
|
322
|
+
|
319
323
|
virtual ~GetAbortedException() throw() {}
|
320
324
|
|
321
325
|
virtual const char *what() const throw() {
|
@@ -323,6 +327,21 @@ public:
|
|
323
327
|
}
|
324
328
|
};
|
325
329
|
|
330
|
+
/**
|
331
|
+
* Indicates that a Pool::get() or Pool::asyncGet() request was denied because
|
332
|
+
* the getWaitlist queue was full.
|
333
|
+
*/
|
334
|
+
class RequestQueueFullException: public GetAbortedException {
|
335
|
+
public:
|
336
|
+
RequestQueueFullException()
|
337
|
+
: GetAbortedException(oxt::tracable_exception::no_backtrace())
|
338
|
+
{ }
|
339
|
+
|
340
|
+
virtual const char *what() const throw() {
|
341
|
+
return "Request queue is full";
|
342
|
+
}
|
343
|
+
};
|
344
|
+
|
326
345
|
/**
|
327
346
|
* Indicates that a specified argument is incorrect or violates a requirement.
|
328
347
|
*
|
@@ -82,7 +82,6 @@ public:
|
|
82
82
|
TRACE_POINT();
|
83
83
|
bool runningAsRoot = geteuid() == 0;
|
84
84
|
struct passwd *defaultUserEntry;
|
85
|
-
struct group *defaultGroupEntry;
|
86
85
|
uid_t defaultUid;
|
87
86
|
gid_t defaultGid;
|
88
87
|
|
@@ -92,12 +91,11 @@ public:
|
|
92
91
|
"' does not exist.");
|
93
92
|
}
|
94
93
|
defaultUid = defaultUserEntry->pw_uid;
|
95
|
-
|
96
|
-
if (
|
94
|
+
defaultGid = lookupGid(defaultGroup);
|
95
|
+
if (defaultGid == (gid_t) -1) {
|
97
96
|
throw NonExistentGroupException("Default group '" + defaultGroup +
|
98
97
|
"' does not exist.");
|
99
98
|
}
|
100
|
-
defaultGid = defaultGroupEntry->gr_gid;
|
101
99
|
|
102
100
|
/* We set a very tight permission here: no read or write access for
|
103
101
|
* anybody except the owner. The individual files and subdirectories
|
@@ -251,6 +249,12 @@ private:
|
|
251
249
|
throw FileSystemException("Cannot create server instance directory '" +
|
252
250
|
path + "'", e, path);
|
253
251
|
}
|
252
|
+
// Explicitly chmod the directory in case the umask is interfering.
|
253
|
+
if (chmod(path.c_str(), parseModeString("u=rwx,g=rx,o=rx")) == -1) {
|
254
|
+
int e = errno;
|
255
|
+
throw FileSystemException("Cannot set permissions on server instance directory '" +
|
256
|
+
path + "'", e, path);
|
257
|
+
}
|
254
258
|
// verifyDirectoryPermissions() checks for the owner/group so we must make
|
255
259
|
// sure the server instance directory has that owner/group, even when the
|
256
260
|
// parent directory has setgid on.
|
data/ext/common/Utils.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010
|
3
|
+
* Copyright (c) 2010-2013 Phusion
|
4
4
|
*
|
5
5
|
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
6
|
*
|
@@ -400,6 +400,38 @@ getProcessUsername() {
|
|
400
400
|
}
|
401
401
|
}
|
402
402
|
|
403
|
+
string
|
404
|
+
getGroupName(gid_t gid) {
|
405
|
+
struct group *groupEntry;
|
406
|
+
|
407
|
+
groupEntry = getgrgid(gid);
|
408
|
+
if (groupEntry == NULL) {
|
409
|
+
return toString(gid);
|
410
|
+
} else {
|
411
|
+
return groupEntry->gr_name;
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
gid_t
|
416
|
+
lookupGid(const StaticString &groupName) {
|
417
|
+
struct group *groupEntry;
|
418
|
+
char name[groupName.size() + 1];
|
419
|
+
|
420
|
+
memcpy(name, groupName.data(), groupName.size());
|
421
|
+
name[groupName.size()] = '\0';
|
422
|
+
|
423
|
+
groupEntry = getgrnam(name);
|
424
|
+
if (groupEntry == NULL) {
|
425
|
+
if (looksLikePositiveNumber(groupName)) {
|
426
|
+
return atoi(name);
|
427
|
+
} else {
|
428
|
+
return (gid_t) -1;
|
429
|
+
}
|
430
|
+
} else {
|
431
|
+
return groupEntry->gr_gid;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
403
435
|
mode_t
|
404
436
|
parseModeString(const StaticString &mode) {
|
405
437
|
mode_t modeBits = 0;
|
data/ext/common/Utils.h
CHANGED
@@ -210,6 +210,20 @@ string escapeForXml(const string &input);
|
|
210
210
|
*/
|
211
211
|
string getProcessUsername();
|
212
212
|
|
213
|
+
/**
|
214
|
+
* Returns either the group name for the given GID, or (if the group name
|
215
|
+
* couldn't be looked up) a string representation of the given GID.
|
216
|
+
*/
|
217
|
+
string getGroupName(gid_t gid);
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Given a `groupName` which is either the name of a group, or a string
|
221
|
+
* containing the GID of a group, looks up the GID as a gid_t.
|
222
|
+
*
|
223
|
+
* Returns `(gid_t) -1` if the lookup fails.
|
224
|
+
*/
|
225
|
+
gid_t lookupGid(const StaticString &groupName);
|
226
|
+
|
213
227
|
/**
|
214
228
|
* Converts a mode string into a mode_t value.
|
215
229
|
*
|
@@ -374,6 +374,22 @@ integerToHexatri(long long value) {
|
|
374
374
|
return string(buf);
|
375
375
|
}
|
376
376
|
|
377
|
+
bool
|
378
|
+
looksLikePositiveNumber(const StaticString &str) {
|
379
|
+
if (str.empty()) {
|
380
|
+
return false;
|
381
|
+
} else {
|
382
|
+
bool result = true;
|
383
|
+
const char *data = str.data();
|
384
|
+
const char *end = str.data() + str.size();
|
385
|
+
while (result && data != end) {
|
386
|
+
result = result && (*data >= '0' && *data <= '9');
|
387
|
+
data++;
|
388
|
+
}
|
389
|
+
return result;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
377
393
|
int
|
378
394
|
atoi(const string &s) {
|
379
395
|
return ::atoi(s.c_str());
|