From 7f323157a238f5669086573d1820df7bc4bd9e74 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 28 Dec 2007 16:20:45 +0000 Subject: [PATCH] First cut at nsswitch.conf support. Further reorganizaton and related changes are forthcoming. --- Makefile.in | 12 +++++----- README.LDAP | 16 ++++++++++---- ldap.c | 3 +++ pathnames.h.in | 4 ++++ sudo.c | 59 +++++++++++++++++++++++++++++++++++++------------- sudo.h | 1 + 6 files changed, 70 insertions(+), 25 deletions(-) diff --git a/Makefile.in b/Makefile.in index 2445b5d77..5a37d02ff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -104,9 +104,9 @@ SRCS = alias.c alloc.c check.c closefrom.c def_data.c defaults.c env.c \ getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y interfaces.c \ lbuf.c ldap.c list.c logging.c match.c mkstemp.c memrchr.c parse.c \ pwutil.c set_perms.c sigaction.c snprintf.c strcasecmp.c strerror.c \ - strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c testsudoers.c \ - tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c visudo.c zero_bytes.c \ - redblack.c $(AUTH_SRCS) + strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c sudo_nss.c \ + testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c visudo.c \ + zero_bytes.c redblack.c $(AUTH_SRCS) AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \ auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \ @@ -127,7 +127,7 @@ COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o list.o match.o \ SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \ getspwuid.o gettime.o goodpath.o fileops.o find_path.o \ interfaces.o lbuf.o logging.o parse.o pwutil.o set_perms.o \ - sudo.o sudo_edit.o tgetpass.o + sudo.o sudo_edit.o sudo_nss.o tgetpass.o VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \ find_path.o pwutil.o @@ -265,8 +265,6 @@ memrchr.o: $(srcdir)/memrchr.c $(SUDODEP) $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c mkstemp.o: $(srcdir)/mkstemp.c $(SUDODEP) $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemp.c -mon_solaris.o: $(srcdir)/mon_solaris.c $(SUDODEP) $(srcdir)/mon_solaris.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mon_solaris.c parse.o: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse.c pwutil.o: $(srcdir)/pwutil.c $(SUDODEP) @@ -293,6 +291,8 @@ sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP) $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_edit.c sudo_noexec.o: $(srcdir)/sudo_noexec.c $(srcdir)/compat.h config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c +sudo_nss.o: $(srcdir)/sudo_nss.c $(SUDODEP) + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_nss.c testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP) diff --git a/README.LDAP b/README.LDAP index b24c7524c..1f74f8de6 100644 --- a/README.LDAP +++ b/README.LDAP @@ -366,8 +366,16 @@ seem. If you desperately want this to be changed, contact Aaron Spangler Configure your /etc/nsswitch.conf ================================= -At the time of this writing, sudo does not consult nsswitch.conf for the -search order. But if it did, it would look like this: -This might be implemented in the future. For now just skip this step. +Starting with version 1.7, sudo consults nsswitch.conf for the search order. +The following sources are recognized. + files read sudoers from a file (usually /etc/sudoers) + ldap read sudoers from LDAP + compat behave as if no nsswitch.conf was present - sudoers: files ldap +I addition, the entry "[NOTFOUND=return]" will short-circuit the +search if the user was not found in the preceding source. + +If /etc/nsswitch.conf is not present or there is no sudoers line, +the following default is assumed: + + sudoers: ldap files diff --git a/ldap.c b/ldap.c index e117311b2..70f419366 100644 --- a/ldap.c +++ b/ldap.c @@ -1304,6 +1304,9 @@ sudo_ldap_check(v, pwflag) int ldap_user_matches = FALSE, ldap_host_matches = FALSE; /* flags */ struct passwd *pw = list_pw ? list_pw : sudo_user.pw; + if (ld == NULL) + return(0); /* XXX - if only LDAP and we return 0, it will misbehasve */ + if (pwflag) { int doauth = UNSPEC; enum def_tupple pwcheck = diff --git a/pathnames.h.in b/pathnames.h.in index 0e76a7283..f06b67477 100644 --- a/pathnames.h.in +++ b/pathnames.h.in @@ -115,3 +115,7 @@ #ifndef _PATH_LDAP_SECRET #define _PATH_LDAP_SECRET "/etc/ldap.secret" #endif /* _PATH_LDAP_SECRET */ + +#ifndef _PATH_NSSWITCH_CONF +#define _PATH_NSSWITCH_CONF "/etc/nsswitch.conf" +#endif /* _PATH_NSSWITCH_CONF */ diff --git a/sudo.c b/sudo.c index 317901677..9f3dde9b7 100644 --- a/sudo.c +++ b/sudo.c @@ -165,6 +165,7 @@ main(argc, argv, envp) extern char *malloc_options; malloc_options = "AFGJPR"; #endif + const unsigned char *nss, *nss_base; #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); @@ -265,18 +266,32 @@ main(argc, argv, envp) init_vars(sudo_mode, envp); /* XXX - move this later? */ -#ifdef HAVE_LDAP - if ((ldap_conn = sudo_ldap_open()) != NULL) - sudo_ldap_update_defaults(ldap_conn); + /* Parse nsswitch.conf for sudoers order. */ + nss_base = read_nss(_PATH_NSSWITCH_CONF); + if (*nss_base == SUDO_NSS_LAST) + log_error(0, "No valid sudoers sources in nsswitch.conf"); - if (!def_ignore_local_sudoers) + /* Set global defaults */ + /* XXX - error out early if no sources can be opened */ + for (nss = nss_base; *nss != SUDO_NSS_LAST; nss++) { +#ifdef HAVE_LDAP + /* LDAP defaults must come first due to def_ignore_local_sudoers */ + if (ldap_conn == NULL && ISSET(*nss, SUDO_NSS_LDAP)) { + if ((ldap_conn = sudo_ldap_open()) != NULL) + sudo_ldap_update_defaults(ldap_conn); + /* XXX - was: break; */ + } else #endif - { - /* Parse sudoers and set any defaults listed in it. */ - if (parse_sudoers(_PATH_SUDOERS) || parse_error) - log_error(0, "parse error in %s near line %d", errorfile, errorlineno); - if (!update_defaults(SKIP_CMND)) - log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); + if (ISSET(*nss, SUDO_NSS_FILES)) { + if (def_ignore_local_sudoers) + continue; + /* Parse sudoers and upate defaults from it. */ + if (parse_sudoers(_PATH_SUDOERS) || parse_error) + log_error(0, "parse error in %s near line %d", errorfile, + errorlineno); + if (!update_defaults(SKIP_CMND)) + log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); + } } /* XXX - collect post-sudoers parse settings into a function */ @@ -325,13 +340,27 @@ main(argc, argv, envp) cmnd_status = set_cmnd(sudo_mode); + for (nss = nss_base; *nss != SUDO_NSS_LAST; nss++) { + if (ISSET(*nss, SUDO_NSS_FILES)) { + if (def_ignore_local_sudoers) + continue; + rc = sudoers_lookup(pwflag); + } #ifdef HAVE_LDAP - if (ldap_conn != NULL) - validated = sudo_ldap_check(ldap_conn, pwflag); - /* Fallback to sudoers if we are allowed to and we aren't validated. */ - if (!def_ignore_local_sudoers && !ISSET(validated, VALIDATE_OK)) + else if (ISSET(*nss, SUDO_NSS_LDAP)) + rc = sudo_ldap_check(ldap_conn, pwflag); #endif - validated = sudoers_lookup(pwflag); + + /* XXX - rethink this logic */ + if (validated == 0 || ISSET(rc, VALIDATE_OK)) + validated = rc; + else if (ISSET(rc, VALIDATE_NOT_OK) && ISSET(validated, VALIDATE_NOT_OK)) + validated |= rc; + + /* Handle [NOTFOUND=return] */ + if (!ISSET(rc, VALIDATE_OK) && ISSET(*nss, SUDO_NSS_RETURN)) + break; + } if (safe_cmnd == NULL) safe_cmnd = estrdup(user_cmnd); diff --git a/sudo.h b/sudo.h index 1aedf0b48..70ebcba1b 100644 --- a/sudo.h +++ b/sudo.h @@ -30,6 +30,7 @@ #include "error.h" #include "defaults.h" #include "logging.h" +#include "sudo_nss.h" /* * Info pertaining to the invoking user.