2 * libdpkg - Debian packaging suite library routines
3 * path-remove.c - path removal functions
5 * Copyright © 1994-1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
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.
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.
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/>.
31 #include <dpkg/i18n.h>
32 #include <dpkg/dpkg.h>
33 #include <dpkg/path.h>
34 #include <dpkg/debug.h>
35 #include <dpkg/subproc.h>
38 secure_unlink_statted(const char *pathname
, const struct stat
*stab
)
40 mode_t mode
= stab
->st_mode
;
42 if (S_ISREG(mode
) ? (mode
& 07000) :
43 !(S_ISLNK(mode
) || S_ISDIR(mode
) ||
44 S_ISFIFO(mode
) || S_ISSOCK(mode
))) {
45 if (chmod(pathname
, 0600))
56 * Securely unlink a pathname.
58 * If the pathname to remove is:
60 * 1. a sticky or set-id file, or
61 * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
63 * we change its mode so that a malicious user cannot use it, even if it's
64 * linked to another file.
67 secure_unlink(const char *pathname
)
71 if (lstat(pathname
, &stab
))
74 return secure_unlink_statted(pathname
, &stab
);
78 * Securely remove a pathname.
80 * This is a secure version of remove(3) using secure_unlink() instead of
83 * @retval 0 On success.
84 * @retval -1 On failure, just like unlink(2) & rmdir(2).
87 secure_remove(const char *pathname
)
91 if (!rmdir(pathname
)) {
92 debug(dbg_eachfiledetail
, "secure_remove '%s' rmdir OK",
97 if (errno
!= ENOTDIR
) {
99 debug(dbg_eachfiledetail
, "secure_remove '%s' rmdir %s",
100 pathname
, strerror(e
));
105 rc
= secure_unlink(pathname
);
107 debug(dbg_eachfiledetail
, "secure_remove '%s' unlink %s",
108 pathname
, rc
? strerror(e
) : "OK");
115 * Remove a pathname and anything below it.
117 * This function removes pathname and all its contents recursively.
120 path_remove_tree(const char *pathname
)
125 u
= path_skip_slash_dotslash(pathname
);
127 internerr("pathname '%s' reduces to nothing", pathname
);
129 debug(dbg_eachfile
, "%s '%s'", __func__
, pathname
);
130 if (!rmdir(pathname
))
131 return; /* Deleted it OK, it was a directory. */
132 if (errno
== ENOENT
|| errno
== ELOOP
)
134 if (errno
== ENOTDIR
) {
135 /* Either it's a file, or one of the path components is. If
136 * one of the path components is this will fail again ... */
137 if (secure_unlink(pathname
) == 0)
138 return; /* OK, it was. */
139 if (errno
== ENOTDIR
)
142 /* Trying to remove a directory or a file on a read-only filesystem,
143 * even if non-existent, always returns EROFS. */
144 if (errno
== EROFS
) {
145 if (access(pathname
, F_OK
) < 0 && errno
== ENOENT
)
149 if (errno
!= ENOTEMPTY
&& errno
!= EEXIST
) /* Huh? */
150 ohshite(_("unable to securely remove '%.255s'"), pathname
);
152 pid
= subproc_fork();
154 execlp(RM
, "rm", "-rf", "--", pathname
, NULL
);
155 ohshite(_("unable to execute %s (%s)"),
156 _("rm command for cleanup"), RM
);
158 debug(dbg_eachfile
, "%s running rm -rf '%s'", __func__
, pathname
);
159 subproc_reap(pid
, _("rm command for cleanup"), 0);