summaryrefslogtreecommitdiff
path: root/src/manconv_client.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2011-01-04 11:11:12 +0000
committerColin Watson <cjwatson@debian.org>2011-01-04 11:11:12 +0000
commit3c3c7ee6965eee3f121e2a762dd1c55b54430721 (patch)
treeef45179c5800382161b1898689779563bf748f69 /src/manconv_client.c
parent0f4620d4ac262733db798f986aece1ef03796a12 (diff)
* lib/security.c (running_setuid): New function.
* lib/security.h (running_setuid): Add prototype. * src/manconv_client.c (manconv_stdin): If running setuid, exec manconv as an external process, since iconv_open is not guaranteed to work correctly in setuid processes. * configure.ac: Require libpipeline >= 1.1.0. * docs/INSTALL.quick: Document increased version requirement. * NEWS: Document this.
Diffstat (limited to 'src/manconv_client.c')
-rw-r--r--src/manconv_client.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/manconv_client.c b/src/manconv_client.c
index 7533b14c..b8e7fd8d 100644
--- a/src/manconv_client.c
+++ b/src/manconv_client.c
@@ -33,6 +33,11 @@
#include "pipeline.h"
#include "decompress.h"
+#ifdef SECURE_MAN_UID
+# include "idpriv.h"
+# include "security.h"
+#endif /* SECURE_MAN_UID */
+
#include "manconv.h"
#include "manconv_client.h"
@@ -44,8 +49,44 @@ struct manconv_codes {
static void manconv_stdin (void *data)
{
struct manconv_codes *codes = data;
- pipeline *p = decompress_fdopen (dup (STDIN_FILENO));
+ pipeline *p;
+
+#ifdef SECURE_MAN_UID
+ /* iconv_open may not work correctly in setuid processes; in GNU
+ * libc, gconv modules may be linked against other gconv modules and
+ * rely on RPATH $ORIGIN to load those modules from the correct
+ * path, but $ORIGIN is disabled in setuid processes. It is
+ * impossible to reset libc's idea of setuidness without creating a
+ * whole new process image. Therefore, if the calling process is
+ * setuid, we must drop privileges and execute manconv.
+ *
+ * If dropping privileges fails, fall through to the in-process
+ * code, as in some situations it may actually manage to work.
+ */
+ if (running_setuid () && !idpriv_drop ()) {
+ char **from_code;
+ char *sources = NULL;
+ pipecmd *cmd;
+
+ for (from_code = codes->from; *from_code; ++from_code) {
+ sources = appendstr (sources, *from_code, NULL);
+ if (*(from_code + 1))
+ sources = appendstr (sources, ":", NULL);
+ }
+
+ cmd = pipecmd_new_args (MANCONV, "-f", sources,
+ "-t", codes->to, NULL);
+ free (sources);
+
+ if (quiet >= 2)
+ pipecmd_arg (cmd, "-q");
+
+ pipecmd_exec (cmd);
+ /* never returns */
+ }
+#endif /* SECURE_MAN_UID */
+ p = decompress_fdopen (dup (STDIN_FILENO));
pipeline_start (p);
manconv (p, codes->from, codes->to);
pipeline_wait (p);