setuid.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /* Copyright (c) 2003, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file setuid.c
  7. * \brief Change the user ID after Tor has started (Unix only)
  8. **/
  9. #include "orconfig.h"
  10. #include "lib/process/setuid.h"
  11. #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC)
  12. #define HAVE_LINUX_CAPABILITIES
  13. #endif
  14. #include "lib/container/smartlist.h"
  15. #include "lib/fs/userdb.h"
  16. #include "lib/log/log.h"
  17. #include "lib/log/util_bug.h"
  18. #include "lib/malloc/malloc.h"
  19. #ifdef HAVE_SYS_TYPES_H
  20. #include <sys/types.h>
  21. #endif
  22. #ifdef HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #ifdef HAVE_GRP_H
  26. #include <grp.h>
  27. #endif
  28. #ifdef HAVE_PWD_H
  29. #include <pwd.h>
  30. #endif
  31. #ifdef HAVE_SYS_CAPABILITY_H
  32. #include <sys/capability.h>
  33. #endif
  34. #ifdef HAVE_SYS_PRCTL_H
  35. #include <sys/prctl.h>
  36. #endif
  37. #include <errno.h>
  38. #include <string.h>
  39. #ifndef _WIN32
  40. /** Log details of current user and group credentials. Return 0 on
  41. * success. Logs and return -1 on failure.
  42. */
  43. static int
  44. log_credential_status(void)
  45. {
  46. /** Log level to use when describing non-error UID/GID status. */
  47. #define CREDENTIAL_LOG_LEVEL LOG_INFO
  48. /* Real, effective and saved UIDs */
  49. uid_t ruid, euid, suid;
  50. /* Read, effective and saved GIDs */
  51. gid_t rgid, egid, sgid;
  52. /* Supplementary groups */
  53. gid_t *sup_gids = NULL;
  54. int sup_gids_size;
  55. /* Number of supplementary groups */
  56. int ngids;
  57. /* log UIDs */
  58. #ifdef HAVE_GETRESUID
  59. if (getresuid(&ruid, &euid, &suid) != 0 ) {
  60. log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno));
  61. return -1;
  62. } else {
  63. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL,
  64. "UID is %u (real), %u (effective), %u (saved)",
  65. (unsigned)ruid, (unsigned)euid, (unsigned)suid);
  66. }
  67. #else /* !(defined(HAVE_GETRESUID)) */
  68. /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */
  69. ruid = getuid();
  70. euid = geteuid();
  71. (void)suid;
  72. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL,
  73. "UID is %u (real), %u (effective), unknown (saved)",
  74. (unsigned)ruid, (unsigned)euid);
  75. #endif /* defined(HAVE_GETRESUID) */
  76. /* log GIDs */
  77. #ifdef HAVE_GETRESGID
  78. if (getresgid(&rgid, &egid, &sgid) != 0 ) {
  79. log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno));
  80. return -1;
  81. } else {
  82. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL,
  83. "GID is %u (real), %u (effective), %u (saved)",
  84. (unsigned)rgid, (unsigned)egid, (unsigned)sgid);
  85. }
  86. #else /* !(defined(HAVE_GETRESGID)) */
  87. /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */
  88. rgid = getgid();
  89. egid = getegid();
  90. (void)sgid;
  91. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL,
  92. "GID is %u (real), %u (effective), unknown (saved)",
  93. (unsigned)rgid, (unsigned)egid);
  94. #endif /* defined(HAVE_GETRESGID) */
  95. /* log supplementary groups */
  96. sup_gids_size = 64;
  97. sup_gids = tor_calloc(64, sizeof(gid_t));
  98. while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 &&
  99. errno == EINVAL &&
  100. sup_gids_size < NGROUPS_MAX) {
  101. sup_gids_size *= 2;
  102. sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size);
  103. }
  104. if (ngids < 0) {
  105. log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s",
  106. strerror(errno));
  107. tor_free(sup_gids);
  108. return -1;
  109. } else {
  110. int i, retval = 0;
  111. char *s = NULL;
  112. smartlist_t *elts = smartlist_new();
  113. for (i = 0; i<ngids; i++) {
  114. smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]);
  115. }
  116. s = smartlist_join_strings(elts, " ", 0, NULL);
  117. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s);
  118. tor_free(s);
  119. SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
  120. smartlist_free(elts);
  121. tor_free(sup_gids);
  122. return retval;
  123. }
  124. return 0;
  125. }
  126. #endif /* !defined(_WIN32) */
  127. /** Return true iff we were compiled with capability support, and capabilities
  128. * seem to work. **/
  129. int
  130. have_capability_support(void)
  131. {
  132. #ifdef HAVE_LINUX_CAPABILITIES
  133. cap_t caps = cap_get_proc();
  134. if (caps == NULL)
  135. return 0;
  136. cap_free(caps);
  137. return 1;
  138. #else /* !(defined(HAVE_LINUX_CAPABILITIES)) */
  139. return 0;
  140. #endif /* defined(HAVE_LINUX_CAPABILITIES) */
  141. }
  142. #ifdef HAVE_LINUX_CAPABILITIES
  143. /** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as
  144. * appropriate.
  145. *
  146. * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and
  147. * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across
  148. * setuid().
  149. *
  150. * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable
  151. * PR_KEEPCAPS.
  152. *
  153. * Return 0 on success, and -1 on failure.
  154. */
  155. static int
  156. drop_capabilities(int pre_setuid)
  157. {
  158. /* We keep these three capabilities, and these only, as we setuid.
  159. * After we setuid, we drop all but the first. */
  160. const cap_value_t caplist[] = {
  161. CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID
  162. };
  163. const char *where = pre_setuid ? "pre-setuid" : "post-setuid";
  164. const int n_effective = pre_setuid ? 3 : 1;
  165. const int n_permitted = pre_setuid ? 3 : 1;
  166. const int n_inheritable = 1;
  167. const int keepcaps = pre_setuid ? 1 : 0;
  168. /* Sets whether we keep capabilities across a setuid. */
  169. if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) {
  170. log_warn(LD_CONFIG, "Unable to call prctl() %s: %s",
  171. where, strerror(errno));
  172. return -1;
  173. }
  174. cap_t caps = cap_get_proc();
  175. if (!caps) {
  176. log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s",
  177. where, strerror(errno));
  178. return -1;
  179. }
  180. cap_clear(caps);
  181. cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET);
  182. cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET);
  183. cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET);
  184. int r = cap_set_proc(caps);
  185. cap_free(caps);
  186. if (r < 0) {
  187. log_warn(LD_CONFIG, "No permission to set capabilities %s: %s",
  188. where, strerror(errno));
  189. return -1;
  190. }
  191. return 0;
  192. }
  193. #endif /* defined(HAVE_LINUX_CAPABILITIES) */
  194. /** Call setuid and setgid to run as <b>user</b> and switch to their
  195. * primary group. Return 0 on success. On failure, log and return -1.
  196. *
  197. * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability
  198. * system to retain the abilitity to bind low ports.
  199. *
  200. * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have
  201. * don't have capability support.
  202. */
  203. int
  204. switch_id(const char *user, const unsigned flags)
  205. {
  206. #ifndef _WIN32
  207. const struct passwd *pw = NULL;
  208. uid_t old_uid;
  209. gid_t old_gid;
  210. static int have_already_switched_id = 0;
  211. const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW);
  212. const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS);
  213. tor_assert(user);
  214. if (have_already_switched_id)
  215. return 0;
  216. /* Log the initial credential state */
  217. if (log_credential_status())
  218. return -1;
  219. log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups");
  220. /* Get old UID/GID to check if we changed correctly */
  221. old_uid = getuid();
  222. old_gid = getgid();
  223. /* Lookup the user and group information, if we have a problem, bail out. */
  224. pw = tor_getpwnam(user);
  225. if (pw == NULL) {
  226. log_warn(LD_CONFIG, "Error setting configured user: %s not found", user);
  227. return -1;
  228. }
  229. #ifdef HAVE_LINUX_CAPABILITIES
  230. (void) warn_if_no_caps;
  231. if (keep_bindlow) {
  232. if (drop_capabilities(1))
  233. return -1;
  234. }
  235. #else /* !(defined(HAVE_LINUX_CAPABILITIES)) */
  236. (void) keep_bindlow;
  237. if (warn_if_no_caps) {
  238. log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support "
  239. "on this system.");
  240. }
  241. #endif /* defined(HAVE_LINUX_CAPABILITIES) */
  242. /* Properly switch egid,gid,euid,uid here or bail out */
  243. if (setgroups(1, &pw->pw_gid)) {
  244. log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".",
  245. (int)pw->pw_gid, strerror(errno));
  246. if (old_uid == pw->pw_uid) {
  247. log_warn(LD_GENERAL, "Tor is already running as %s. You do not need "
  248. "the \"User\" option if you are already running as the user "
  249. "you want to be. (If you did not set the User option in your "
  250. "torrc, check whether it was specified on the command line "
  251. "by a startup script.)", user);
  252. } else {
  253. log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor"
  254. " as root.");
  255. }
  256. return -1;
  257. }
  258. if (setegid(pw->pw_gid)) {
  259. log_warn(LD_GENERAL, "Error setting egid to %d: %s",
  260. (int)pw->pw_gid, strerror(errno));
  261. return -1;
  262. }
  263. if (setgid(pw->pw_gid)) {
  264. log_warn(LD_GENERAL, "Error setting gid to %d: %s",
  265. (int)pw->pw_gid, strerror(errno));
  266. return -1;
  267. }
  268. if (setuid(pw->pw_uid)) {
  269. log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s",
  270. user, (int)pw->pw_uid, strerror(errno));
  271. return -1;
  272. }
  273. if (seteuid(pw->pw_uid)) {
  274. log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s",
  275. user, (int)pw->pw_uid, strerror(errno));
  276. return -1;
  277. }
  278. /* This is how OpenBSD rolls:
  279. if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) ||
  280. setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) {
  281. setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) {
  282. log_warn(LD_GENERAL, "Error setting configured UID/GID: %s",
  283. strerror(errno));
  284. return -1;
  285. }
  286. */
  287. /* We've properly switched egid, gid, euid, uid, and supplementary groups if
  288. * we're here. */
  289. #ifdef HAVE_LINUX_CAPABILITIES
  290. if (keep_bindlow) {
  291. if (drop_capabilities(0))
  292. return -1;
  293. }
  294. #endif /* defined(HAVE_LINUX_CAPABILITIES) */
  295. #if !defined(CYGWIN) && !defined(__CYGWIN__)
  296. /* If we tried to drop privilege to a group/user other than root, attempt to
  297. * restore root (E)(U|G)ID, and abort if the operation succeeds */
  298. /* Only check for privilege dropping if we were asked to be non-root */
  299. if (pw->pw_uid) {
  300. /* Try changing GID/EGID */
  301. if (pw->pw_gid != old_gid &&
  302. (setgid(old_gid) != -1 || setegid(old_gid) != -1)) {
  303. log_warn(LD_GENERAL, "Was able to restore group credentials even after "
  304. "switching GID: this means that the setgid code didn't work.");
  305. return -1;
  306. }
  307. /* Try changing UID/EUID */
  308. if (pw->pw_uid != old_uid &&
  309. (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) {
  310. log_warn(LD_GENERAL, "Was able to restore user credentials even after "
  311. "switching UID: this means that the setuid code didn't work.");
  312. return -1;
  313. }
  314. }
  315. #endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */
  316. /* Check what really happened */
  317. if (log_credential_status()) {
  318. return -1;
  319. }
  320. have_already_switched_id = 1; /* mark success so we never try again */
  321. #if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \
  322. defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
  323. if (pw->pw_uid) {
  324. /* Re-enable core dumps if we're not running as root. */
  325. log_info(LD_CONFIG, "Re-enabling coredumps");
  326. if (prctl(PR_SET_DUMPABLE, 1)) {
  327. log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno));
  328. }
  329. }
  330. #endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */
  331. return 0;
  332. #else /* !(!defined(_WIN32)) */
  333. (void)user;
  334. (void)flags;
  335. log_warn(LD_CONFIG, "Switching users is unsupported on your OS.");
  336. return -1;
  337. #endif /* !defined(_WIN32) */
  338. }