userdb.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* Copyright (c) 2003-2004, 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 userdb.c
  7. *
  8. * \brief Access the POSIX user database.
  9. **/
  10. #include "lib/fs/userdb.h"
  11. #ifndef _WIN32
  12. #include "lib/malloc/malloc.h"
  13. #include "lib/log/log.h"
  14. #include "lib/log/util_bug.h"
  15. #include <pwd.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18. /** Cached struct from the last getpwname() call we did successfully. */
  19. static struct passwd *passwd_cached = NULL;
  20. /** Helper: copy a struct passwd object.
  21. *
  22. * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use
  23. * any others, and I don't want to run into incompatibilities.
  24. */
  25. static struct passwd *
  26. tor_passwd_dup(const struct passwd *pw)
  27. {
  28. struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd));
  29. if (pw->pw_name)
  30. new_pw->pw_name = tor_strdup(pw->pw_name);
  31. if (pw->pw_dir)
  32. new_pw->pw_dir = tor_strdup(pw->pw_dir);
  33. new_pw->pw_uid = pw->pw_uid;
  34. new_pw->pw_gid = pw->pw_gid;
  35. return new_pw;
  36. }
  37. #define tor_passwd_free(pw) \
  38. FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw))
  39. /** Helper: free one of our cached 'struct passwd' values. */
  40. static void
  41. tor_passwd_free_(struct passwd *pw)
  42. {
  43. if (!pw)
  44. return;
  45. tor_free(pw->pw_name);
  46. tor_free(pw->pw_dir);
  47. tor_free(pw);
  48. }
  49. /** Wrapper around getpwnam() that caches result. Used so that we don't need
  50. * to give the sandbox access to /etc/passwd.
  51. *
  52. * The following fields alone will definitely be copied in the output: pw_uid,
  53. * pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
  54. *
  55. * When called with a NULL argument, this function clears storage associated
  56. * with static variables it uses.
  57. **/
  58. const struct passwd *
  59. tor_getpwnam(const char *username)
  60. {
  61. struct passwd *pw;
  62. if (username == NULL) {
  63. tor_passwd_free(passwd_cached);
  64. passwd_cached = NULL;
  65. return NULL;
  66. }
  67. if ((pw = getpwnam(username))) {
  68. tor_passwd_free(passwd_cached);
  69. passwd_cached = tor_passwd_dup(pw);
  70. log_info(LD_GENERAL, "Caching new entry %s for %s",
  71. passwd_cached->pw_name, username);
  72. return pw;
  73. }
  74. /* Lookup failed */
  75. if (! passwd_cached || ! passwd_cached->pw_name)
  76. return NULL;
  77. if (! strcmp(username, passwd_cached->pw_name))
  78. return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
  79. return NULL;
  80. }
  81. /** Wrapper around getpwnam() that can use cached result from
  82. * tor_getpwnam(). Used so that we don't need to give the sandbox access to
  83. * /etc/passwd.
  84. *
  85. * The following fields alone will definitely be copied in the output: pw_uid,
  86. * pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
  87. */
  88. const struct passwd *
  89. tor_getpwuid(uid_t uid)
  90. {
  91. struct passwd *pw;
  92. if ((pw = getpwuid(uid))) {
  93. return pw;
  94. }
  95. /* Lookup failed */
  96. if (! passwd_cached)
  97. return NULL;
  98. if (uid == passwd_cached->pw_uid)
  99. return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
  100. return NULL;
  101. }
  102. /** Allocate and return a string containing the home directory for the
  103. * user <b>username</b>. Only works on posix-like systems. */
  104. char *
  105. get_user_homedir(const char *username)
  106. {
  107. const struct passwd *pw;
  108. tor_assert(username);
  109. if (!(pw = tor_getpwnam(username))) {
  110. log_err(LD_CONFIG,"User \"%s\" not found.", username);
  111. return NULL;
  112. }
  113. return tor_strdup(pw->pw_dir);
  114. }
  115. #endif /* !defined(_WIN32) */