aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-06-16 15:58:07 -0700
committerUlrich Drepper <drepper@redhat.com>2009-06-16 15:58:07 -0700
commitf793b62438a3cfdbcc5ba453eebee1db3f315bea (patch)
treec0c8cf38a5c5293bfc05af20ab797e2496137158
parentfab8238de69de67637d21923b3ec1c26e4ce8450 (diff)
downloadglibc-f793b62438a3cfdbcc5ba453eebee1db3f315bea.tar
glibc-f793b62438a3cfdbcc5ba453eebee1db3f315bea.tar.gz
glibc-f793b62438a3cfdbcc5ba453eebee1db3f315bea.tar.bz2
glibc-f793b62438a3cfdbcc5ba453eebee1db3f315bea.zip
Extend pt_chown to drop privileges.
If libcap is available, use it to drop privileges in pt_chown before starting the work to change the permissions and ownership of the slave device.
-rw-r--r--ChangeLog4
-rw-r--r--login/Makefile7
-rw-r--r--login/programs/pt_chown.c45
-rw-r--r--sysdeps/generic/pty-private.h5
-rw-r--r--sysdeps/unix/grantpt.c5
5 files changed, 55 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 85ab3dab50..4d7f002a4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-06-16 Ulrich Drepper <drepper@redhat.com>
+
+ * login/Makefile: If necessary link pt_chown with -lcap.
+
2009-06-16 Jakub Jelinek <jakub@redhat.com>
* sysdeps/x86_64/memchr.S (memchr): Use unsigned instead of signed
diff --git a/login/Makefile b/login/Makefile
index b02d385b66..427c050a89 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1996-1998,2000-2002,2003,2007 Free Software Foundation, Inc.
+# Copyright (C) 1996-1998,2000-2003,2007, 2009 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -54,6 +54,11 @@ otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \
$(resolvobjdir)/libresolv.a $(common-objpfx)libc.a
endif
+ifeq (yes,$(have-libcap))
+libcap = -lcap
+endif
+LDLIBS-pt_chown = $(libcap)
+
# pt_chown needs to be setuid root.
$(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force)
$(make-target-directory)
diff --git a/login/programs/pt_chown.c b/login/programs/pt_chown.c
index 5167b29225..7e279a5f3b 100644
--- a/login/programs/pt_chown.c
+++ b/login/programs/pt_chown.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
+#ifdef HAVE_LIBCAP
+# include <sys/capability.h>
+# include <sys/prctl.h>
+#endif
#include "pty-private.h"
@@ -99,7 +103,7 @@ static int
do_pt_chown (void)
{
char *pty;
- struct stat st;
+ struct stat64 st;
struct group *p;
gid_t gid;
@@ -110,7 +114,7 @@ do_pt_chown (void)
/* Check that the returned slave pseudo terminal is a
character device. */
- if (stat (pty, &st) < 0 || !S_ISCHR(st.st_mode))
+ if (stat64 (pty, &st) < 0 || !S_ISCHR (st.st_mode))
return FAIL_EINVAL;
/* Get the group ID of the special `tty' group. */
@@ -136,16 +140,43 @@ int
main (int argc, char *argv[])
{
uid_t euid = geteuid ();
+ uid_t uid = getuid ();
int remaining;
- /* Normal invocation of this program is with no arguments and
- with privileges.
- FIXME: Should use capable (CAP_CHOWN|CAP_FOWNER). */
if (argc == 1 && euid == 0)
- return do_pt_chown ();
+ {
+#ifdef HAVE_LIBCAP
+ /* Drop privileges. */
+ if (uid != euid)
+ {
+ static const cap_value_t cap_list[] =
+ { CAP_CHOWN, CAP_FOWNER };
+# define ncap_list (sizeof (cap_list) / sizeof (cap_list[0]))
+ cap_t caps = cap_init ();
+ if (caps == NULL)
+ error (FAIL_ENOMEM, errno,
+ _("Failed to initialize drop of capabilities"));
+
+ /* There is no reason why these should not work. */
+ cap_set_flag (caps, CAP_PERMITTED, ncap_list, cap_list, CAP_SET);
+ cap_set_flag (caps, CAP_EFFECTIVE, ncap_list, cap_list, CAP_SET);
+
+ int res = cap_set_proc (caps);
+
+ cap_free (caps);
+
+ if (__builtin_expect (res != 0, 0))
+ error (FAIL_EXEC, errno, _("cap_set_proc failed"));
+ }
+#endif
+
+ /* Normal invocation of this program is with no arguments and
+ with privileges. */
+ return do_pt_chown ();
+ }
/* We aren't going to be using privileges, so drop them right now. */
- setuid (getuid ());
+ setuid (uid);
/* Set locale via LC_ALL. */
setlocale (LC_ALL, "");
diff --git a/sysdeps/generic/pty-private.h b/sysdeps/generic/pty-private.h
index d6ec2cee68..493f40551d 100644
--- a/sysdeps/generic/pty-private.h
+++ b/sysdeps/generic/pty-private.h
@@ -1,5 +1,5 @@
/* Internal defenitions and declarations for pseudo terminal functions.
- Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
@@ -39,7 +39,8 @@ enum /* failure modes */
FAIL_EBADF = 1,
FAIL_EINVAL,
FAIL_EACCES,
- FAIL_EXEC
+ FAIL_EXEC,
+ FAIL_ENOMEM
};
#endif /* pty-private.h */
diff --git a/sysdeps/unix/grantpt.c b/sysdeps/unix/grantpt.c
index f664b9eb1b..8c299e9147 100644
--- a/sysdeps/unix/grantpt.c
+++ b/sysdeps/unix/grantpt.c
@@ -202,7 +202,7 @@ grantpt (int fd)
if (!WIFEXITED (w))
__set_errno (ENOEXEC);
else
- switch (WEXITSTATUS(w))
+ switch (WEXITSTATUS (w))
{
case 0:
retval = 0;
@@ -219,6 +219,9 @@ grantpt (int fd)
case FAIL_EXEC:
__set_errno (ENOEXEC);
break;
+ case FAIL_ENOMEM:
+ __set_errno (ENOMEM);
+ break;
default:
assert(! "getpt: internal error: invalid exit code from pt_chown");