Replace built-in non-unix group support with a sudoers group plugin.

Include a sample plugin that can read Unix-format group files.
This commit is contained in:
Todd C. Miller
2010-07-02 11:11:25 -04:00
parent 66eafd0994
commit e6b48d415c
26 changed files with 714 additions and 593 deletions

10
INSTALL
View File

@@ -340,16 +340,6 @@ Special features/options:
Enable support for role based access control (RBAC) on
systems that support SELinux.
--with-libvas=[NAME]
Enable non-Unix group support using Quest Authentication
Services. If NAME is specified, it should be the name of
the shared library providing QAS support (libvas.so by default).
--with-libvas-rpath=[PATH]
The path to search when loading libvas.so (or an alternate
name as specified by --with-libvas). This option only has
an effect when --with-libvas is specified.
The following options are also configurable at runtime:
--with-long-otp-prompt

View File

@@ -101,6 +101,9 @@ mkinstalldirs
pathnames.h.in
plugins/sample/Makefile.in
plugins/sample/sample_plugin.c
plugins/sample_group/Makefile.in
plugins/sample_group/getgrent.c
plugins/sample_group/sample_group.c
plugins/sudoers/Makefile.in
plugins/sudoers/aixcrypt.exp
plugins/sudoers/alias.c
@@ -140,6 +143,7 @@ plugins/sudoers/goodpath.c
plugins/sudoers/gram.c
plugins/sudoers/gram.h
plugins/sudoers/gram.y
plugins/sudoers/group_plugin.c
plugins/sudoers/ins_2001.h
plugins/sudoers/ins_classic.h
plugins/sudoers/ins_csops.h
@@ -155,7 +159,6 @@ plugins/sudoers/logging.c
plugins/sudoers/logging.h
plugins/sudoers/match.c
plugins/sudoers/mkdefaults
plugins/sudoers/nonunix.h
plugins/sudoers/parse.c
plugins/sudoers/parse.h
plugins/sudoers/plugin_error.c
@@ -175,7 +178,6 @@ plugins/sudoers/timestr.c
plugins/sudoers/toke.c
plugins/sudoers/toke.l
plugins/sudoers/tsgetgrpw.c
plugins/sudoers/vasgroups.c
plugins/sudoers/visudo.c
src/Makefile.in
src/conversation.c

View File

@@ -20,7 +20,8 @@ devdir = @devdir@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = compat common src plugins/sample plugins/sudoers include doc
SUBDIRS = compat common src plugins/sample plugins/sample_group \
plugins/sudoers include doc
VERSION = @PACKAGE_VERSION@

View File

@@ -585,9 +585,6 @@
/* The message given when a bad password is entered. */
#undef INCORRECT_PASSWORD
/* The name of libvas.so */
#undef LIBVAS_SO
/* The syslog facility sudo will use. */
#undef LOGFAC
@@ -719,9 +716,6 @@
/* Define to 1 if you want a different ticket file for each tty. */
#undef USE_TTY_TICKETS
/* Define to 1 if using a non-Unix group lookup implementation. */
#undef USING_NONUNIX_GROUPS
/* Define to avoid using the passwd/shadow file for authentication. */
#undef WITHOUT_PASSWD

87
configure vendored
View File

@@ -978,8 +978,6 @@ with_secure_path
with_interfaces
with_stow
with_askpass
with_libvas
with_libvas_rpath
with_plugin_dir
enable_authentication
enable_root_mailer
@@ -1741,10 +1739,6 @@ Optional Packages:
--without-interfaces don't try to read the ip addr of ether interfaces
--with-stow properly handle GNU stow packaging
--with-askpass=PATH Fully qualified pathname of askpass helper
--with-libvas=NAME Name of the libvas shared library
(default=libvas.so)
--with-libvas-rpath=PATH
Path to look for libvas in [default=/opt/quest/lib]
--with-plugin_dir set directory to load plugins from
--with-selinux enable SELinux support
--with-pic try to use only PIC/non-PIC objects [default=use
@@ -5093,42 +5087,6 @@ $as_echo "no" >&6; }
fi
# Check whether --with-libvas was given.
if test "${with_libvas+set}" = set; then :
withval=$with_libvas; case $with_libvas in
yes) with_libvas=libvas.so
;;
no) ;;
*)
cat >>confdefs.h <<_ACEOF
#define LIBVAS_SO "$with_libvas"
_ACEOF
;;
esac
if test X"$with_libvas" != X"no"; then
cat >>confdefs.h <<_ACEOF
#define LIBVAS_SO "$with_libvas"
_ACEOF
$as_echo "#define USING_NONUNIX_GROUPS 1" >>confdefs.h
NONUNIX_GROUPS_IMPL="vasgroups.o"
# Check whether --with-libvas-rpath was given.
if test "${with_libvas_rpath+set}" = set; then :
withval=$with_libvas_rpath; LIBVAS_RPATH=$withval
else
LIBVAS_RPATH=/opt/quest/lib
fi
fi
fi
with_plugindir="$libexecdir"
# Check whether --with-plugin_dir was given.
@@ -6968,13 +6926,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:6971: $ac_compile\"" >&5)
(eval echo "\"\$as_me:6929: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:6974: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:6932: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:6977: output\"" >&5)
(eval echo "\"\$as_me:6935: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -8179,7 +8137,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 8182 "configure"' > conftest.$ac_ext
echo '#line 8140 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -9440,11 +9398,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:9443: $lt_compile\"" >&5)
(eval echo "\"\$as_me:9401: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:9447: \$? = $ac_status" >&5
echo "$as_me:9405: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -9779,11 +9737,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:9782: $lt_compile\"" >&5)
(eval echo "\"\$as_me:9740: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:9786: \$? = $ac_status" >&5
echo "$as_me:9744: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -9884,11 +9842,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:9887: $lt_compile\"" >&5)
(eval echo "\"\$as_me:9845: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:9891: \$? = $ac_status" >&5
echo "$as_me:9849: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9939,11 +9897,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:9942: $lt_compile\"" >&5)
(eval echo "\"\$as_me:9900: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:9946: \$? = $ac_status" >&5
echo "$as_me:9904: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -12306,7 +12264,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 12309 "configure"
#line 12267 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12402,7 +12360,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 12405 "configure"
#line 12363 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -18129,19 +18087,6 @@ fi
;;
esac
if test X"$LIBVAS_RPATH" != X""; then
if test -n "$blibpath"; then
blibpath_add="${blibpath_add}:$LIBVAS_RPATH"
else
case "$host" in
*-*-hpux*) LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH"
;;
*) LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH"
;;
esac
fi
fi
if test -n "$blibpath"; then
if test -n "$blibpath_add"; then
SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}"
@@ -18312,7 +18257,7 @@ EOF
exec_prefix="$oexec_prefix"
fi
ac_config_files="$ac_config_files Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sudoers/Makefile"
ac_config_files="$ac_config_files Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sample_group/Makefile plugins/sudoers/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -19270,6 +19215,7 @@ do
"src/sudo_usage.h") CONFIG_FILES="$CONFIG_FILES src/sudo_usage.h" ;;
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"plugins/sample/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample/Makefile" ;;
"plugins/sample_group/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample_group/Makefile" ;;
"plugins/sudoers/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/Makefile" ;;
*) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
@@ -20574,6 +20520,5 @@ fi

View File

@@ -1087,29 +1087,6 @@ AC_ARG_WITH(askpass, [AS_HELP_STRING([--with-askpass=PATH], [Fully qualified pat
;;
esac], AC_MSG_RESULT(no))
dnl
dnl If enabled, set LIBVAS_SO, LIBVAS_RPATH and USING_NONUNIX_GROUPS
dnl
AC_ARG_WITH(libvas, [AS_HELP_STRING([--with-libvas=NAME], [Name of the libvas shared library (default=libvas.so)])],
[case $with_libvas in
yes) with_libvas=libvas.so
;;
no) ;;
*) AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so])
;;
esac
if test X"$with_libvas" != X"no"; then
AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so])
AC_DEFINE(USING_NONUNIX_GROUPS)
NONUNIX_GROUPS_IMPL="vasgroups.o"
AC_ARG_WITH([libvas-rpath],
[AS_HELP_STRING([--with-libvas-rpath=PATH],
[Path to look for libvas in [default=/opt/quest/lib]])],
[LIBVAS_RPATH=$withval],
[LIBVAS_RPATH=/opt/quest/lib])
fi
])
with_plugindir="$libexecdir"
AC_ARG_WITH(plugin_dir, [AS_HELP_STRING([--with-plugin_dir], [set directory to load plugins from])],
[case $with_plugin_dir in
@@ -2671,23 +2648,6 @@ case "$host" in
;;
esac
dnl
dnl Add LIBVAS_RPATH to LDFLAGS
dnl GNU ld accepts -R/path/ as an alias for -rpath /path/
dnl
if test X"$LIBVAS_RPATH" != X""; then
if test -n "$blibpath"; then
blibpath_add="${blibpath_add}:$LIBVAS_RPATH"
else
case "$host" in
*-*-hpux*) LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH"
;;
*) LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH"
;;
esac
fi
fi
dnl
dnl Add $blibpath to SUDOERS_LDFLAGS if specified by the user or if we
dnl added -L dirpaths to SUDOERS_LDFLAGS.
@@ -2779,7 +2739,7 @@ dnl
dnl Substitute into the Makefile and man pages
dnl
dnl AC_CONFIG_FILES([doc/sudo.man doc/visudo.man doc/sudoers.man doc/sudoers.ldap.man doc/sudoreplay.man src/Makefile src/sudo_usage.h])
AC_CONFIG_FILES([Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sudoers/Makefile])
AC_CONFIG_FILES([Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sample_group/Makefile plugins/sudoers/Makefile])
AC_OUTPUT
dnl
@@ -2875,7 +2835,6 @@ AH_TEMPLATE(USE_TTY_TICKETS, [Define to 1 if you want a different ticket file fo
AH_TEMPLATE(WITHOUT_PASSWD, [Define to avoid using the passwd/shadow file for authentication.])
AH_TEMPLATE(sig_atomic_t, [Define to `int' if <signal.h> does not define.])
AH_TEMPLATE(__signed, [Define to `signed' or nothing if compiler does not support a signed type qualifier.])
AH_TEMPLATE(USING_NONUNIX_GROUPS, [Define to 1 if using a non-Unix group lookup implementation.])
dnl
dnl Bits to copy verbatim into config.h.in

View File

@@ -48,31 +48,3 @@ bear the following UCB license:
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
nonunix.h and vasgroups.c bear the following license:
Copyright (c) 2006 Quest Software, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Quest Software, Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -52,32 +52,3 @@ bear the following UCB license:
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
=head3
nonunix.h and vasgroups.c bear the following license:
Copyright (c) 2006 Quest Software, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Quest Software, Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -104,4 +104,33 @@ struct generic_plugin {
/* the rest depends on the type... */
};
/* Sudoers group plugin version major/minor */
#define GROUP_API_VERSION_MAJOR 1
#define GROUP_API_VERSION_MINOR 0
#define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | GROUP_API_VERSION_MINOR)
/* Getters and setters for group version */
#define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
#define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
#define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \
*(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
} while(0)
#define GROUP_API_VERSION_SET_MINOR(vp, n) do { \
*(vp) = (*(vp) & 0xffff0000) | (n); \
} while(0)
/*
* version: for compatibility checking
* group_init: return 1 on success, 0 if unconfigured, -1 on error.
* group_cleanup: called to clean up resources used by provider
* user_in_group: returns 1 if user is in group, 0 if not.
* note that pwd may be NULL if the user is not in passwd.
*/
struct sudoers_group_plugin {
unsigned int version;
int (*init)(int version, sudo_printf_t sudo_printf, char *const argv[]);
void (*cleanup)(void);
int (*query)(const char *user, const char *group, const struct passwd *pwd);
};
#endif /* _SUDO_PLUGIN_H */

View File

@@ -0,0 +1,120 @@
#
# Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# @configure_input@
#
#### Start of system configuration section. ####
srcdir = @srcdir@
devdir = @devdir@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
incdir = $(top_srcdir)/include
# For out of tree builds
VPATH = $(srcdir)
# Compiler & tools to use
CC = @CC@
LIBTOOL = @LIBTOOL@ --tag=disable-static
# Our install program supports extra flags...
INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
# Libraries
LIBS = $(LIBOBJDIR)/libreplace.la
# C preprocessor flags
CPPFLAGS = -I$(incdir) -I$(top_builddir) @CPPFLAGS@
# Usually -O and/or -g
CFLAGS = @CFLAGS@
# Flags to pass to the link stage
LDFLAGS =
# Where to install things...
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
sysconfdir = @sysconfdir@
libexecdir = @libexecdir@
datarootdir = @datarootdir@
plugindir = @PLUGINDIR@
# OS dependent defines
DEFS = @OSDEFS@
#### End of system configuration section. ####
SHELL = @SHELL@
OBJS = sample_group.lo getgrent.lo
LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/
VERSION = @PACKAGE_VERSION@
all: sample_group.la
.SUFFIXES: .o .c .h .lo
.c.o:
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
.c.lo:
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $<
getgrent.lo: $(srcdir)/getgrent.c
sample_group.lo: $(srcdir)/sample_group.c
sample_group.la: $(OBJS)
$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -module -avoid-version -rpath $(plugindir)
install: install-dirs install-plugin
install-dirs:
$(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir)
install-binaries:
install-includes:
install-man:
install-plugin: install-dirs sample_group.la
$(LIBTOOL) --mode=install --quiet $(INSTALL) sample_group.la $(plugindir)
check:
@echo nothing to check
clean:
-$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.*
mostlyclean: clean
distclean: clean
-rm -rf Makefile .libs
clobber: distclean
realclean: distclean
rm -f TAGS tags
cleandir: realclean

View File

@@ -0,0 +1,185 @@
/*
* Copyright (c) 2005, 2008, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Trivial replacements for the libc getgr{uid,nam}() routines.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
# include <memory.h>
# endif
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <fcntl.h>
#include <limits.h>
#include <pwd.h>
#include <grp.h>
#include <compat.h>
#include <missing.h>
#ifndef LINE_MAX
# define LINE_MAX 2048
#endif
#undef GRMEM_MAX
#define GRMEM_MAX 200
static FILE *grf;
static const char *grfile = "/etc/group";
static int gr_stayopen;
void mysetgrfile(const char *);
void mysetgrent(void);
void myendgrent(void);
struct group *mygetgrent(void);
struct group *mygetgrnam(const char *);
struct group *mygetgrgid(gid_t);
void
mysetgrfile(const char *file)
{
grfile = file;
if (grf != NULL)
myendgrent();
}
void
mysetgrent(void)
{
if (grf == NULL) {
grf = fopen(grfile, "r");
if (grf != NULL)
fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
} else {
rewind(grf);
}
gr_stayopen = 1;
}
void
myendgrent(void)
{
if (grf != NULL) {
fclose(grf);
grf = NULL;
}
gr_stayopen = 0;
}
struct group *
mygetgrent(void)
{
static struct group gr;
static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1];
size_t len;
char *cp, *colon;
int n;
if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
return(NULL);
memset(&gr, 0, sizeof(gr));
if ((colon = strchr(cp = colon, ':')) == NULL)
return(NULL);
*colon++ = '\0';
gr.gr_name = cp;
if ((colon = strchr(cp = colon, ':')) == NULL)
return(NULL);
*colon++ = '\0';
gr.gr_passwd = cp;
if ((colon = strchr(cp = colon, ':')) == NULL)
return(NULL);
*colon++ = '\0';
gr.gr_gid = atoi(cp);
len = strlen(colon);
if (len > 0 && colon[len - 1] == '\n')
colon[len - 1] = '\0';
if (*colon != '\0') {
gr.gr_mem = gr_mem;
cp = strtok(colon, ",");
for (n = 0; cp != NULL && n < GRMEM_MAX; n++) {
gr.gr_mem[n] = cp;
cp = strtok(NULL, ",");
}
gr.gr_mem[n++] = NULL;
} else
gr.gr_mem = NULL;
return(&gr);
}
struct group *
mygetgrnam(const char *name)
{
struct group *gr;
if (grf == NULL) {
if ((grf = fopen(grfile, "r")) == NULL)
return(NULL);
fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
} else {
rewind(grf);
}
while ((gr = mygetgrent()) != NULL) {
if (strcmp(gr->gr_name, name) == 0)
break;
}
if (!gr_stayopen) {
fclose(grf);
grf = NULL;
}
return(gr);
}
struct group *
mygetgrgid(gid_t gid)
{
struct group *gr;
if (grf == NULL) {
if ((grf = fopen(grfile, "r")) == NULL)
return(NULL);
fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
} else {
rewind(grf);
}
while ((gr = mygetgrent()) != NULL) {
if (gr->gr_gid == gid)
break;
}
if (!gr_stayopen) {
fclose(grf);
grf = NULL;
}
return(gr);
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
# include <memory.h>
# endif
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <grp.h>
#include <pwd.h>
#include <sudo_plugin.h>
#include <compat.h>
#include <missing.h>
/*
* Sample sudoers group plugin that uses an extra group file with the
* same format as /etc/group.
*/
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
#undef ERROR
#define ERROR -1
static sudo_printf_t sudo_log;
extern void mysetgrfile(const char *);
extern void mysetgrent(void);
extern void myendgrent(void);
extern struct group *mygetgrnam(const char *);
static int sample_init(int version, sudo_printf_t sudo_printf, char *const argv[])
{
struct stat sb;
sudo_log = sudo_printf;
if (GROUP_API_VERSION_GET_MAJOR(version) != GROUP_API_VERSION_MAJOR) {
sudo_log(SUDO_CONV_ERROR_MSG,
"sample_group: incompatible major version %d, expected %d\n",
GROUP_API_VERSION_GET_MAJOR(version),
GROUP_API_VERSION_MAJOR);
return ERROR;
}
/* Sanity check the specified group file. */
if (argv == NULL || argv[0] == NULL) {
sudo_log(SUDO_CONV_ERROR_MSG,
"sample_group: path to group file not specified\n");
return ERROR;
}
if (stat(argv[0], &sb) != 0) {
sudo_log(SUDO_CONV_ERROR_MSG,
"sample_group: %s: %s\n", argv[0], strerror(errno));
return ERROR;
}
if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
sudo_log(SUDO_CONV_ERROR_MSG,
"%s must be only be writable by owner\n", argv[0]);
return ERROR;
}
mysetgrfile(argv[0]);
mysetgrent();
return TRUE;
}
static void sample_cleanup(void)
{
myendgrent();
}
/*
* Returns TRUE if "user" is a member of "group", else FALSE.
*/
static int sample_query(const char *user, const char *group, const struct passwd *pwd)
{
struct group *grp;
char **member;
grp = mygetgrnam(group);
if (grp != NULL) {
for (member = grp->gr_mem; *member != NULL; member++) {
if (strcasecmp(user, *member) == 0)
return TRUE;
}
}
return FALSE;
}
struct sudoers_group_plugin group_plugin = {
GROUP_API_VERSION,
sample_init,
sample_cleanup,
sample_query
};

View File

@@ -105,7 +105,7 @@ LIBSUDOERS_OBJS = alias.lo audit.lo defaults.lo gram.lo match.lo pwutil.lo \
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo \
plugin_error.lo env.lo getspwuid.lo \
goodpath.lo find_path.lo interfaces.lo \
goodpath.lo group_plugin.lo find_path.lo interfaces.lo \
logging.lo parse.lo set_perms.lo sudoers.lo sudo_nss.lo \
iolog.lo @SUDOERS_OBJS@
@@ -113,7 +113,7 @@ VISUDO_OBJS = visudo.o goodpath.o find_path.o error.o
REPLAY_OBJS = getdate.o sudoreplay.o error.o
TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o
TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o group_plugin.o
VERSION = @PACKAGE_VERSION@
@@ -197,6 +197,7 @@ getspwuid.lo: $(srcdir)/getspwuid.c $(SUDODEP)
goodpath.lo: $(srcdir)/goodpath.c $(SUDODEP)
gram.lo: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(devdir)/gram.h
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/gram.c
group_plugin.lo: $(srcdir)/group_plugin.c $(SUDODEP)
interfaces.lo: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h
iolog.lo: $(srcdir)/iolog.c $(SUDODEP)
ldap.lo: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h
@@ -213,7 +214,6 @@ timestr.lo: $(srcdir)/timestr.c $(incdir)/compat.h $(top_builddir)/config.h
toke.lo: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(incdir)/list.h $(devdir)/gram.h
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/toke.c
tsgetgrpw.lo: $(srcdir)/tsgetgrpw.c $(SUDODEP)
vasgroups.lo: $(srcdir)/vasgroups.c $(srcdir)/nonunix.h $(SUDODEP)
plugin_error.lo: $(srcdir)/plugin_error.c $(incdir)/error.h $(incdir)/compat.h $(top_builddir)/config.h
# Auth dependencies

View File

@@ -326,6 +326,10 @@ struct sudo_defs_types sudo_defs_table[] = {
"use_pty", T_FLAG,
"Always run commands in a pseudo-tty",
NULL,
}, {
"group_plugin", T_STR,
"Plugin for non-Unix group support",
NULL,
}, {
NULL, 0, NULL
}

View File

@@ -150,6 +150,8 @@
#define I_COMPRESS_IO 74
#define def_use_pty (sudo_defs_table[75].sd_un.flag)
#define I_USE_PTY 75
#define def_group_plugin (sudo_defs_table[76].sd_un.str)
#define I_GROUP_PLUGIN 76
enum def_tupple {
never,

View File

@@ -241,3 +241,6 @@ compress_io
use_pty
T_FLAG
"Always run commands in a pseudo-tty"
group_plugin
T_STR
"Plugin for non-Unix group support"

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if TIME_WITH_SYS_TIME
# include <time.h>
#endif
#include <ctype.h>
#include <dlfcn.h>
#include <errno.h>
#include <pwd.h>
#include "sudoers.h"
static void *group_handle;
static struct sudoers_group_plugin *group_plugin;
/*
* Load the specified plugin and run its init function.
* Returns -1 if unable to open the plugin, else it returns
* the value from the plugin's init function.
*/
int
group_plugin_load(char *plugin_info)
{
struct stat sb;
char *args, path[PATH_MAX], savedch;
char **argv = NULL;
size_t len;
int rc;
/*
* Fill in .so path and split out args (if any).
*/
path[0] = '\0';
if (plugin_info[0] != '/')
strlcpy(path, _PATH_SUDO_PLUGIN_DIR, sizeof(path));
if ((args = strpbrk(plugin_info, " \t")) != NULL) {
savedch = *args;
*args = '\0';
}
len = strlcat(path, plugin_info, sizeof(path));
if (args != NULL)
*args++ = savedch;
if (len >= sizeof(path)) {
warningx("%s%s: %s", _PATH_SUDO_PLUGIN_DIR, plugin_info,
strerror(ENAMETOOLONG));
return -1;
}
/* Sanity check plugin path. */
if (stat(path, &sb) != 0) {
warning("%s", path);
return -1;
}
if (sb.st_uid != ROOT_UID) {
warningx("%s must be owned by uid %d", path, ROOT_UID);
return -1;
}
if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
warningx("%s must be only be writable by owner", path);
return -1;
}
/* Open plugin and map in symbol. */
group_handle = dlopen(path, RTLD_NOW);
if (!group_handle) {
warningx("unable to dlopen %s: %s", path, dlerror());
return -1;
}
group_plugin = dlsym(group_handle, "group_plugin");
if (group_plugin == NULL) {
warningx("unable to find symbol \"group_plugin\" in %s", path);
return -1;
}
if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) {
warningx("%s: incompatible group plugin major version %d, expected %d",
path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version),
GROUP_API_VERSION_MAJOR);
return -1;
}
/*
* Split args into a vector if specified.
*/
if (args != NULL) {
int ac = 0, wasblank = TRUE;
char *cp;
for (cp = args; *cp != '\0'; cp++) {
if (isblank((unsigned char)*cp)) {
wasblank = TRUE;
} else if (wasblank) {
wasblank = FALSE;
ac++;
}
}
if (ac != 0) {
argv = emalloc2(ac, sizeof(char *));
ac = 0;
for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t")))
argv[ac++] = cp;
}
}
rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv);
efree(argv);
return rc;
}
void
group_plugin_unload(void)
{
(group_plugin->cleanup)();
dlclose(group_handle);
group_handle = NULL;
}
int
group_plugin_query(const char *user, const char *group,
const struct passwd *pwd)
{
return (group_plugin->query)(user, group, pwd);
}

View File

@@ -88,9 +88,6 @@
#ifndef HAVE_EXTENDED_GLOB
# include <compat/glob.h>
#endif /* HAVE_EXTENDED_GLOB */
#ifdef USING_NONUNIX_GROUPS
# include "nonunix.h"
#endif /* USING_NONUNIX_GROUPS */
static struct member_list empty;
@@ -778,10 +775,8 @@ usergr_matches(char *group, char *user, struct passwd *pw)
if (*group++ != '%')
return(FALSE);
#ifdef USING_NONUNIX_GROUPS
if (*group == ':')
return(sudo_nonunix_groupcheck(++group, user, pw));
#endif /* USING_NONUNIX_GROUPS */
if (*group == ':' && def_group_plugin)
return(group_plugin_query(user, group + 1, pw));
/* look up user's primary gid in the passwd file */
if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
@@ -790,12 +785,9 @@ usergr_matches(char *group, char *user, struct passwd *pw)
if (user_in_group(pw, group))
return(TRUE);
#ifdef USING_NONUNIX_GROUPS
/* not a Unix group, could be an AD group */
if (sudo_nonunix_groupcheck_available() &&
sudo_nonunix_groupcheck(group, user, pw))
/* not a Unix group, could be an external group */
if (def_group_plugin && group_plugin_query(user, group, pw))
return(TRUE);
#endif /* USING_NONUNIX_GROUPS */
return(FALSE);
}

View File

@@ -1,40 +0,0 @@
/*
* (c) 2006 Quest Software, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of Quest Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NONUNIX_H
#define _NONUNIX_H
void sudo_nonunix_groupcheck_init(void);
void sudo_nonunix_groupcheck_cleanup(void);
int sudo_nonunix_groupcheck(const char *group, const char *user,
const struct passwd *pwd);
int sudo_nonunix_groupcheck_available(void);
#endif /* _NONUNIX_H */

View File

@@ -50,12 +50,6 @@
#include "sudoers.h"
#ifdef __TANDEM
# define ROOT_UID 65535
#else
# define ROOT_UID 0
#endif
/*
* Prototypes
*/

View File

@@ -105,10 +105,6 @@
#include "interfaces.h"
#include "auth/sudo_auth.h"
#ifdef USING_NONUNIX_GROUPS
# include "nonunix.h"
#endif
/*
* Prototypes
*/
@@ -223,10 +219,6 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
init_vars(envp); /* XXX - move this later? */
#ifdef USING_NONUNIX_GROUPS
sudo_nonunix_groupcheck_init(); /* initialise nonunix groups impl */
#endif /* USING_NONUNIX_GROUPS */
/* Parse nsswitch.conf for sudoers order. */
snl = sudo_read_nss();
@@ -246,6 +238,18 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
/* XXX - collect post-sudoers parse settings into a function */
/*
* Initialize external group plugin.
*/
if (def_group_plugin) {
switch (group_plugin_load(def_group_plugin)) {
case -1:
return -1;
case FALSE:
def_group_plugin = NULL;
}
}
/*
* Set runas passwd/group entries based on command line or sudoers.
* Note that if runas_group was specified without runas_user we
@@ -343,10 +347,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
NewArgv[0] = runas_pw->pw_shell;
#ifdef USING_NONUNIX_GROUPS
sudo_nonunix_groupcheck_init(); /* initialise nonunix groups impl */
#endif /* USING_NONUNIX_GROUPS */
/* Find command in path */
cmnd_status = set_cmnd(sudo_mode);
if (cmnd_status == -1) {
@@ -527,11 +527,8 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
tq_foreach_fwd(snl, nss) {
nss->close(nss);
}
#ifdef USING_NONUNIX_GROUPS
/* Finished with the groupcheck code */
sudo_nonunix_groupcheck_cleanup();
#endif
if (def_group_plugin)
group_plugin_unload();
if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST)))
goto done;
@@ -1138,9 +1135,8 @@ cleanup(int gotsignal)
tq_foreach_fwd(snl, nss)
nss->close(nss);
}
#ifdef USING_NONUNIX_GROUPS
sudo_nonunix_groupcheck_cleanup();
#endif
if (def_group_plugin)
group_plugin_unload();
sudo_endpwent();
sudo_endgrent();
}

View File

@@ -177,6 +177,12 @@ struct sudo_user {
#define user_type (sudo_user.type)
#define user_closefrom (sudo_user.closefrom)
#ifdef __TANDEM
# define ROOT_UID 65535
#else
# define ROOT_UID 0
#endif
/*
* We used to use the system definition of PASS_MAX or _PASSWD_LEN,
* but that caused problems with various alternate authentication
@@ -299,6 +305,12 @@ FILE *open_sudoers(const char *, int, int *);
void aix_restoreauthdb(void);
void aix_setauthdb(char *user);
/* group_plugin.c */
int group_plugin_load(char *plugin_info);
void group_plugin_unload(void);
int group_plugin_query(const char *user, const char *group,
const struct passwd *pwd);
#ifndef _SUDO_MAIN
extern struct sudo_user sudo_user;
extern struct passwd *auth_pw, *list_pw;

View File

@@ -248,6 +248,9 @@ main(int argc, char *argv[])
(void) fputs(" (problem with defaults entries)", stdout);
puts(".");
if (def_group_plugin && group_plugin_load(def_group_plugin) != TRUE)
def_group_plugin = NULL;
/*
* Set runas passwd/group entries based on command line or sudoers.
* Note that if runas_group was specified without runas_user we

View File

@@ -1,319 +0,0 @@
/*
* (c) 2006 Quest Software, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of Quest Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include <stdlib.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <dlfcn.h>
#include <vas.h>
#include "nonunix.h"
#include "sudoers.h"
#include "parse.h"
/* Pseudo-boolean types */
#undef TRUE
#undef FALSE
#define FALSE 0
#define TRUE 1
static vas_ctx_t *sudo_vas_ctx;
static vas_id_t *sudo_vas_id;
/* Don't use VAS_NAME_FLAG_NO_CACHE or lookups just won't work.
* -tedp, 2006-08-29 */
static const int update_flags = 0;
static int sudo_vas_available = 0;
static char *err_msg = NULL;
static void *libvas_handle = NULL;
/* libvas functions */
static vas_err_t (*v_ctx_alloc) (vas_ctx_t **ctx);
static void (*v_ctx_free) (vas_ctx_t *ctx);
static vas_err_t (*v_id_alloc) (vas_ctx_t *ctx, const char *name, vas_id_t **id);
static void (*v_id_free) (vas_ctx_t *ctx, vas_id_t *id);
static vas_err_t (*v_id_establish_cred_keytab) (vas_ctx_t *ctx, vas_id_t *id, int credflags, const char *keytab);
static vas_err_t (*v_user_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_user_t **user);
static void (*v_user_free) (vas_ctx_t *ctx, vas_user_t *user);
static vas_err_t (*v_group_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_group_t **group);
static void (*v_group_free) (vas_ctx_t *ctx, vas_group_t *group);
static vas_err_t (*v_user_is_member) (vas_ctx_t *ctx, vas_id_t *id, vas_user_t *user, vas_group_t *group);
static const char* (*v_err_get_string) (vas_ctx_t *ctx, int with_cause);
static int resolve_vas_funcs(void);
/**
* Whether nonunix group lookups are available.
* @return 1 if available, 0 if not.
*/
int
sudo_nonunix_groupcheck_available(void)
{
return sudo_vas_available;
}
/**
* Check if the user is in the group
* @param group group name which can be in DOMAIN\sam format or just the group
* name
* @param user user name
* @param pwd (unused)
* @return 1 if user is a member of the group, 0 if not (or error occurred)
*/
int
sudo_nonunix_groupcheck( const char* group, const char* user, const struct passwd* pwd )
{
static int error_cause_shown = FALSE;
int rval = FALSE;
vas_err_t vaserr;
vas_user_t* vas_user = NULL;
vas_group_t* vas_group = NULL;
if (!sudo_vas_available) {
if (error_cause_shown == FALSE) {
/* Produce the saved error reason */
warningx("Non-unix group checking unavailable: %s",
err_msg ? err_msg
: "(unknown cause)");
error_cause_shown = TRUE;
}
return 0;
}
/* resolve the user and group. The user will be a real Unix account name,
* while the group may be a unix name, or any group name accepted by
* vas_name_to_dn, which means any of:
* - Group Name
* - Group Name@FULLY.QUALIFIED.DOMAIN
* - CN=sudoers,CN=Users,DC=rcdev,DC=vintela,DC=com
* - S-1-2-34-5678901234-5678901234-5678901234-567
*
* XXX - we may get non-VAS user accounts here. You can add local users to an
* Active Directory group through override files. Should we handle that case?
* */
if( (vaserr = v_user_init( sudo_vas_ctx, sudo_vas_id, user, update_flags, &vas_user )) != VAS_ERR_SUCCESS ) {
if (vaserr == VAS_ERR_NOT_FOUND) {
/* No such user in AD. Probably a local user. */
vaserr = VAS_ERR_SUCCESS;
}
goto FINISHED;
}
if( (vaserr = v_group_init( sudo_vas_ctx, sudo_vas_id, group, update_flags, &vas_group )) != VAS_ERR_SUCCESS ) {
goto FINISHED;
}
/* do the membership check */
if( (vaserr = v_user_is_member( sudo_vas_ctx, sudo_vas_id, vas_user, vas_group )) == VAS_ERR_SUCCESS ) {
rval = TRUE;
}
else if (vaserr == VAS_ERR_NOT_FOUND) {
/* fake the vaserr code so no error is triggered */
vaserr = VAS_ERR_SUCCESS;
}
FINISHED: /* cleanups */
if (vaserr != VAS_ERR_SUCCESS && vaserr != VAS_ERR_NOT_FOUND ) {
warningx("Error while checking group membership "
"for user \"%s\", group \"%s\", error: %s%s.", user, group,
v_err_get_string(sudo_vas_ctx, 1),
/* A helpful hint if there seems to be a non-FQDN as the domain */
(strchr(group, '@') && !strchr(group, '.'))
? "\nMake sure the fully qualified domain name is specified"
: "");
}
if( vas_group ) v_group_free( sudo_vas_ctx, vas_group );
if( vas_user ) v_user_free( sudo_vas_ctx, vas_user );
return(rval);
}
static void
set_err_msg(const char *msg, ...) {
va_list ap;
if (!msg) /* assert */
return;
if (err_msg)
free(err_msg);
va_start(ap, msg);
if (vasprintf(&err_msg, msg, ap) == -1)
err_msg = NULL;
va_end(ap);
}
/**
* Initialise nonunix_groupcheck state.
*/
void
sudo_nonunix_groupcheck_init(void)
{
vas_err_t vaserr;
void *libvas;
if (err_msg) {
free(err_msg);
err_msg = NULL;
}
libvas = dlopen(LIBVAS_SO, RTLD_LAZY);
if (!libvas) {
set_err_msg("dlopen() failed: %s", dlerror());
return;
}
libvas_handle = libvas;
if (resolve_vas_funcs() != 0)
return;
if (VAS_ERR_SUCCESS == (vaserr = v_ctx_alloc(&sudo_vas_ctx))) {
if (VAS_ERR_SUCCESS == (vaserr = v_id_alloc(sudo_vas_ctx, "host/", &sudo_vas_id))) {
if (update_flags & VAS_NAME_FLAG_NO_LDAP) {
sudo_vas_available = 1;
return; /* OK */
} else { /* Get a keytab */
if ((vaserr = v_id_establish_cred_keytab( sudo_vas_ctx,
sudo_vas_id,
VAS_ID_FLAG_USE_MEMORY_CCACHE
| VAS_ID_FLAG_KEEP_COPY_OF_CRED
| VAS_ID_FLAG_NO_INITIAL_TGT,
NULL )) == VAS_ERR_SUCCESS) {
sudo_vas_available = 1;
return; /* OK */
}
if (!err_msg)
set_err_msg("unable to establish creds: %s",
v_err_get_string(sudo_vas_ctx, 1));
}
v_id_free(sudo_vas_ctx, sudo_vas_id);
sudo_vas_id = NULL;
}
/* This is the last opportunity to get an error message from libvas */
if (!err_msg)
set_err_msg("Error initializing non-unix group checking: %s",
v_err_get_string(sudo_vas_ctx, 1));
v_ctx_free(sudo_vas_ctx);
sudo_vas_ctx = NULL;
}
if (!err_msg)
set_err_msg("Failed to get a libvas handle for non-unix group checking (unknown cause)");
sudo_vas_available = 0;
}
/**
* Clean up nonunix_groupcheck state.
*/
void
sudo_nonunix_groupcheck_cleanup(void)
{
if (err_msg) {
free(err_msg);
err_msg = NULL;
}
if (sudo_vas_available) {
v_id_free(sudo_vas_ctx, sudo_vas_id);
sudo_vas_id = NULL;
v_ctx_free(sudo_vas_ctx);
sudo_vas_ctx = NULL;
sudo_vas_available = FALSE;
}
if (libvas_handle) {
if (dlclose(libvas_handle) != 0)
warningx("dlclose() failed: %s", dlerror());
libvas_handle = NULL;
}
}
#define RESOLVE_OR_ERR(fptr, sym) \
do { \
void *_fptr = dlsym(libvas_handle, (sym)); \
if (!_fptr) { \
set_err_msg("dlsym() failed: %s", dlerror()); \
return -1; \
} \
fptr = _fptr; \
} while (0)
/**
* Resolve all the libvas functions.
* Returns -1 and sets err_msg if something went wrong, or 0 on success.
*/
int
resolve_vas_funcs(void)
{
if (!libvas_handle) /* assert */
return -1;
RESOLVE_OR_ERR(v_ctx_alloc, "vas_ctx_alloc");
RESOLVE_OR_ERR(v_ctx_free, "vas_ctx_free");
RESOLVE_OR_ERR(v_id_alloc, "vas_id_alloc");
RESOLVE_OR_ERR(v_id_free, "vas_id_free");
RESOLVE_OR_ERR(v_id_establish_cred_keytab, "vas_id_establish_cred_keytab");
RESOLVE_OR_ERR(v_user_init, "vas_user_init");
RESOLVE_OR_ERR(v_user_free, "vas_user_free");
RESOLVE_OR_ERR(v_group_init, "vas_group_init");
RESOLVE_OR_ERR(v_group_free, "vas_group_free");
RESOLVE_OR_ERR(v_user_is_member, "vas_user_is_member");
RESOLVE_OR_ERR(v_err_get_string, "vas_err_get_string");
return 0;
}

View File

@@ -573,6 +573,13 @@ sudo_endspent(void)
return;
}
/* STUB */
int
group_plugin_query(const char *user, const char *group, const struct passwd *pw)
{
return FALSE;
}
char *
sudo_getepw(const struct passwd *pw)
{

View File

@@ -80,10 +80,6 @@
#include "sudo_plugin_int.h"
#include <sudo_usage.h>
#ifdef USING_NONUNIX_GROUPS
# include "nonunix.h"
#endif
/*
* Local variables
*/