14 #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC)
15 #define HAVE_LINUX_CAPABILITIES
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
36 #ifdef HAVE_SYS_CAPABILITY_H
37 #include <sys/capability.h>
39 #ifdef HAVE_SYS_PRCTL_H
40 #include <sys/prctl.h>
54 #define CREDENTIAL_LOG_LEVEL LOG_INFO
56 uid_t ruid, euid, suid;
58 gid_t rgid, egid, sgid;
60 gid_t *sup_gids = NULL;
67 if (getresuid(&ruid, &euid, &suid) != 0) {
68 log_warn(
LD_GENERAL,
"Error getting changed UIDs: %s", strerror(errno));
72 "UID is %u (real), %u (effective), %u (saved)",
73 (
unsigned)ruid, (
unsigned)euid, (
unsigned)suid);
82 "UID is %u (real), %u (effective), unknown (saved)",
83 (
unsigned)ruid, (
unsigned)euid);
88 if (getresgid(&rgid, &egid, &sgid) != 0) {
89 log_warn(
LD_GENERAL,
"Error getting changed GIDs: %s", strerror(errno));
93 "GID is %u (real), %u (effective), %u (saved)",
94 (
unsigned)rgid, (
unsigned)egid, (
unsigned)sgid);
102 "GID is %u (real), %u (effective), unknown (saved)",
103 (
unsigned)rgid, (
unsigned)egid);
108 sup_gids = tor_calloc(64,
sizeof(gid_t));
109 while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 &&
111 sup_gids_size < NGROUPS_MAX) {
113 sup_gids = tor_reallocarray(sup_gids,
sizeof(gid_t), sup_gids_size);
117 log_warn(
LD_GENERAL,
"Error getting supplementary GIDs: %s",
126 for (i = 0; i<ngids; i++) {
136 smartlist_free(elts);
151 #ifdef HAVE_LINUX_CAPABILITIES
152 cap_t caps = cap_get_proc();
162 #ifdef HAVE_LINUX_CAPABILITIES
176 drop_capabilities(
int pre_setuid)
180 const cap_value_t caplist[] = {
181 CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID
183 const char *where = pre_setuid ?
"pre-setuid" :
"post-setuid";
184 const int n_effective = pre_setuid ? 3 : 1;
185 const int n_permitted = pre_setuid ? 3 : 1;
186 const int n_inheritable = 1;
187 const int keepcaps = pre_setuid ? 1 : 0;
190 if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) {
191 log_warn(
LD_CONFIG,
"Unable to call prctl() %s: %s",
192 where, strerror(errno));
196 cap_t caps = cap_get_proc();
198 log_warn(
LD_CONFIG,
"Unable to call cap_get_proc() %s: %s",
199 where, strerror(errno));
204 cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET);
205 cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET);
206 cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET);
208 int r = cap_set_proc(caps);
211 log_warn(
LD_CONFIG,
"No permission to set capabilities %s: %s",
212 where, strerror(errno));
233 const struct passwd *pw = NULL;
236 static int have_already_switched_id = 0;
242 if (have_already_switched_id)
258 log_warn(
LD_CONFIG,
"Error setting configured user: %s not found", user);
262 #ifdef HAVE_LINUX_CAPABILITIES
263 (void) warn_if_no_caps;
265 if (drop_capabilities(1))
270 if (warn_if_no_caps) {
271 log_warn(
LD_CONFIG,
"KeepBindCapabilities set, but no capability support "
277 if (setgroups(1, &pw->pw_gid)) {
278 log_warn(
LD_GENERAL,
"Error setting groups to gid %d: \"%s\".",
279 (
int)pw->pw_gid, strerror(errno));
280 if (old_uid == pw->pw_uid) {
281 log_warn(
LD_GENERAL,
"Tor is already running as %s. You do not need "
282 "the \"User\" option if you are already running as the user "
283 "you want to be. (If you did not set the User option in your "
284 "torrc, check whether it was specified on the command line "
285 "by a startup script.)", user);
287 log_warn(
LD_GENERAL,
"If you set the \"User\" option, you must start Tor"
293 if (setegid(pw->pw_gid)) {
294 log_warn(
LD_GENERAL,
"Error setting egid to %d: %s",
295 (
int)pw->pw_gid, strerror(errno));
299 if (setgid(pw->pw_gid)) {
300 log_warn(
LD_GENERAL,
"Error setting gid to %d: %s",
301 (
int)pw->pw_gid, strerror(errno));
305 if (setuid(pw->pw_uid)) {
306 log_warn(
LD_GENERAL,
"Error setting configured uid to %s (%d): %s",
307 user, (
int)pw->pw_uid, strerror(errno));
311 if (seteuid(pw->pw_uid)) {
312 log_warn(
LD_GENERAL,
"Error setting configured euid to %s (%d): %s",
313 user, (
int)pw->pw_uid, strerror(errno));
329 #ifdef HAVE_LINUX_CAPABILITIES
331 if (drop_capabilities(0))
336 #if !defined(CYGWIN) && !defined(__CYGWIN__)
343 if (pw->pw_gid != old_gid &&
344 (setgid(old_gid) != -1 || setegid(old_gid) != -1)) {
345 log_warn(
LD_GENERAL,
"Was able to restore group credentials even after "
346 "switching GID: this means that the setgid code didn't work.");
351 if (pw->pw_uid != old_uid &&
352 (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) {
353 log_warn(
LD_GENERAL,
"Was able to restore user credentials even after "
354 "switching UID: this means that the setuid code didn't work.");
365 have_already_switched_id = 1;
367 #if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \
368 defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
371 log_info(
LD_CONFIG,
"Re-enabling coredumps");
372 if (prctl(PR_SET_DUMPABLE, 1)) {
373 log_warn(
LD_CONFIG,
"Unable to re-enable coredumps: %s",strerror(errno));
383 log_warn(
LD_CONFIG,
"Switching users is unsupported on your OS.");
#define log_fn(severity, domain, args,...)
Headers for util_malloc.c.
static int log_credential_status(void)
int have_capability_support(void)
int switch_id(const char *user, const unsigned flags)
#define SWITCH_ID_WARN_IF_NO_CAPS
#define SWITCH_ID_KEEP_BINDLOW
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
const struct passwd * tor_getpwnam(const char *username)
Macros to manage assertions, fatal and non-fatal.