declare_folded_class NO LONGER _in_file
[hiphop-php.git] / hphp / util / capability.cpp
blob685fe9a6e31b0c5fe285668e841f0caff4fabb3a
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 "hphp/util/user-info.h"
22 #include <folly/String.h>
23 #include <linux/types.h>
24 #include <sys/capability.h>
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <pwd.h>
28 #include <grp.h>
30 namespace HPHP {
31 ///////////////////////////////////////////////////////////////////////////////
33 static bool setInitialCapabilities() {
34 cap_t cap_d = cap_init();
35 if (cap_d != nullptr) {
36 cap_value_t cap_list[] = {CAP_NET_BIND_SERVICE, CAP_SYS_RESOURCE,
37 CAP_SETUID, CAP_SETGID, CAP_SYS_NICE};
38 constexpr unsigned cap_size = sizeof(cap_list)/sizeof(*cap_list);
40 cap_clear(cap_d);
42 if (cap_set_flag(cap_d, CAP_PERMITTED, cap_size, cap_list, CAP_SET) < 0 ||
43 cap_set_flag(cap_d, CAP_EFFECTIVE, cap_size, cap_list, CAP_SET) < 0) {
44 Logger::Error("cap_set_flag failed: %s", folly::errnoStr(errno).c_str());
45 return false;
48 if (cap_set_proc(cap_d) == -1) {
49 Logger::Error("cap_set_proc failed: %s", folly::errnoStr(errno).c_str());
50 return false;
53 if (cap_free(cap_d) == -1) {
54 Logger::Error("cap_free failed: %s", folly::errnoStr(errno).c_str());
55 return false;
58 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
59 Logger::Error("prctl(PR_SET_KEEPCAPS) failed: %s",
60 folly::errnoStr(errno).c_str());
61 return false;
63 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
64 return true;
66 return false;
69 static bool setMinimalCapabilities() {
70 cap_t cap_d = cap_init();
72 if (cap_d != nullptr) {
73 cap_value_t cap_list[] = {CAP_NET_BIND_SERVICE, CAP_SYS_RESOURCE,
74 CAP_SYS_NICE};
75 constexpr unsigned cap_size = sizeof(cap_list)/sizeof(*cap_list);
77 cap_clear(cap_d);
79 if (cap_set_flag(cap_d, CAP_PERMITTED, cap_size, cap_list, CAP_SET) < 0 ||
80 cap_set_flag(cap_d, CAP_EFFECTIVE, cap_size, cap_list, CAP_SET) < 0) {
81 Logger::Error("cap_set_flag failed: %s", folly::errnoStr(errno).c_str());
82 return false;
85 if (cap_set_proc(cap_d) == -1) {
86 Logger::Error("cap_set_proc failed: %s", folly::errnoStr(errno).c_str());
87 return false;
90 if (cap_free(cap_d) == -1) {
91 Logger::Error("cap_free failed: %s", folly::errnoStr(errno).c_str());
92 return false;
95 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
96 return true;
98 return false;
101 bool Capability::ChangeUnixUser(uid_t uid, bool allowRoot) {
102 if (uid == 0 && !allowRoot) {
103 Logger::Error("unable to change user to root");
104 return false;
107 if (uid == getuid()) {
108 return true;
111 if (setInitialCapabilities()) {
112 auto buf = PasswdBuffer{};
113 struct passwd *pw;
115 if (getpwuid_r(uid, &buf.ent, buf.data.get(), buf.size, &pw)) {
116 Logger::Error("unable to getpwuid(%d): %s", uid,
117 folly::errnoStr(errno).c_str());
118 return false;
120 if (pw == nullptr) {
121 Logger::Error("user id %d does not exist", uid);
122 return false;
125 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
126 Logger::Error("unable to drop supplementary group privs: %s",
127 folly::errnoStr(errno).c_str());
128 return false;
131 if (pw->pw_gid == 0 || setgid(pw->pw_gid) < 0) {
132 Logger::Error("unable to drop gid privs: %s",
133 folly::errnoStr(errno).c_str());
134 return false;
137 if (uid == 0 || setuid(uid) < 0) {
138 Logger::Error("unable to drop uid privs: %s",
139 folly::errnoStr(errno).c_str());
140 return false;
143 if (!setMinimalCapabilities()) {
144 Logger::Error("unable to set minimal server capabilities");
145 return false;
147 return true;
149 return false;
152 bool Capability::ChangeUnixUser(const std::string &username, bool allowRoot) {
153 if (!username.empty()) {
154 auto buf = PasswdBuffer{};
155 struct passwd *pw;
156 if (getpwnam_r(username.c_str(), &buf.ent, buf.data.get(), buf.size, &pw)) {
157 Logger::Error("Call to getpwnam_r failed for %s: %s",
158 username.c_str(),
159 folly::errnoStr(errno).c_str());
160 return false;
162 if (!pw) {
163 Logger::Error("unable to find user %s", username.c_str());
164 return false;
166 return ChangeUnixUser(pw->pw_uid, allowRoot);
168 return false;
171 bool Capability::SetDumpable() {
172 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
173 Logger::Error("Unable to make process dumpable: %s",
174 folly::errnoStr(errno).c_str());
177 return true;
180 ///////////////////////////////////////////////////////////////////////////////
183 #endif