diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | login/Makefile | 7 | ||||
-rw-r--r-- | login/programs/pt_chown.c | 45 | ||||
-rw-r--r-- | sysdeps/generic/pty-private.h | 5 | ||||
-rw-r--r-- | sysdeps/unix/grantpt.c | 5 |
5 files changed, 55 insertions, 11 deletions
@@ -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 b02d385..427c050 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 5167b29..7e279a5 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 d6ec2ce..493f405 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 f664b9e..8c299e9 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"); |