From: Sean Finney <sean...@debian.org>
Date: Sun, 11 Oct 2009 12:43:50 +0200

A small number of functions from help.c are required for outside-of-dpkg
functioning of the conffiledb routines. As we want to be able to have
functional unit tests as well as to use these routines in other cmdline
programs (such as a hypothetical dpkg-conffile utility), we need to move
these functions out of help.c which is otherwise hopelessly intertwined with
the main dpkg code.

Therefore, the following functions have been moved to a new util.c file:

 * void ensure_pathname_nonexisting(const char *pathname)
 * int secure_unlink(const char *pathname)
 * int secure_unlink_statted(const char *pathname, const struct stat *stab)

Doxygen documentation has been added to the functions in the process.

The Makefile.am automake template has also been updated to include this file
in dpkg_SOURCES and no further changes are required to dpkg source code.

[jn: rebased on current dpkg]

Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
---
Hi,

debug is now part of libdpkg so I left that one out.

help.c describes itself as "help.c - various helper routines", which
doesn't seem so far from util.c.  Do I understand correctly that the
main purpose is to make ensure_pathname_nonexisting et al usable as
a separate translation unit that doesn't depend on too much else?

In the long term it might be most intuitive to do something like what
1.16.0~160 (Move and generalize debug API from dpkg to libdpkg,
2011-02-04) does.

 src/Makefile.am |    3 +-
 src/help.c      |   61 --------------------------
 src/util.c      |  126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 62 deletions(-)
 create mode 100644 src/util.c

diff --git a/src/Makefile.am b/src/Makefile.am
index e29abf3..51e2b9f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,7 +44,8 @@ dpkg_SOURCES = \
        remove.c \
        select.c \
        trigproc.c \
-       update.c
+       update.c \
+       util.c
 
 dpkg_LDADD = \
        $(LDADD) \
diff --git a/src/help.c b/src/help.c
index 1be86e6..4ad8823 100644
--- a/src/help.c
+++ b/src/help.c
@@ -525,67 +525,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 ensure_pathname_nonexisting(const char *pathname) {
-  pid_t pid;
-  const char *u;
-
-  u = path_skip_slash_dotslash(pathname);
-  assert(*u);
-
-  debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",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,"ensure_pathname_nonexisting running rm -rf");
-  subproc_wait_check(pid, "rm cleanup", 0);
-}
 
 void log_action(const char *action, struct pkginfo *pkg) {
   log_message("%s %s %s %s", action, pkg->name,
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..3dd4fed
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,126 @@
+/*
+ * dpkg - main program for package management
+ * util.c - miscellaneous utility functions
+ *
+ * Copyright © 1995 Ian Jackson <i...@chiark.greenend.org.uk>
+ *
+ * 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,
+ * 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <config.h>
+#include <compat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "main.h"
+
+#include "dpkg/dpkg.h"
+#include "dpkg/i18n.h"
+#include "dpkg/path.h"
+#include "dpkg/subproc.h"
+
+/**
+ * Safely unlink a given pathname, with checks on file type and mode.
+ *
+ * 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.
+ *
+ * @param pathname the path to unlink
+ * @return 0 on success, -1 on error.
+ */
+int
+secure_unlink(const char *pathname)
+{
+       struct stat stab;
+
+       if (lstat(pathname, &stab))
+               return -1;
+
+       return secure_unlink_statted(pathname, &stab);
+}
+
+/**
+ * Safely unlink a given pathname, checking file type and mode against
+ * externally provided file type and mode information.
+ *
+ * See notes in secure_unlink.
+ *
+ * @param pathname the path to unlink.
+ * @param stab a struct stat containing information about the path.
+ * @return 0 on success, -1 on error.
+ */
+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;
+}
+
+/**
+ * Delete a pathname and anything that may be beneath it.
+ *
+ * This function is a generic catch-all delete utility, which
+ * will remove anything that may exist at the given pathname.  If
+ * The pathname is a nonempty directory, it will be recursively
+ * removed with a fork/exec of rm -rf.
+ *
+ * @param pathname the path to be removed.
+ */
+void
+ensure_pathname_nonexisting(const char *pathname)
+{
+       pid_t pid;
+       const char *u;
+
+       u = path_skip_slash_dotslash(pathname);
+       assert(*u);
+
+       debug(dbg_eachfile, "ensure_pathname_nonexisting `%s'", 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, "ensure_pathname_nonexisting running rm -rf");
+       subproc_wait_check(pid, "rm cleanup", 0);
+}
-- 
1.7.5.1


--
To UNSUBSCRIBE, email to debian-dpkg-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org
Archive: http://lists.debian.org/20110506074930.GA1040@elie

Reply via email to