浏览代码

libdpkg: Move path removal functions to path-remove module

Guillem Jover 11 年之前
父节点
当前提交
f603dc5d08
共有 10 个文件被更改,包括 158 次插入105 次删除
  1. 1 0
      lib/dpkg/Makefile.am
  2. 4 0
      lib/dpkg/libdpkg.map
  3. 143 0
      lib/dpkg/path-remove.c
  4. 8 0
      lib/dpkg/path.h
  5. 0 35
      src/archives.c
  6. 0 2
      src/archives.h
  7. 1 0
      src/cleanup.c
  8. 0 65
      src/help.c
  9. 0 3
      src/main.h
  10. 1 0
      src/remove.c

+ 1 - 0
lib/dpkg/Makefile.am

@@ -71,6 +71,7 @@ libdpkg_la_SOURCES = \
 	parse.c \
 	parsehelp.c \
 	path.c \
+	path-remove.c \
 	pkg.c \
 	pkg-db.c \
 	pkg-array.c \

+ 4 - 0
lib/dpkg/libdpkg.map

@@ -98,6 +98,10 @@ LIBDPKG_PRIVATE {
 	varbuf_destroy;
 
 	# Path, directory and file functions
+	secure_unlink_statted;
+	secure_unlink;
+	secure_remove;
+	path_remove_tree;
 	path_skip_slash_dotslash;
 	path_trim_slash_slashdot;
 	path_basename;

+ 143 - 0
lib/dpkg/path-remove.c

@@ -0,0 +1,143 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * path-remove.c - path removal functionss
+ *
+ * Copyright © 1994-1995 Ian Jackson <ian@chiark.greenend.org.uk>
+ * Copyright © 2007-2014 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/path.h>
+#include <dpkg/debug.h>
+#include <dpkg/subproc.h>
+
+int
+secure_unlink_statted(const char *pathname, const struct stat *stab)
+{
+	if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
+	    !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
+	      S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
+		if (chmod(pathname, 0600))
+			return -1;
+	}
+
+	if (unlink(pathname))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * If the pathname to remove is:
+ *
+ * 1. a sticky or set-id file, or
+ * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
+ *
+ * we change its mode so that a malicious user cannot use it, even if it's
+ * linked to another file.
+ */
+int
+secure_unlink(const char *pathname)
+{
+	struct stat stab;
+
+	if (lstat(pathname, &stab))
+		return -1;
+
+	return secure_unlink_statted(pathname, &stab);
+}
+
+/**
+ * Securely remove a pathname.
+ *
+ * This is a secure version of remove(3) using secure_unlink() instead of
+ * unlink(2).
+ *
+ * @retval  0 On success.
+ * @retval -1 On failure, just like unlink(2) & rmdir(2).
+ */
+int
+secure_remove(const char *pathname)
+{
+	int rc, e;
+
+	if (!rmdir(pathname)) {
+		debug(dbg_eachfiledetail, "secure_remove '%s' rmdir OK",
+		      pathname);
+		return 0;
+	}
+
+	if (errno != ENOTDIR) {
+		e = errno;
+		debug(dbg_eachfiledetail, "secure_remove '%s' rmdir %s",
+		      pathname, strerror(e));
+		errno = e;
+		return -1;
+	}
+
+	rc = secure_unlink(pathname);
+	e = errno;
+	debug(dbg_eachfiledetail, "secure_remove '%s' unlink %s",
+	      pathname, rc ? strerror(e) : "OK");
+	errno = e;
+
+	return rc;
+}
+
+void
+path_remove_tree(const char *pathname)
+{
+	pid_t pid;
+	const char *u;
+
+	u = path_skip_slash_dotslash(pathname);
+	assert(*u);
+
+	debug(dbg_eachfile, "%s '%s'", __func__, pathname);
+	if (!rmdir(pathname))
+		return; /* Deleted it OK, it was a directory. */
+	if (errno == ENOENT || errno == ELOOP)
+		return;
+	if (errno == ENOTDIR) {
+		/* Either it's a file, or one of the path components is. If
+		 * one of the path components is this will fail again ... */
+		if (secure_unlink(pathname) == 0)
+			return; /* OK, it was. */
+		if (errno == ENOTDIR)
+			return;
+	}
+	if (errno != ENOTEMPTY && errno != EEXIST) /* Huh? */
+		ohshite(_("unable to securely remove '%.255s'"), pathname);
+
+	pid = subproc_fork();
+	if (pid == 0) {
+		execlp(RM, "rm", "-rf", "--", pathname, NULL);
+		ohshite(_("unable to execute %s (%s)"),
+		        _("rm command for cleanup"), RM);
+	}
+	debug(dbg_eachfile, "%s running rm -rf '%s'", __func__, pathname);
+	subproc_reap(pid, _("rm command for cleanup"), 0);
+}

+ 8 - 0
lib/dpkg/path.h

@@ -21,6 +21,8 @@
 #ifndef LIBDPKG_PATH_H
 #define LIBDPKG_PATH_H
 
+#include <sys/stat.h>
+
 #include <stddef.h>
 
 #include <dpkg/macros.h>
@@ -40,6 +42,12 @@ char *path_quote_filename(char *dst, const char *src, size_t size);
 
 char *path_make_temp_template(const char *suffix);
 
+int secure_unlink_statted(const char *pathname, const struct stat *stab);
+int secure_unlink(const char *pathname);
+int secure_remove(const char *pathname);
+
+void path_remove_tree(const char *pathname);
+
 /** @} */
 
 DPKG_END_DECLS

+ 0 - 35
src/archives.c

@@ -567,41 +567,6 @@ void setupfnamevbs(const char *filename) {
         fnamevb.buf, fnametmpvb.buf, fnamenewvb.buf);
 }
 
-/**
- * Securely remove a pathname.
- *
- * This is a secure version of remove(3) using secure_unlink() instead of
- * unlink(2).
- *
- * @retval  0 On success.
- * @retval -1 On failure, just like unlink(2) & rmdir(2).
- */
-int
-secure_remove(const char *filename)
-{
-  int rc, e;
-
-  if (!rmdir(filename)) {
-    debug(dbg_eachfiledetail, "secure_remove '%s' rmdir OK", filename);
-    return 0;
-  }
-
-  if (errno != ENOTDIR) {
-    e= errno;
-    debug(dbg_eachfiledetail, "secure_remove '%s' rmdir %s", filename,
-          strerror(e));
-    errno= e; return -1;
-  }
-
-  rc = secure_unlink(filename);
-  e = errno;
-  debug(dbg_eachfiledetail, "secure_remove '%s' unlink %s",
-        filename, rc ? strerror(e) : "OK");
-  errno = e;
-
-  return rc;
-}
-
 struct fileinlist *addfiletolist(struct tarcontext *tc,
 				 struct filenamenode *namenode) {
   struct fileinlist *nifd;

+ 0 - 2
src/archives.h

@@ -68,8 +68,6 @@ void ok_prermdeconfigure(int argc, void **argv);
 
 void setupfnamevbs(const char *filename);
 
-int secure_remove(const char *filename);
-
 int tarobject(void *ctx, struct tar_entry *ti);
 int tarfileread(void *ud, char *buf, int len);
 void tar_deferred_extract(struct fileinlist *files, struct pkginfo *pkg);

+ 1 - 0
src/cleanup.c

@@ -38,6 +38,7 @@
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
 #include <dpkg/pkg.h>
+#include <dpkg/path.h>
 #include <dpkg/options.h>
 
 #include "filesdb.h"

+ 0 - 65
src/help.c

@@ -35,7 +35,6 @@
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
 #include <dpkg/path.h>
-#include <dpkg/subproc.h>
 
 #include "filesdb.h"
 #include "main.h"
@@ -334,70 +333,6 @@ void oldconffsetflags(const struct conffile *searchconff) {
   }
 }
 
-/*
- * If the pathname to remove is:
- *
- * 1. a sticky or set-id file, or
- * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
- *
- * we change its mode so that a malicious user cannot use it, even if it's
- * linked to another file.
- */
-int
-secure_unlink(const char *pathname)
-{
-  struct stat stab;
-
-  if (lstat(pathname,&stab)) return -1;
-
-  return secure_unlink_statted(pathname, &stab);
-}
-
-int
-secure_unlink_statted(const char *pathname, const struct stat *stab)
-{
-  if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
-      !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
-	S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
-    if (chmod(pathname, 0600))
-      return -1;
-  }
-  if (unlink(pathname)) return -1;
-  return 0;
-}
-
-void
-path_remove_tree(const char *pathname)
-{
-  pid_t pid;
-  const char *u;
-
-  u = path_skip_slash_dotslash(pathname);
-  assert(*u);
-
-  debug(dbg_eachfile, "%s '%s'", __func__, pathname);
-  if (!rmdir(pathname))
-    return; /* Deleted it OK, it was a directory. */
-  if (errno == ENOENT || errno == ELOOP) return;
-  if (errno == ENOTDIR) {
-    /* Either it's a file, or one of the path components is. If one
-     * of the path components is this will fail again ... */
-    if (secure_unlink(pathname) == 0)
-      return; /* OK, it was. */
-    if (errno == ENOTDIR) return;
-  }
-  if (errno != ENOTEMPTY && errno != EEXIST) { /* Huh? */
-    ohshite(_("unable to securely remove '%.255s'"), pathname);
-  }
-  pid = subproc_fork();
-  if (pid == 0) {
-    execlp(RM, "rm", "-rf", "--", pathname, NULL);
-    ohshite(_("unable to execute %s (%s)"), _("rm command for cleanup"), RM);
-  }
-  debug(dbg_eachfile, "%s running rm -rf '%s'", __func__, pathname);
-  subproc_reap(pid, _("rm command for cleanup"), 0);
-}
-
 void
 log_action(const char *action, struct pkginfo *pkg, struct pkgbin *pkgbin)
 {

+ 0 - 3
src/main.h

@@ -242,9 +242,6 @@ bool force_depends(struct deppossi *possi);
 bool force_conflicts(struct deppossi *possi);
 void conffile_mark_obsolete(struct pkginfo *pkg, struct filenamenode *namenode);
 void oldconffsetflags(const struct conffile *searchconff);
-void path_remove_tree(const char *pathname);
-int secure_unlink(const char *pathname);
-int secure_unlink_statted(const char *pathname, const struct stat *stab);
 void checkpath(void);
 
 struct filenamenode *namenodetouse(struct filenamenode *namenode,

+ 1 - 0
src/remove.c

@@ -38,6 +38,7 @@
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
 #include <dpkg/pkg.h>
+#include <dpkg/path.h>
 #include <dpkg/dir.h>
 #include <dpkg/options.h>
 #include <dpkg/triglib.h>