SHA256
1
0
forked from pool/coreutils
coreutils/coreutils-6.8-su.patch
Philipp Thomas d58c8ecf79 - Update to 8.5:
Bug fixes
  * cp and mv once again support preserving extended attributes.
  * cp now preserves "capabilities" when also preserving file ownership.7
  * ls --color once again honors the 'NORMAL' dircolors directive.
    [bug introduced in coreutils-6.11]
  * sort -M now handles abbreviated months that are aligned using
    blanks in the locale database.  Also locales with 8 bit characters
    are handled correctly, including multi byte locales with the caveat
    that multi byte characters are matched case sensitively.
  * sort again handles obsolescent key formats (+POS -POS) correctly. 
    Previously if -POS was specified, 1 field too many was used in the
    sort. [bug introduced in coreutils-7.2]
  New features
  * join now accepts the --header option, to treat the first line of
    each file as a header line to be joined and printed
    unconditionally.
  * timeout now accepts the --kill-after option which sends a kill
    signal to the monitored command if it's still running the specified
    duration after the initial signal was sent.
  * who: the "+/-" --mesg (-T) indicator of whether a user/tty is
    accepting messages could be incorrectly listed as "+", when in
    fact, the user was not accepting messages (mesg no).  Before, who
    would examine only the permission bits, and not consider the group
    of the TTY device file.  Thus, if a login tty's group would change
    somehow e.g., to "root", that would make it unwritable (via
    write(1)) by normal users, in spite of whatever the permission bits
    might imply.  Now, when configured using the
    --with-tty-group[=NAME] option, who also compares the group of the
    TTY device with NAME (or "tty" if no group name is specified).
  Changes in behavior
  * ls --color no longer emits the final 3-byte color-resetting escape
    sequence when it would be a no-op.
  * join -t '' no longer emits an error and instead operates on each
    line as a whole (even if they contain NUL characters).
  For other changes since 7.1 see NEWS.
- Split-up coreutils-%%{version}.diff as far as possible.
- Prefix all patches with coreutils-.
- All patches have the .patch suffix.
- Use the i18n patch from Archlinux as it fixes at least one test
  suite failure.

OBS-URL: https://build.opensuse.org/package/show/Base:System/coreutils?expand=0&rev=9
2010-05-07 15:54:35 +00:00

1033 lines
28 KiB
Diff

Add pam support in su
Index: Makefile.in
===================================================================
--- Makefile.in.orig 2010-04-23 17:58:41.000000000 +0200
+++ Makefile.in 2010-05-06 19:37:44.784359208 +0200
@@ -961,6 +961,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
Index: configure
===================================================================
--- configure.orig 2010-05-06 19:37:44.688359301 +0200
+++ configure 2010-05-06 19:37:44.816359169 +0200
@@ -631,6 +631,7 @@ OPTIONAL_BIN_PROGS
INSTALL_SU
LIB_GMP
LIB_CRYPT
+PAM_LIBS
GNULIB_WARN_CFLAGS
WERROR_CFLAGS
SEQ_LIBM
@@ -1501,6 +1502,7 @@ enable_xattr
enable_libcap
with_tty_group
enable_gcc_warnings
+enable_pam
with_gmp
enable_install_program
enable_no_install_program
@@ -2152,6 +2154,7 @@ Optional Features:
--disable-xattr do not support extended attributes
--disable-libcap disable libcap support
--enable-gcc-warnings turn on lots of GCC warnings (for developers)
+ --disable-pam Disable PAM support in su (default=auto)
--enable-install-program=PROG_LIST
install the programs in PROG_LIST (comma-separated,
default: none)
@@ -51989,6 +51992,111 @@ $as_echo "#define HAVE_WORKING_FORK 1" >
fi
+# Check whether --enable-pam was given.
+if test "${enable_pam+set}" = set; then
+ enableval=$enable_pam;
+else
+ enable_pam=yes
+fi
+
+if test "x$enable_pam" != xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5
+$as_echo_n "checking for pam_start in -lpam... " >&6; }
+if test "${ac_cv_lib_pam_pam_start+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pam_start ();
+int
+main ()
+{
+return pam_start ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then
+ ac_cv_lib_pam_pam_start=yes
+else
+ ac_cv_lib_pam_pam_start=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_start" >&5
+$as_echo "$ac_cv_lib_pam_pam_start" >&6; }
+if test "x$ac_cv_lib_pam_pam_start" = x""yes; then
+ enable_pam=yes
+else
+ enable_pam=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for misc_conv in -lpam_misc" >&5
+$as_echo_n "checking for misc_conv in -lpam_misc... " >&6; }
+if test "${ac_cv_lib_pam_misc_misc_conv+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam_misc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char misc_conv ();
+int
+main ()
+{
+return misc_conv ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then
+ ac_cv_lib_pam_misc_misc_conv=yes
+else
+ ac_cv_lib_pam_misc_misc_conv=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_misc_misc_conv" >&5
+$as_echo "$ac_cv_lib_pam_misc_misc_conv" >&6; }
+if test "x$ac_cv_lib_pam_misc_misc_conv" = x""yes; then
+ :
+else
+ enable_pam=no
+fi
+
+ if test "x$enable_pam" != xno; then
+
+$as_echo "#define USE_PAM 1" >>confdefs.h
+
+ PAM_LIBS="-lpam -lpam_misc"
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable PAM support in su" >&5
+$as_echo_n "checking whether to enable PAM support in su... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pam" >&5
+$as_echo "$enable_pam" >&6; }
+
optional_bin_progs=
for ac_func in chroot
do :
Index: configure.ac
===================================================================
--- configure.ac.orig 2010-03-13 16:14:09.000000000 +0100
+++ configure.ac 2010-05-06 19:37:44.843292013 +0200
@@ -128,6 +128,20 @@ fi
AC_FUNC_FORK
+AC_ARG_ENABLE(pam, AS_HELP_STRING([--disable-pam],
+ [Enable PAM support in su (default=auto)]), , [enable_pam=yes])
+if test "x$enable_pam" != xno; then
+ AC_CHECK_LIB([pam], [pam_start], [enable_pam=yes], [enable_pam=no])
+ AC_CHECK_LIB([pam_misc], [misc_conv], [:], [enable_pam=no])
+ if test "x$enable_pam" != xno; then
+ AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
+ PAM_LIBS="-lpam -lpam_misc"
+ AC_SUBST(PAM_LIBS)
+ fi
+fi
+AC_MSG_CHECKING([whether to enable PAM support in su])
+AC_MSG_RESULT([$enable_pam])
+
optional_bin_progs=
AC_CHECK_FUNCS([chroot],
gl_ADD_PROG([optional_bin_progs], [chroot]))
Index: doc/Makefile.in
===================================================================
--- doc/Makefile.in.orig 2010-04-23 17:58:37.000000000 +0200
+++ doc/Makefile.in 2010-05-06 19:37:44.868359246 +0200
@@ -957,6 +957,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
Index: gnulib-tests/Makefile.in
===================================================================
--- gnulib-tests/Makefile.in.orig 2010-04-23 18:00:33.000000000 +0200
+++ gnulib-tests/Makefile.in 2010-05-06 19:37:44.871374260 +0200
@@ -2191,6 +2191,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
Index: lib/Makefile.in
===================================================================
--- lib/Makefile.in.orig 2010-04-23 17:58:38.000000000 +0200
+++ lib/Makefile.in 2010-05-06 19:37:59.594863753 +0200
@@ -1006,6 +1006,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
Index: man/Makefile.in
===================================================================
--- man/Makefile.in.orig 2010-05-06 19:37:44.618920753 +0200
+++ man/Makefile.in 2010-05-06 19:37:44.934868934 +0200
@@ -926,6 +926,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
Index: src/Makefile.am
===================================================================
--- src/Makefile.am.orig 2010-04-23 15:44:14.000000000 +0200
+++ src/Makefile.am 2010-05-06 19:37:59.594863753 +0200
@@ -364,7 +364,8 @@ factor_LDADD += $(LIB_GMP)
uptime_LDADD += $(GETLOADAVG_LIBS)
# for crypt
-su_LDADD += $(LIB_CRYPT)
+su_SOURCES = su.c getdef.c
+su_LDADD = $(LDADD) $(LIB_CRYPT) $(PAM_LIBS)
# for various ACL functions
copy_LDADD += $(LIB_ACL)
Index: src/Makefile.in
===================================================================
--- src/Makefile.in.orig 2010-04-23 18:35:11.000000000 +0200
+++ src/Makefile.in 2010-05-06 19:37:59.594863753 +0200
@@ -553,9 +553,10 @@ stdbuf_DEPENDENCIES = $(am__DEPENDENCIES
stty_SOURCES = stty.c
stty_OBJECTS = stty.$(OBJEXT)
stty_DEPENDENCIES = $(am__DEPENDENCIES_2)
-su_SOURCES = su.c
-su_OBJECTS = su.$(OBJEXT)
-su_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+am_su_OBJECTS = su.$(OBJEXT) getdef.$(OBJEXT)
+su_OBJECTS = $(am_su_OBJECTS)
+su_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
sum_SOURCES = sum.c
sum_OBJECTS = sum.$(OBJEXT)
sum_DEPENDENCIES = $(am__DEPENDENCIES_2)
@@ -665,8 +666,8 @@ SOURCES = $(nodist_libver_a_SOURCES) $(_
$(rmdir_SOURCES) runcon.c seq.c setuidgid.c $(sha1sum_SOURCES) \
$(sha224sum_SOURCES) $(sha256sum_SOURCES) $(sha384sum_SOURCES) \
$(sha512sum_SOURCES) shred.c shuf.c sleep.c sort.c split.c \
- stat.c stdbuf.c stty.c su.c sum.c sync.c tac.c tail.c tee.c \
- test.c $(timeout_SOURCES) touch.c tr.c true.c truncate.c \
+ stat.c stdbuf.c stty.c $(su_SOURCES) sum.c sync.c tac.c tail.c \
+ tee.c test.c $(timeout_SOURCES) touch.c tr.c true.c truncate.c \
tsort.c tty.c $(uname_SOURCES) unexpand.c uniq.c unlink.c \
uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c
DIST_SOURCES = $(__SOURCES) $(arch_SOURCES) base64.c basename.c cat.c \
@@ -683,7 +684,7 @@ DIST_SOURCES = $(__SOURCES) $(arch_SOURC
$(rm_SOURCES) $(rmdir_SOURCES) runcon.c seq.c setuidgid.c \
$(sha1sum_SOURCES) $(sha224sum_SOURCES) $(sha256sum_SOURCES) \
$(sha384sum_SOURCES) $(sha512sum_SOURCES) shred.c shuf.c \
- sleep.c sort.c split.c stat.c stdbuf.c stty.c su.c sum.c \
+ sleep.c sort.c split.c stat.c stdbuf.c stty.c $(su_SOURCES) sum.c \
sync.c tac.c tail.c tee.c test.c $(timeout_SOURCES) touch.c \
tr.c true.c truncate.c tsort.c tty.c $(uname_SOURCES) \
unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) \
@@ -1338,6 +1339,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@
@@ -1743,7 +1745,8 @@ stdbuf_LDADD = $(LDADD) $(LIBICONV)
stty_LDADD = $(LDADD)
# for crypt
-su_LDADD = $(LDADD) $(LIB_CRYPT)
+su_SOURCES = su.c getdef.c
+su_LDADD = $(LDADD) $(LIB_CRYPT) $(PAM_LIBS)
sum_LDADD = $(LDADD)
sync_LDADD = $(LDADD)
tac_LDADD = $(LDADD) $(LIB_GETHRXTIME)
@@ -2386,6 +2389,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/false.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fold.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdef.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getlimits.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ginstall-copy.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ginstall-cp-hash.Po@am__quote@
Index: src/getdef.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/getdef.c 2010-05-06 19:37:45.014990147 +0200
@@ -0,0 +1,259 @@
+/* Copyright (C) 2003, 2004, 2005 Thorsten Kukuk
+ Author: Thorsten Kukuk <kukuk@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program 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 this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "getdef.h"
+
+struct item {
+ char *name; /* Name of the option. */
+ char *value; /* Value of the option. */
+ struct item *next; /* Pointer to next option. */
+};
+
+static struct item *list = NULL;
+
+void
+free_getdef_data (void)
+{
+ struct item *ptr;
+
+ ptr = list;
+ while (ptr != NULL)
+ {
+ struct item *tmp;
+ tmp = ptr->next;
+ free (ptr->name);
+ free (ptr->value);
+ free (ptr);
+ ptr = tmp;
+ }
+
+ list = NULL;
+}
+
+/* Add a new entry to the list. */
+static void
+store (const char *name, const char *value)
+{
+ struct item *new = malloc (sizeof (struct item));
+
+ if (new == NULL)
+ abort ();
+
+ if (name == NULL)
+ abort ();
+
+ new->name = strdup (name);
+ new->value = strdup (value ?: "");
+ new->next = list;
+ list = new;
+}
+
+/* Search a special entry in the list and return the value. */
+static const char *
+search (const char *name)
+{
+ struct item *ptr;
+
+ ptr = list;
+ while (ptr != NULL)
+ {
+ if (strcasecmp (name, ptr->name) == 0)
+ return ptr->value;
+ ptr = ptr->next;
+ }
+
+ return NULL;
+}
+
+/* Load the login.defs file (/etc/login.defs). */
+static void
+load_defaults_internal (const char *filename)
+{
+ FILE *fp;
+ char *buf = NULL;
+ size_t buflen = 0;
+
+ fp = fopen (filename, "r");
+ if (NULL == fp)
+ return;
+
+ while (!feof (fp))
+ {
+ char *tmp, *cp;
+#if defined(HAVE_GETLINE)
+ ssize_t n = getline (&buf, &buflen, fp);
+#elif defined (HAVE_GETDELIM)
+ ssize_t n = getdelim (&buf, &buflen, '\n', fp);
+#else
+ ssize_t n;
+
+ if (buf == NULL)
+ {
+ buflen = 8096;
+ buf = malloc (buflen);
+ }
+ buf[0] = '\0';
+ fgets (buf, buflen - 1, fp);
+ if (buf != NULL)
+ n = strlen (buf);
+ else
+ n = 0;
+#endif /* HAVE_GETLINE / HAVE_GETDELIM */
+ cp = buf;
+
+ if (n < 1)
+ break;
+
+ tmp = strchr (cp, '#'); /* remove comments */
+ if (tmp)
+ *tmp = '\0';
+ while (isspace ((unsigned char) *cp)) /* remove spaces and tabs */
+ ++cp;
+ if (*cp == '\0') /* ignore empty lines */
+ continue;
+
+ if (cp[strlen (cp) - 1] == '\n')
+ cp[strlen (cp) - 1] = '\0';
+
+ tmp = strsep (&cp, " \t=");
+ if (cp != NULL)
+ while (isspace ((unsigned char) *cp) || *cp == '=')
+ ++cp;
+
+ store (tmp, cp);
+ }
+ fclose (fp);
+
+ if (buf)
+ free (buf);
+}
+
+static void
+load_defaults (void)
+{
+ load_defaults_internal ("/etc/default/su");
+ load_defaults_internal ("/etc/login.defs");
+}
+
+int
+getdef_bool (const char *name, int dflt)
+{
+ const char *val;
+
+ if (list == NULL)
+ load_defaults ();
+
+ val = search (name);
+
+ if (val == NULL)
+ return dflt;
+
+ return (strcasecmp (val, "yes") == 0);
+}
+
+long
+getdef_num (const char *name, long dflt)
+{
+ const char *val;
+ char *cp;
+ long retval;
+
+ if (list == NULL)
+ load_defaults ();
+
+ val = search (name);
+
+ if (val == NULL)
+ return dflt;
+
+ errno = 0;
+ retval = strtol (val, &cp, 0);
+ if (*cp != '\0'
+ || ((retval == LONG_MAX || retval == LONG_MIN) && errno == ERANGE))
+ {
+ fprintf (stderr,
+ "%s contains invalid numerical value: %s!\n",
+ name, val);
+ retval = dflt;
+ }
+ return retval;
+}
+
+unsigned long
+getdef_unum (const char *name, unsigned long dflt)
+{
+ const char *val;
+ char *cp;
+ unsigned long retval;
+
+ if (list == NULL)
+ load_defaults ();
+
+ val = search (name);
+
+ if (val == NULL)
+ return dflt;
+
+ errno = 0;
+ retval = strtoul (val, &cp, 0);
+ if (*cp != '\0' || (retval == ULONG_MAX && errno == ERANGE))
+ {
+ fprintf (stderr,
+ "%s contains invalid numerical value: %s!\n",
+ name, val);
+ retval = dflt;
+ }
+ return retval;
+}
+
+const char *
+getdef_str (const char *name, const char *dflt)
+{
+ const char *retval;
+
+ if (list == NULL)
+ load_defaults ();
+
+ retval = search (name);
+
+ return retval ?: dflt;
+}
+
+#if defined(TEST)
+
+int
+main ()
+{
+ printf ("CYPT=%s\n", getdef_str ("cRypt", "no"));
+ printf ("LOG_UNKFAIL_ENAB=%s\n", getdef_str ("log_unkfail_enab",""));
+ printf ("DOESNOTEXIST=%s\n", getdef_str ("DOESNOTEXIST","yes"));
+ return 0;
+}
+
+#endif
Index: src/getdef.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/getdef.h 2010-05-06 19:37:45.054863903 +0200
@@ -0,0 +1,29 @@
+/* Copyright (C) 2003, 2005 Thorsten Kukuk
+ Author: Thorsten Kukuk <kukuk@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program 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 this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _GETDEF_H_
+
+#define _GETDEF_H_ 1
+
+extern int getdef_bool (const char *name, int dflt);
+extern long getdef_num (const char *name, long dflt);
+extern unsigned long getdef_unum (const char *name, unsigned long dflt);
+extern const char *getdef_str (const char *name, const char *dflt);
+
+/* Free all data allocated by getdef_* calls before. */
+extern void free_getdef_data (void);
+
+#endif /* _GETDEF_H_ */
Index: src/su.c
===================================================================
--- src/su.c.orig 2010-01-01 14:06:47.000000000 +0100
+++ src/su.c 2010-05-06 19:37:59.538860383 +0200
@@ -37,6 +37,16 @@
restricts who can su to UID 0 accounts. RMS considers that to
be fascist.
+#ifdef USE_PAM
+
+ Actually, with PAM, su has nothing to do with whether or not a
+ wheel group is enforced by su. RMS tries to restrict your access
+ to a su which implements the wheel group, but PAM considers that
+ to be fascist, and gives the user/sysadmin the opportunity to
+ enforce a wheel group by proper editing of /etc/pam.d/su
+
+#endif
+
Compile-time options:
-DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
-DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
@@ -52,12 +62,22 @@
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/fsuid.h>
+#endif
#include "system.h"
#include "getpass.h"
#if HAVE_SYSLOG_H && HAVE_SYSLOG
# include <syslog.h>
+# define SYSLOG_SUCCESS 1
+# define SYSLOG_FAILURE 1
+# define SYSLOG_NON_ROOT 1
#else
# undef SYSLOG_SUCCESS
# undef SYSLOG_FAILURE
@@ -91,19 +111,13 @@
# include <paths.h>
#endif
+#include "getdef.h"
+
/* The default PATH for simulated logins to non-superuser accounts. */
-#ifdef _PATH_DEFPATH
-# define DEFAULT_LOGIN_PATH _PATH_DEFPATH
-#else
-# define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin"
-#endif
+#define DEFAULT_LOGIN_PATH "/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin"
/* The default PATH for simulated logins to superuser accounts. */
-#ifdef _PATH_DEFPATH_ROOT
-# define DEFAULT_ROOT_LOGIN_PATH _PATH_DEFPATH_ROOT
-#else
-# define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc"
-#endif
+#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin:/usr/X11R6/bin"
/* The shell to run if none is given in the user's passwd entry. */
#define DEFAULT_SHELL "/bin/sh"
@@ -111,8 +125,9 @@
/* The user to become if none is specified. */
#define DEFAULT_USER "root"
+#ifndef USE_PAM
char *crypt (char const *key, char const *salt);
-
+#endif
static void run_shell (char const *, char const *, char **, size_t)
ATTRIBUTE_NORETURN;
@@ -125,6 +140,13 @@ static bool simulate_login;
/* If true, change some environment vars to indicate the user su'd to. */
static bool change_environment;
+#ifdef USE_PAM
+static bool _pam_session_opened;
+static bool _pam_cred_established;
+static void export_pamenv (void);
+static void create_watching_parent (void);
+#endif
+
static struct option const longopts[] =
{
{"command", required_argument, NULL, 'c'},
@@ -200,7 +222,162 @@ log_su (struct passwd const *pw, bool su
}
#endif
+#ifdef USE_PAM
+#define PAM_SERVICE_NAME PROGRAM_NAME
+#define PAM_SERVICE_NAME_L PROGRAM_NAME "-l"
+static bool caught_signal = false;
+static pam_handle_t *pamh = NULL;
+static int retval;
+static struct pam_conv conv =
+{
+ misc_conv,
+ NULL
+};
+
+#define PAM_BAIL_P(a) \
+ if (retval) \
+ { \
+ pam_end (pamh, retval); \
+ a; \
+ }
+
+static void
+cleanup_pam (int retcode)
+{
+ if (_pam_session_opened)
+ pam_close_session (pamh, 0);
+
+ if (_pam_cred_established)
+ pam_setcred (pamh, PAM_DELETE_CRED | PAM_SILENT);
+
+ pam_end(pamh, retcode);
+}
+
+/* Signal handler for parent process. */
+static void
+su_catch_sig (int sig)
+{
+ caught_signal = true;
+}
+
+/* Export env variables declared by PAM modules. */
+static void
+export_pamenv (void)
+{
+ char **env;
+
+ /* This is a copy but don't care to free as we exec later anyways. */
+ env = pam_getenvlist (pamh);
+ while (env && *env)
+ {
+ if (putenv (*env) != 0)
+ xalloc_die ();
+ env++;
+ }
+}
+
+static void
+create_watching_parent (void)
+{
+ pid_t child;
+ sigset_t ourset;
+ int status;
+
+ retval = pam_open_session (pamh, 0);
+ if (retval != PAM_SUCCESS)
+ {
+ cleanup_pam (retval);
+ error (EXIT_FAILURE, 0, _("cannot not open session: %s"),
+ pam_strerror (pamh, retval));
+ }
+ else
+ _pam_session_opened = 1;
+
+ child = fork ();
+ if (child == (pid_t) -1)
+ {
+ cleanup_pam (PAM_ABORT);
+ error (EXIT_FAILURE, errno, _("cannot create child process"));
+ }
+
+ /* the child proceeds to run the shell */
+ if (child == 0)
+ return;
+
+ /* In the parent watch the child. */
+
+ /* su without pam support does not have a helper that keeps
+ sitting on any directory so let's go to /. */
+ if (chdir ("/") != 0)
+ error (0, errno, _("warning: cannot change directory to %s"), "/");
+
+ sigfillset (&ourset);
+ if (sigprocmask (SIG_BLOCK, &ourset, NULL))
+ {
+ error (0, errno, _("cannot block signals"));
+ caught_signal = true;
+ }
+ if (!caught_signal)
+ {
+ struct sigaction action;
+ action.sa_handler = su_catch_sig;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+ sigemptyset (&ourset);
+ if (sigaddset (&ourset, SIGTERM)
+ || sigaddset (&ourset, SIGALRM)
+ || sigaction (SIGTERM, &action, NULL)
+ || sigprocmask (SIG_UNBLOCK, &ourset, NULL))
+ {
+ error (0, errno, _("cannot set signal handler"));
+ caught_signal = true;
+ }
+ }
+ if (!caught_signal)
+ {
+ for (;;)
+ {
+ pid_t pid;
+
+ pid = waitpid (child, &status, WUNTRACED);
+
+ if (WIFSTOPPED (status))
+ {
+ kill (getpid (), SIGSTOP);
+ /* once we get here, we must have resumed */
+ kill (pid, SIGCONT);
+ }
+ else
+ break;
+ }
+ if (WIFSIGNALED (status))
+ status = WTERMSIG (status) + 128;
+ else
+ status = WEXITSTATUS (status);
+ }
+ else
+ status = 1;
+
+ if (caught_signal)
+ {
+ fprintf (stderr, _("\nSession terminated, killing shell..."));
+ kill (child, SIGTERM);
+ }
+
+ cleanup_pam (PAM_SUCCESS);
+
+ if (caught_signal)
+ {
+ sleep (2);
+ kill (child, SIGKILL);
+ fprintf (stderr, _(" ...killed.\n"));
+ }
+ exit (status);
+}
+#endif
+
/* Ask the user for a password.
+ If PAM is in use, let PAM ask for the password if necessary.
Return true if the user gives the correct password for entry PW,
false if not. Return true without asking for a password if run by UID 0
or if PW has an empty password. */
@@ -208,10 +385,52 @@ log_su (struct passwd const *pw, bool su
static bool
correct_password (const struct passwd *pw)
{
+#ifdef USE_PAM
+ const struct passwd *lpw;
+ const char *cp;
+
+ retval = pam_start (simulate_login ? PAM_SERVICE_NAME_L : PAM_SERVICE_NAME,
+ pw->pw_name, &conv, &pamh);
+ PAM_BAIL_P (return false);
+
+ if (isatty (0) && (cp = ttyname (0)) != NULL)
+ {
+ const char *tty;
+
+ if (strncmp (cp, "/dev/", 5) == 0)
+ tty = cp + 5;
+ else
+ tty = cp;
+ retval = pam_set_item (pamh, PAM_TTY, tty);
+ PAM_BAIL_P (return false);
+ }
+#if 0 /* Manpage discourages use of getlogin. */
+ cp = getlogin ();
+ if (!(cp && *cp && (lpw = getpwnam (cp)) != NULL && lpw->pw_uid == getuid ()))
+#endif
+ lpw = getpwuid (getuid ());
+ if (lpw && lpw->pw_name)
+ {
+ retval = pam_set_item (pamh, PAM_RUSER, (const void *) lpw->pw_name);
+ PAM_BAIL_P (return false);
+ }
+ retval = pam_authenticate (pamh, 0);
+ PAM_BAIL_P (return false);
+ retval = pam_acct_mgmt (pamh, 0);
+ if (retval == PAM_NEW_AUTHTOK_REQD)
+ {
+ /* Password has expired. Offer option to change it. */
+ retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ PAM_BAIL_P (return false);
+ }
+ PAM_BAIL_P (return false);
+ /* Must be authenticated if this point was reached. */
+ return true;
+#else /* !USE_PAM */
char *unencrypted, *encrypted, *correct;
#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
/* Shadow passwd stuff for SVR3 and maybe other systems. */
- struct spwd *sp = getspnam (pw->pw_name);
+ const struct spwd *sp = getspnam (pw->pw_name);
endspent ();
if (sp)
@@ -232,6 +451,7 @@ correct_password (const struct passwd *p
encrypted = crypt (unencrypted, correct);
memset (unencrypted, 0, strlen (unencrypted));
return STREQ (encrypted, correct);
+#endif /* !USE_PAM */
}
/* Update `environ' for the new shell based on PW, with SHELL being
@@ -256,8 +476,8 @@ modify_environment (const struct passwd
xsetenv ("USER", pw->pw_name);
xsetenv ("LOGNAME", pw->pw_name);
xsetenv ("PATH", (pw->pw_uid
- ? DEFAULT_LOGIN_PATH
- : DEFAULT_ROOT_LOGIN_PATH));
+ ? getdef_str ("PATH", DEFAULT_LOGIN_PATH)
+ : getdef_str ("SUPATH", DEFAULT_ROOT_LOGIN_PATH)));
}
else
{
@@ -267,6 +487,12 @@ modify_environment (const struct passwd
{
xsetenv ("HOME", pw->pw_dir);
xsetenv ("SHELL", shell);
+ if (getdef_bool ("ALWAYS_SET_PATH", 0))
+ xsetenv ("PATH", (pw->pw_uid
+ ? getdef_str ("PATH",
+ DEFAULT_LOGIN_PATH)
+ : getdef_str ("SUPATH",
+ DEFAULT_ROOT_LOGIN_PATH)));
if (pw->pw_uid)
{
xsetenv ("USER", pw->pw_name);
@@ -274,19 +500,41 @@ modify_environment (const struct passwd
}
}
}
+
+#ifdef USE_PAM
+ export_pamenv ();
+#endif
}
/* Become the user and group(s) specified by PW. */
static void
-change_identity (const struct passwd *pw)
+init_groups (const struct passwd *pw)
{
#ifdef HAVE_INITGROUPS
errno = 0;
if (initgroups (pw->pw_name, pw->pw_gid) == -1)
- error (EXIT_CANCELED, errno, _("cannot set groups"));
+ {
+#ifdef USE_PAM
+ cleanup_pam (PAM_ABORT);
+#endif
+ error (EXIT_FAILURE, errno, _("cannot set groups"));
+ }
endgrent ();
#endif
+
+#ifdef USE_PAM
+ retval = pam_setcred (pamh, PAM_ESTABLISH_CRED);
+ if (retval != PAM_SUCCESS)
+ error (EXIT_FAILURE, 0, "%s", pam_strerror (pamh, retval));
+ else
+ _pam_cred_established = 1;
+#endif
+}
+
+static void
+change_identity (const struct passwd *pw)
+{
if (setgid (pw->pw_gid))
error (EXIT_CANCELED, errno, _("cannot set group id"));
if (setuid (pw->pw_uid))
@@ -479,6 +727,7 @@ main (int argc, char **argv)
#ifdef SYSLOG_FAILURE
log_su (pw, false);
#endif
+ sleep (getdef_num ("FAIL_DELAY", 1));
error (EXIT_CANCELED, 0, _("incorrect password"));
}
#ifdef SYSLOG_SUCCESS
@@ -500,9 +749,21 @@ main (int argc, char **argv)
shell = NULL;
}
shell = xstrdup (shell ? shell : pw->pw_shell);
- modify_environment (pw, shell);
+
+ init_groups (pw);
+
+#ifdef USE_PAM
+ create_watching_parent ();
+ /* Now we're in the child. */
+#endif
change_identity (pw);
+
+ /* Set environment after pam_open_session, which may put KRB5CCNAME
+ into the pam_env, etc. */
+
+ modify_environment (pw, shell);
+
if (simulate_login && chdir (pw->pw_dir) != 0)
error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
Index: tests/Makefile.in
===================================================================
--- tests/Makefile.in.orig 2010-04-23 17:58:39.000000000 +0200
+++ tests/Makefile.in 2010-05-06 19:37:45.091861849 +0200
@@ -986,6 +986,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_LIBS = @PAM_LIBS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
POSIX_SHELL = @POSIX_SHELL@