dir.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* Copyright (c) 2003, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "lib/fs/dir.h"
  6. #include "lib/fs/path.h"
  7. #include "lib/fs/userdb.h"
  8. #include "lib/log/torlog.h"
  9. #include "lib/log/util_bug.h"
  10. #include "lib/log/win32err.h"
  11. #include "lib/container/smartlist.h"
  12. #include "lib/sandbox/sandbox.h"
  13. #include "lib/malloc/util_malloc.h"
  14. #include "lib/string/printf.h"
  15. #include "lib/string/compat_string.h"
  16. #ifdef HAVE_SYS_TYPES_H
  17. #include <sys/types.h>
  18. #endif
  19. #ifdef HAVE_SYS_STAT_H
  20. #include <sys/stat.h>
  21. #endif
  22. #ifdef HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #ifdef HAVE_FCNTL_H
  26. #include <fcntl.h>
  27. #endif
  28. #ifdef _WIN32
  29. #include <io.h>
  30. #include <direct.h>
  31. #include <windows.h>
  32. #else /* !(defined(_WIN32)) */
  33. #include <dirent.h>
  34. #include <pwd.h>
  35. #include <grp.h>
  36. #endif /* defined(_WIN32) */
  37. #include <errno.h>
  38. #include <string.h>
  39. /** Check whether <b>dirname</b> exists and is private. If yes return 0.
  40. * If <b>dirname</b> does not exist:
  41. * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success.
  42. * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0.
  43. * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0.
  44. * - otherwise, return -1.
  45. * If CPD_GROUP_OK is set, then it's okay if the directory
  46. * is group-readable, but in all cases we create the directory mode 0700.
  47. * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and
  48. * if the directory is created it will use mode 0750 with group read
  49. * permission. Group read privileges also assume execute permission
  50. * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't
  51. * alter the directory permissions if they are too permissive:
  52. * we just return -1.
  53. * When effective_user is not NULL, check permissions against the given user
  54. * and its primary group.
  55. */
  56. MOCK_IMPL(int,
  57. check_private_dir,(const char *dirname, cpd_check_t check,
  58. const char *effective_user))
  59. {
  60. int r;
  61. struct stat st;
  62. tor_assert(dirname);
  63. #ifndef _WIN32
  64. int fd;
  65. const struct passwd *pw = NULL;
  66. uid_t running_uid;
  67. gid_t running_gid;
  68. /*
  69. * Goal is to harden the implementation by removing any
  70. * potential for race between stat() and chmod().
  71. * chmod() accepts filename as argument. If an attacker can move
  72. * the file between stat() and chmod(), a potential race exists.
  73. *
  74. * Several suggestions taken from:
  75. * https://developer.apple.com/library/mac/documentation/
  76. * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html
  77. */
  78. /* Open directory.
  79. * O_NOFOLLOW to ensure that it does not follow symbolic links */
  80. fd = open(sandbox_intern_string(dirname), O_NOFOLLOW);
  81. /* Was there an error? Maybe the directory does not exist? */
  82. if (fd == -1) {
  83. if (errno != ENOENT) {
  84. /* Other directory error */
  85. log_warn(LD_FS, "Directory %s cannot be read: %s", dirname,
  86. strerror(errno));
  87. return -1;
  88. }
  89. /* Received ENOENT: Directory does not exist */
  90. /* Should we create the directory? */
  91. if (check & CPD_CREATE) {
  92. log_info(LD_GENERAL, "Creating directory %s", dirname);
  93. if (check & CPD_GROUP_READ) {
  94. r = mkdir(dirname, 0750);
  95. } else {
  96. r = mkdir(dirname, 0700);
  97. }
  98. /* check for mkdir() error */
  99. if (r) {
  100. log_warn(LD_FS, "Error creating directory %s: %s", dirname,
  101. strerror(errno));
  102. return -1;
  103. }
  104. /* we just created the directory. try to open it again.
  105. * permissions on the directory will be checked again below.*/
  106. fd = open(sandbox_intern_string(dirname), O_NOFOLLOW);
  107. if (fd == -1) {
  108. log_warn(LD_FS, "Could not reopen recently created directory %s: %s",
  109. dirname,
  110. strerror(errno));
  111. return -1;
  112. } else {
  113. close(fd);
  114. }
  115. } else if (!(check & CPD_CHECK)) {
  116. log_warn(LD_FS, "Directory %s does not exist.", dirname);
  117. return -1;
  118. }
  119. /* XXXX In the case where check==CPD_CHECK, we should look at the
  120. * parent directory a little harder. */
  121. return 0;
  122. }
  123. tor_assert(fd >= 0);
  124. //f = tor_strdup(dirname);
  125. //clean_name_for_stat(f);
  126. log_debug(LD_FS, "stat()ing %s", dirname);
  127. //r = stat(sandbox_intern_string(f), &st);
  128. r = fstat(fd, &st);
  129. if (r == -1) {
  130. log_warn(LD_FS, "fstat() on directory %s failed.", dirname);
  131. close(fd);
  132. return -1;
  133. }
  134. //tor_free(f);
  135. /* check that dirname is a directory */
  136. if (!(st.st_mode & S_IFDIR)) {
  137. log_warn(LD_FS, "%s is not a directory", dirname);
  138. close(fd);
  139. return -1;
  140. }
  141. if (effective_user) {
  142. /* Look up the user and group information.
  143. * If we have a problem, bail out. */
  144. pw = tor_getpwnam(effective_user);
  145. if (pw == NULL) {
  146. log_warn(LD_CONFIG, "Error setting configured user: %s not found",
  147. effective_user);
  148. close(fd);
  149. return -1;
  150. }
  151. running_uid = pw->pw_uid;
  152. running_gid = pw->pw_gid;
  153. } else {
  154. running_uid = getuid();
  155. running_gid = getgid();
  156. }
  157. if (st.st_uid != running_uid) {
  158. char *process_ownername = NULL, *file_ownername = NULL;
  159. {
  160. const struct passwd *pw_running = tor_getpwuid(running_uid);
  161. process_ownername = pw_running ? tor_strdup(pw_running->pw_name) :
  162. tor_strdup("<unknown>");
  163. }
  164. {
  165. const struct passwd *pw_stat = tor_getpwuid(st.st_uid);
  166. file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) :
  167. tor_strdup("<unknown>");
  168. }
  169. log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by "
  170. "%s (%d). Perhaps you are running Tor as the wrong user?",
  171. dirname, process_ownername, (int)running_uid,
  172. file_ownername, (int)st.st_uid);
  173. tor_free(process_ownername);
  174. tor_free(file_ownername);
  175. close(fd);
  176. return -1;
  177. }
  178. if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ))
  179. && (st.st_gid != running_gid) && (st.st_gid != 0)) {
  180. struct group *gr;
  181. char *process_groupname = NULL;
  182. gr = getgrgid(running_gid);
  183. process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>");
  184. gr = getgrgid(st.st_gid);
  185. log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group "
  186. "%s (%d). Are you running Tor as the wrong user?",
  187. dirname, process_groupname, (int)running_gid,
  188. gr ? gr->gr_name : "<unknown>", (int)st.st_gid);
  189. tor_free(process_groupname);
  190. close(fd);
  191. return -1;
  192. }
  193. unsigned unwanted_bits = 0;
  194. if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) {
  195. unwanted_bits = 0027;
  196. } else {
  197. unwanted_bits = 0077;
  198. }
  199. unsigned check_bits_filter = ~0;
  200. if (check & CPD_RELAX_DIRMODE_CHECK) {
  201. check_bits_filter = 0022;
  202. }
  203. if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) {
  204. unsigned new_mode;
  205. if (check & CPD_CHECK_MODE_ONLY) {
  206. log_warn(LD_FS, "Permissions on directory %s are too permissive.",
  207. dirname);
  208. close(fd);
  209. return -1;
  210. }
  211. log_warn(LD_FS, "Fixing permissions on directory %s", dirname);
  212. new_mode = st.st_mode;
  213. new_mode |= 0700; /* Owner should have rwx */
  214. if (check & CPD_GROUP_READ) {
  215. new_mode |= 0050; /* Group should have rx */
  216. }
  217. new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/
  218. if (fchmod(fd, new_mode)) {
  219. log_warn(LD_FS, "Could not chmod directory %s: %s", dirname,
  220. strerror(errno));
  221. close(fd);
  222. return -1;
  223. } else {
  224. close(fd);
  225. return 0;
  226. }
  227. }
  228. close(fd);
  229. #else /* !(!defined(_WIN32)) */
  230. /* Win32 case: we can't open() a directory. */
  231. (void)effective_user;
  232. char *f = tor_strdup(dirname);
  233. clean_fname_for_stat(f);
  234. log_debug(LD_FS, "stat()ing %s", f);
  235. r = stat(sandbox_intern_string(f), &st);
  236. tor_free(f);
  237. if (r) {
  238. if (errno != ENOENT) {
  239. log_warn(LD_FS, "Directory %s cannot be read: %s", dirname,
  240. strerror(errno));
  241. return -1;
  242. }
  243. if (check & CPD_CREATE) {
  244. log_info(LD_GENERAL, "Creating directory %s", dirname);
  245. r = mkdir(dirname);
  246. if (r) {
  247. log_warn(LD_FS, "Error creating directory %s: %s", dirname,
  248. strerror(errno));
  249. return -1;
  250. }
  251. } else if (!(check & CPD_CHECK)) {
  252. log_warn(LD_FS, "Directory %s does not exist.", dirname);
  253. return -1;
  254. }
  255. return 0;
  256. }
  257. if (!(st.st_mode & S_IFDIR)) {
  258. log_warn(LD_FS, "%s is not a directory", dirname);
  259. return -1;
  260. }
  261. #endif /* !defined(_WIN32) */
  262. return 0;
  263. }
  264. /** Return a new list containing the filenames in the directory <b>dirname</b>.
  265. * Return NULL on error or if <b>dirname</b> is not a directory.
  266. */
  267. MOCK_IMPL(smartlist_t *,
  268. tor_listdir, (const char *dirname))
  269. {
  270. smartlist_t *result;
  271. #ifdef _WIN32
  272. char *pattern=NULL;
  273. TCHAR tpattern[MAX_PATH] = {0};
  274. char name[MAX_PATH*2+1] = {0};
  275. HANDLE handle;
  276. WIN32_FIND_DATA findData;
  277. tor_asprintf(&pattern, "%s\\*", dirname);
  278. #ifdef UNICODE
  279. mbstowcs(tpattern,pattern,MAX_PATH);
  280. #else
  281. strlcpy(tpattern, pattern, MAX_PATH);
  282. #endif
  283. if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) {
  284. tor_free(pattern);
  285. return NULL;
  286. }
  287. result = smartlist_new();
  288. while (1) {
  289. #ifdef UNICODE
  290. wcstombs(name,findData.cFileName,MAX_PATH);
  291. name[sizeof(name)-1] = '\0';
  292. #else
  293. strlcpy(name,findData.cFileName,sizeof(name));
  294. #endif /* defined(UNICODE) */
  295. if (strcmp(name, ".") &&
  296. strcmp(name, "..")) {
  297. smartlist_add_strdup(result, name);
  298. }
  299. if (!FindNextFile(handle, &findData)) {
  300. DWORD err;
  301. if ((err = GetLastError()) != ERROR_NO_MORE_FILES) {
  302. char *errstr = format_win32_error(err);
  303. log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr);
  304. tor_free(errstr);
  305. }
  306. break;
  307. }
  308. }
  309. FindClose(handle);
  310. tor_free(pattern);
  311. #else /* !(defined(_WIN32)) */
  312. const char *prot_dname = sandbox_intern_string(dirname);
  313. DIR *d;
  314. struct dirent *de;
  315. if (!(d = opendir(prot_dname)))
  316. return NULL;
  317. result = smartlist_new();
  318. while ((de = readdir(d))) {
  319. if (!strcmp(de->d_name, ".") ||
  320. !strcmp(de->d_name, ".."))
  321. continue;
  322. smartlist_add_strdup(result, de->d_name);
  323. }
  324. closedir(d);
  325. #endif /* defined(_WIN32) */
  326. return result;
  327. }