From: Todd C. Miller Date: Fri, 2 Jul 2010 15:11:25 +0000 (-0400) Subject: Replace built-in non-unix group support with a sudoers group plugin. X-Git-Tag: SUDO_1_8_0~423 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e6b48d415c14a2a590f1199d2f9fb5b508f374ba;p=sudo Replace built-in non-unix group support with a sudoers group plugin. Include a sample plugin that can read Unix-format group files. --- diff --git a/INSTALL b/INSTALL index 4562f9828..bce53efed 100644 --- a/INSTALL +++ b/INSTALL @@ -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 diff --git a/MANIFEST b/MANIFEST index d6889cf02..d4c27925d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -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 diff --git a/Makefile.in b/Makefile.in index 664a41e4c..079800fce 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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@ diff --git a/config.h.in b/config.h.in index 277b67542..be9ca3776 100644 --- a/config.h.in +++ b/config.h.in @@ -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 diff --git a/configure b/configure index 558ef7463..61f990c28 100755 --- a/configure +++ b/configure @@ -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 - diff --git a/configure.in b/configure.in index de7adf5f6..1d72b5882 100644 --- a/configure.in +++ b/configure.in @@ -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 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 diff --git a/doc/LICENSE b/doc/LICENSE index 6e9a547ab..9032932dd 100644 --- a/doc/LICENSE +++ b/doc/LICENSE @@ -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. diff --git a/doc/license.pod b/doc/license.pod index a5fdb7bdc..ef509ffd7 100644 --- a/doc/license.pod +++ b/doc/license.pod @@ -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. diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index ef7ccf2eb..7eb871e3f 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -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 */ diff --git a/plugins/sample_group/Makefile.in b/plugins/sample_group/Makefile.in new file mode 100644 index 000000000..fe12ab85b --- /dev/null +++ b/plugins/sample_group/Makefile.in @@ -0,0 +1,120 @@ +# +# Copyright (c) 2010 Todd C. Miller +# +# 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 diff --git a/plugins/sample_group/getgrent.c b/plugins/sample_group/getgrent.c new file mode 100644 index 000000000..f2a65f4cd --- /dev/null +++ b/plugins/sample_group/getgrent.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2005, 2008, 2010 Todd C. Miller + * + * 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 + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include +#include + +#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); +} diff --git a/plugins/sample_group/sample_group.c b/plugins/sample_group/sample_group.c new file mode 100644 index 000000000..133a6642a --- /dev/null +++ b/plugins/sample_group/sample_group.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2010 Todd C. Miller + * + * 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 + +#include +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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 +}; diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index c599b2884..5f257ade1 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -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 diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 81c03f432..79e99ea37 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -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 } diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index ec1014ab9..76b9f12e2 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -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, diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index 203fd1d0c..9dd769951 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -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" diff --git a/plugins/sudoers/group_plugin.c b/plugins/sudoers/group_plugin.c new file mode 100644 index 000000000..a187105c4 --- /dev/null +++ b/plugins/sudoers/group_plugin.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2010 Todd C. Miller + * + * 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 + +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include +#include + +#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); +} diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index c1978026e..6093b8893 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -88,9 +88,6 @@ #ifndef HAVE_EXTENDED_GLOB # include #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); } diff --git a/plugins/sudoers/nonunix.h b/plugins/sudoers/nonunix.h deleted file mode 100644 index 09cd450be..000000000 --- a/plugins/sudoers/nonunix.h +++ /dev/null @@ -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 */ diff --git a/plugins/sudoers/set_perms.c b/plugins/sudoers/set_perms.c index d91b3dabf..46253a6c2 100644 --- a/plugins/sudoers/set_perms.c +++ b/plugins/sudoers/set_perms.c @@ -50,12 +50,6 @@ #include "sudoers.h" -#ifdef __TANDEM -# define ROOT_UID 65535 -#else -# define ROOT_UID 0 -#endif - /* * Prototypes */ diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index db577dbdf..8c4033dde 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -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(); } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 319409152..f2ec62eb4 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -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; diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index e2c607a90..f72684523 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -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 diff --git a/plugins/sudoers/vasgroups.c b/plugins/sudoers/vasgroups.c deleted file mode 100644 index ed614de0d..000000000 --- a/plugins/sudoers/vasgroups.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - -#include - -#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; -} diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index cd0f5c6df..c56ffe030 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -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) { diff --git a/src/sudo.c b/src/sudo.c index b330b709d..e3097a0db 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -80,10 +80,6 @@ #include "sudo_plugin_int.h" #include -#ifdef USING_NONUNIX_GROUPS -# include "nonunix.h" -#endif - /* * Local variables */