path-remove.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * path-remove.c - path removal functionss
  4. *
  5. * Copyright © 1994-1995 Ian Jackson <ian@chiark.greenend.org.uk>
  6. * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <compat.h>
  23. #include <sys/stat.h>
  24. #include <assert.h>
  25. #include <errno.h>
  26. #include <unistd.h>
  27. #include <dpkg/i18n.h>
  28. #include <dpkg/dpkg.h>
  29. #include <dpkg/path.h>
  30. #include <dpkg/debug.h>
  31. #include <dpkg/subproc.h>
  32. int
  33. secure_unlink_statted(const char *pathname, const struct stat *stab)
  34. {
  35. if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
  36. !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
  37. S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
  38. if (chmod(pathname, 0600))
  39. return -1;
  40. }
  41. if (unlink(pathname))
  42. return -1;
  43. return 0;
  44. }
  45. /*
  46. * If the pathname to remove is:
  47. *
  48. * 1. a sticky or set-id file, or
  49. * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
  50. *
  51. * we change its mode so that a malicious user cannot use it, even if it's
  52. * linked to another file.
  53. */
  54. int
  55. secure_unlink(const char *pathname)
  56. {
  57. struct stat stab;
  58. if (lstat(pathname, &stab))
  59. return -1;
  60. return secure_unlink_statted(pathname, &stab);
  61. }
  62. /**
  63. * Securely remove a pathname.
  64. *
  65. * This is a secure version of remove(3) using secure_unlink() instead of
  66. * unlink(2).
  67. *
  68. * @retval 0 On success.
  69. * @retval -1 On failure, just like unlink(2) & rmdir(2).
  70. */
  71. int
  72. secure_remove(const char *pathname)
  73. {
  74. int rc, e;
  75. if (!rmdir(pathname)) {
  76. debug(dbg_eachfiledetail, "secure_remove '%s' rmdir OK",
  77. pathname);
  78. return 0;
  79. }
  80. if (errno != ENOTDIR) {
  81. e = errno;
  82. debug(dbg_eachfiledetail, "secure_remove '%s' rmdir %s",
  83. pathname, strerror(e));
  84. errno = e;
  85. return -1;
  86. }
  87. rc = secure_unlink(pathname);
  88. e = errno;
  89. debug(dbg_eachfiledetail, "secure_remove '%s' unlink %s",
  90. pathname, rc ? strerror(e) : "OK");
  91. errno = e;
  92. return rc;
  93. }
  94. void
  95. path_remove_tree(const char *pathname)
  96. {
  97. pid_t pid;
  98. const char *u;
  99. u = path_skip_slash_dotslash(pathname);
  100. assert(*u);
  101. debug(dbg_eachfile, "%s '%s'", __func__, pathname);
  102. if (!rmdir(pathname))
  103. return; /* Deleted it OK, it was a directory. */
  104. if (errno == ENOENT || errno == ELOOP)
  105. return;
  106. if (errno == ENOTDIR) {
  107. /* Either it's a file, or one of the path components is. If
  108. * one of the path components is this will fail again ... */
  109. if (secure_unlink(pathname) == 0)
  110. return; /* OK, it was. */
  111. if (errno == ENOTDIR)
  112. return;
  113. }
  114. if (errno != ENOTEMPTY && errno != EEXIST) /* Huh? */
  115. ohshite(_("unable to securely remove '%.255s'"), pathname);
  116. pid = subproc_fork();
  117. if (pid == 0) {
  118. execlp(RM, "rm", "-rf", "--", pathname, NULL);
  119. ohshite(_("unable to execute %s (%s)"),
  120. _("rm command for cleanup"), RM);
  121. }
  122. debug(dbg_eachfile, "%s running rm -rf '%s'", __func__, pathname);
  123. subproc_reap(pid, _("rm command for cleanup"), 0);
  124. }