secutil.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * secutil.c
  6. */
  7. #include "secutil.h"
  8. #include "str.h"
  9. #include "sysutil.h"
  10. #include "sysstr.h"
  11. #include "utility.h"
  12. #include "sysdeputil.h"
  13. void
  14. vsf_secutil_change_credentials(const struct mystr* p_user_str,
  15. const struct mystr* p_dir_str,
  16. const struct mystr* p_ext_dir_str,
  17. unsigned int caps, unsigned int options)
  18. {
  19. struct vsf_sysutil_user* p_user;
  20. if (!vsf_sysutil_running_as_root())
  21. {
  22. bug("not running as root");
  23. }
  24. p_user = str_getpwnam(p_user_str);
  25. if (p_user == 0)
  26. {
  27. die2("cannot locate user entry:", str_getbuf(p_user_str));
  28. }
  29. {
  30. struct mystr dir_str = INIT_MYSTR;
  31. /* Work out where the chroot() jail is */
  32. if (p_dir_str == 0 || str_isempty(p_dir_str))
  33. {
  34. str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user));
  35. }
  36. else
  37. {
  38. str_copy(&dir_str, p_dir_str);
  39. }
  40. /* Sort out supplementary groups before the chroot(). We need to access
  41. * /etc/groups
  42. */
  43. if (options & VSF_SECUTIL_OPTION_USE_GROUPS)
  44. {
  45. vsf_sysutil_initgroups(p_user);
  46. }
  47. else
  48. {
  49. vsf_sysutil_clear_supp_groups();
  50. }
  51. /* Always do the chdir() regardless of whether we are chroot()'ing */
  52. {
  53. /* Do chdir() with the target effective IDs to cater for NFS mounted
  54. * home directories.
  55. */
  56. int saved_euid = 0;
  57. int saved_egid = 0;
  58. int retval;
  59. if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
  60. {
  61. saved_euid = vsf_sysutil_geteuid();
  62. saved_egid = vsf_sysutil_getegid();
  63. vsf_sysutil_setegid(p_user);
  64. vsf_sysutil_seteuid(p_user);
  65. }
  66. retval = str_chdir(&dir_str);
  67. if (retval != 0)
  68. {
  69. die2("cannot change directory:", str_getbuf(&dir_str));
  70. }
  71. if (p_ext_dir_str && !str_isempty(p_ext_dir_str))
  72. {
  73. retval = str_chdir(p_ext_dir_str);
  74. /* Failure on the extra directory is OK as long as we're not in
  75. * chroot() mode
  76. */
  77. if (retval != 0 && !(options & VSF_SECUTIL_OPTION_CHROOT))
  78. {
  79. retval = 0;
  80. }
  81. }
  82. if (retval != 0)
  83. {
  84. die2("cannot change directory:", str_getbuf(p_ext_dir_str));
  85. }
  86. if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
  87. {
  88. vsf_sysutil_seteuid_numeric(saved_euid);
  89. vsf_sysutil_setegid_numeric(saved_egid);
  90. }
  91. /* Do the chroot() if required */
  92. if (options & VSF_SECUTIL_OPTION_CHROOT)
  93. {
  94. vsf_sysutil_chroot(".");
  95. }
  96. }
  97. str_free(&dir_str);
  98. }
  99. if (options & VSF_SECUTIL_OPTION_NO_FDS)
  100. {
  101. vsf_sysutil_set_no_fds();
  102. }
  103. /* Handle capabilities */
  104. if (caps)
  105. {
  106. if (!vsf_sysdep_has_capabilities())
  107. {
  108. /* Need privilege but OS has no capabilities - have to keep root */
  109. return;
  110. }
  111. if (!vsf_sysdep_has_capabilities_as_non_root())
  112. {
  113. vsf_sysdep_adopt_capabilities(caps);
  114. return;
  115. }
  116. vsf_sysdep_keep_capabilities();
  117. }
  118. /* Set group id */
  119. vsf_sysutil_setgid(p_user);
  120. /* Finally set user id */
  121. vsf_sysutil_setuid(p_user);
  122. if (caps)
  123. {
  124. vsf_sysdep_adopt_capabilities(caps);
  125. }
  126. if (options & VSF_SECUTIL_OPTION_NO_PROCS)
  127. {
  128. vsf_sysutil_set_no_procs();
  129. }
  130. /* Misconfiguration check: don't ever chroot() to a directory writable by
  131. * the current user.
  132. */
  133. if ((options & VSF_SECUTIL_OPTION_CHROOT) &&
  134. !(options & VSF_SECUTIL_OPTION_ALLOW_WRITEABLE_ROOT))
  135. {
  136. if (vsf_sysutil_write_access("/"))
  137. {
  138. die("ftpz: writable root inside chroot()");
  139. }
  140. }
  141. }