2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #if !defined(SKIP_USER_CHANGE)
19 #include "hphp/util/capability.h"
20 #include "hphp/util/logger.h"
21 #include <folly/String.h>
22 #include <linux/types.h>
23 #include <sys/capability.h>
24 #include <sys/prctl.h>
25 #include <sys/types.h>
30 ///////////////////////////////////////////////////////////////////////////////
32 static bool setInitialCapabilities() {
33 cap_t cap_d
= cap_init();
34 if (cap_d
!= nullptr) {
35 cap_value_t cap_list
[] = {CAP_NET_BIND_SERVICE
, CAP_SYS_RESOURCE
,
36 CAP_SETUID
, CAP_SETGID
, CAP_SYS_NICE
};
37 constexpr unsigned cap_size
= sizeof(cap_list
)/sizeof(*cap_list
);
41 if (cap_set_flag(cap_d
, CAP_PERMITTED
, cap_size
, cap_list
, CAP_SET
) < 0 ||
42 cap_set_flag(cap_d
, CAP_EFFECTIVE
, cap_size
, cap_list
, CAP_SET
) < 0) {
43 Logger::Error("cap_set_flag failed: %s", folly::errnoStr(errno
).c_str());
47 if (cap_set_proc(cap_d
) == -1) {
48 Logger::Error("cap_set_proc failed: %s", folly::errnoStr(errno
).c_str());
52 if (cap_free(cap_d
) == -1) {
53 Logger::Error("cap_free failed: %s", folly::errnoStr(errno
).c_str());
57 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0) < 0) {
58 Logger::Error("prctl(PR_SET_KEEPCAPS) failed: %s",
59 folly::errnoStr(errno
).c_str());
62 prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0);
68 static bool setMinimalCapabilities() {
69 cap_t cap_d
= cap_init();
71 if (cap_d
!= nullptr) {
72 cap_value_t cap_list
[] = {CAP_NET_BIND_SERVICE
, CAP_SYS_RESOURCE
,
74 constexpr unsigned cap_size
= sizeof(cap_list
)/sizeof(*cap_list
);
78 if (cap_set_flag(cap_d
, CAP_PERMITTED
, cap_size
, cap_list
, CAP_SET
) < 0 ||
79 cap_set_flag(cap_d
, CAP_EFFECTIVE
, cap_size
, cap_list
, CAP_SET
) < 0) {
80 Logger::Error("cap_set_flag failed: %s", folly::errnoStr(errno
).c_str());
84 if (cap_set_proc(cap_d
) == -1) {
85 Logger::Error("cap_set_proc failed: %s", folly::errnoStr(errno
).c_str());
89 if (cap_free(cap_d
) == -1) {
90 Logger::Error("cap_free failed: %s", folly::errnoStr(errno
).c_str());
94 prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0);
100 bool Capability::ChangeUnixUser(uid_t uid
, bool allowRoot
) {
101 if (uid
== 0 && !allowRoot
) {
102 Logger::Error("unable to change user to root");
106 if (uid
== getuid()) {
110 if (setInitialCapabilities()) {
113 if ((pw
= getpwuid(uid
)) == nullptr) {
114 Logger::Error("unable to getpwuid(%d): %s", uid
,
115 folly::errnoStr(errno
).c_str());
119 if (initgroups(pw
->pw_name
, pw
->pw_gid
) < 0) {
120 Logger::Error("unable to drop supplementary group privs: %s",
121 folly::errnoStr(errno
).c_str());
125 if (pw
->pw_gid
== 0 || setgid(pw
->pw_gid
) < 0) {
126 Logger::Error("unable to drop gid privs: %s",
127 folly::errnoStr(errno
).c_str());
131 if (uid
== 0 || setuid(uid
) < 0) {
132 Logger::Error("unable to drop uid privs: %s",
133 folly::errnoStr(errno
).c_str());
137 if (!setMinimalCapabilities()) {
138 Logger::Error("unable to set minimal server capabiltiies");
146 bool Capability::ChangeUnixUser(const std::string
&username
, bool allowRoot
) {
147 if (!username
.empty()) {
148 struct passwd
*pw
= getpwnam(username
.c_str());
150 Logger::Error("unable to find user %s: %s",
152 folly::errnoStr(errno
).c_str());
155 return ChangeUnixUser(pw
->pw_uid
, allowRoot
);
160 bool Capability::SetDumpable() {
161 if (prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0)) {
162 Logger::Error("Unable to make process dumpable: %s",
163 folly::errnoStr(errno
).c_str());
169 ///////////////////////////////////////////////////////////////////////////////