Browse Source

Propagate --admindir to programs run from maintainer scripts

Always set DPKG_ADMINDIR from dpkg so that all subprocesses inherit
the variable and there's no possible security risk from a user process
setting the variable to write onto a user controlled area.

As usual, the order in which the admindir value is overridden is the
following: built-in default, environment variable and command line
option.

Closes: #97076

Suggested-by: Brendan O'Dea <bod@debian.org>
Guillem Jover 13 years ago
parent
commit
e63e1fa4a4

+ 0 - 2
TODO

@@ -99,8 +99,6 @@ TODO
    automatically.
    - Support for output format. (#214566)
 
- * Propagate --admindir to programs run from maintainer scritpts. (#97076)
-
  * Fix conflicting action -%c, when short is 0.
 
  * We should set our own obstack_alloc_failed_handler.

+ 2 - 0
debian/changelog

@@ -20,6 +20,8 @@ dpkg (1.16.0) UNRELEASED; urgency=low
     a program needed for dpkg correct operation.
   * Fix dpkg -GEO options on multiple versions of the same packages.
     Closes: #31141
+  * Propagate --admindir to programs run from maintainer scritpts.
+    Closes: #97076
 
   [ Raphaël Hertzog ]
   * Fail properly when debian/source/format is empty. Closes: #600854

+ 12 - 0
lib/dpkg/dbmodify.c

@@ -392,6 +392,18 @@ modstatdb_note_ifwrite(struct pkginfo *pkg)
     modstatdb_note(pkg);
 }
 
+const char *
+pkgadmindir_init(const char *default_dir)
+{
+  const char *env;
+
+  env = getenv("DPKG_ADMINDIR");
+  if (env)
+    return env;
+  else
+    return default_dir;
+}
+
 const char *
 pkgadmindir(void)
 {

+ 1 - 0
lib/dpkg/dpkg-db.h

@@ -224,6 +224,7 @@ void modstatdb_note_ifwrite(struct pkginfo *pkg);
 void modstatdb_checkpoint(void);
 void modstatdb_shutdown(void);
 
+const char *pkgadmindir_init(const char *default_dir);
 const char *pkgadmindir(void);
 const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile);
 

+ 4 - 0
man/dpkg-divert.8

@@ -111,6 +111,10 @@ dpkg-divert \-\-package wibble \-\-rename \-\-remove /usr/bin/example
 .
 .SH ENVIRONMENT
 .TP
+.B DPKG_ADMINDIR
+If set and the \fB\-\-admindir\fP option has not been specified, it will
+be used as the dpkg data directory.
+.TP
 .B DPKG_MAINTSCRIPT_PACKAGE
 If set and the \fI\-\-local\fP and \fI\-\-package\fP options have not been
 specified, \fBdpkg\-divert\fP will use it as the package name.

+ 4 - 0
man/dpkg-query.1

@@ -195,6 +195,10 @@ query, including no file or package being found (except for \-\-control\-path).
 .
 .SH ENVIRONMENT
 .TP
+.B DPKG_ADMINDIR
+If set and the \fB\-\-admindir\fP option has not been specified, it will
+be used as the dpkg data directory.
+.TP
 \fBCOLUMNS\fP
 This setting influences the output of the \fB\-\-list\fP option by changing
 the width of its output.

+ 6 - 0
man/dpkg-statoverride.8

@@ -66,6 +66,12 @@ exists.
 .B \-\-quiet
 Be less verbose about what we do.
 .
+.SH ENVIRONMENT
+.TP
+.B DPKG_ADMINDIR
+If set and the \fB\-\-admindir\fP option has not been specified, it will
+be used as the dpkg data directory.
+.
 .SH FILES
 .TP
 .I /var/lib/dpkg/statoverride

+ 6 - 0
man/dpkg-trigger.1

@@ -57,6 +57,12 @@ the trigger.
 .BR \-\-no\-act
 Just test, do not actually change anything.
 .
+.SH ENVIRONMENT
+.TP
+.B DPKG_ADMINDIR
+If set and the \fB\-\-admindir\fP option has not been specified, it will
+be used as the dpkg data directory.
+.
 .SH SEE ALSO
 .BR dpkg "(1), " deb-triggers "(5), " /usr/share/doc/dpkg-dev/triggers.txt.gz .
 

+ 6 - 0
man/update-alternatives.8

@@ -352,6 +352,12 @@ is doing.
 .B \-\-quiet
 Don't generate any comments unless errors occur.
 .
+.SH ENVIRONMENT
+.TP
+.B DPKG_ADMINDIR
+If set and the \fB\-\-admindir\fP option has not been specified, it will
+be used as the base administrative directory.
+.
 .SH FILES
 .TP
 .I /etc/alternatives/

+ 3 - 1
src/divertcmd.c

@@ -49,7 +49,7 @@
 const char thisname[] = "dpkg-divert";
 const char printforhelp[] = N_("Use --help for help about querying packages.");
 
-const char *admindir = ADMINDIR;
+const char *admindir;
 
 static bool opt_pkgname_match_any = true;
 static const char *opt_pkgname = NULL;
@@ -710,6 +710,8 @@ main(int argc, const char * const *argv)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	admindir = pkgadmindir_init(ADMINDIR);
+
 	standard_startup();
 	myopt(&argv, cmdinfos);
 

+ 4 - 9
src/main.c

@@ -568,15 +568,6 @@ void execbackend(const char *const *argv) {
   command_init(&cmd, cipaction->parg, NULL);
   command_add_arg(&cmd, cipaction->parg);
 
-  /* Special case: dpkg-query takes the --admindir option, and if dpkg
-   * itself was given a different admin directory, we need to pass it
-   * along to it. */
-  if (strcmp(cipaction->parg, DPKGQUERY) == 0 &&
-      strcmp(admindir, ADMINDIR) != 0) {
-    m_asprintf(&arg, "--admindir=%s", admindir);
-    command_add_arg(&cmd, arg);
-  }
-
   m_asprintf(&arg, "--%s", cipaction->olong);
   command_add_arg(&cmd, arg);
 
@@ -699,6 +690,10 @@ int main(int argc, const char *const *argv) {
 
   if (!cipaction) badusage(_("need an action option"));
 
+  /* Always set environment, to avoid possible security risks. */
+  if (setenv("DPKG_ADMINDIR", admindir, 1) < 0)
+    ohshite(_("unable to setenv for subprocesses"));
+
   if (!f_triggers)
     f_triggers = (cipaction->arg == act_triggers && *argv) ? -1 : 1;
 

+ 3 - 1
src/querycmd.c

@@ -695,7 +695,7 @@ usage(const struct cmdinfo *ci, const char *value)
 const char thisname[]= "dpkg-query";
 const char printforhelp[]= N_("Use --help for help about querying packages.");
 
-const char *admindir= ADMINDIR;
+const char *admindir;
 
 /* This table has both the action entries in it and the normal options.
  * The action entries are made with the ACTION macro, as they all
@@ -724,6 +724,8 @@ int main(int argc, const char *const *argv) {
   bindtextdomain(PACKAGE, LOCALEDIR);
   textdomain(PACKAGE);
 
+  admindir = pkgadmindir_init(ADMINDIR);
+
   standard_startup();
   myopt(&argv, cmdinfos);
 

+ 3 - 1
src/statcmd.c

@@ -99,7 +99,7 @@ usage(const struct cmdinfo *cip, const char *value)
 	exit(0);
 }
 
-const char *admindir = ADMINDIR;
+const char *admindir;
 
 static int opt_verbose = 1;
 static int opt_force = 0;
@@ -369,6 +369,8 @@ main(int argc, const char *const *argv)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	admindir = pkgadmindir_init(ADMINDIR);
+
 	standard_startup();
 	myopt(&argv, cmdinfos);
 

+ 3 - 1
src/trigcmd.c

@@ -94,7 +94,7 @@ usage(const struct cmdinfo *ci, const char *value)
 	exit(0);
 }
 
-static const char *admindir = ADMINDIR;
+static const char *admindir;
 static int f_noact, f_check;
 
 static const char *bypackage, *activate;
@@ -188,6 +188,8 @@ main(int argc, const char *const *argv)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	admindir = pkgadmindir_init(ADMINDIR);
+
 	standard_startup();
 	myopt(&argv, cmdinfos);
 

+ 20 - 1
utils/update-alternatives.c

@@ -51,7 +51,7 @@
 #define PROGNAME "update-alternatives"
 
 static const char *altdir = SYSCONFDIR "/alternatives";
-static const char *admdir = ADMINDIR "/alternatives";
+static const char *admdir;
 
 static const char *prog_path = "update-alternatives";
 
@@ -328,6 +328,23 @@ set_action(const char *new_action)
     action = new_action;
 }
 
+static const char *
+admindir_init(void)
+{
+	const char *basedir, *dpkg_basedir;
+	char *admindir;
+
+	dpkg_basedir = getenv("DPKG_ADMINDIR");
+	if (dpkg_basedir)
+		basedir = dpkg_basedir;
+	else
+		basedir = ADMINDIR;
+
+	xasprintf(&admindir, "%s/%s", basedir, "alternatives");
+
+	return admindir;
+}
+
 static FILE *fh_log = NULL;
 
 static void DPKG_ATTR_PRINTF(1)
@@ -2014,6 +2031,8 @@ main(int argc, char **argv)
 	bindtextdomain("dpkg", LOCALEDIR);
 	textdomain("dpkg");
 
+	admdir = admindir_init();
+
 	if (setvbuf(stdout, NULL, _IONBF, 0))
 		error("setvbuf failed: %s", strerror(errno));