From: Todd C. Miller Date: Mon, 31 Dec 2007 12:39:52 +0000 (+0000) Subject: Use nsswitch to hide some sudoers vs. ldap implementation details X-Git-Tag: SUDO_1_7_0~290 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ae2ae34528601975ddda7f244ddd21f9cf33ce76;p=sudo Use nsswitch to hide some sudoers vs. ldap implementation details and reduce the number of #ifdef LDAP TODO: fix display routines and error handling --- diff --git a/Makefile.in b/Makefile.in index 5a37d02ff..bb9b152e8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -157,8 +157,8 @@ BINFILES= ChangeLog HISTORY LICENSE README TODO TROUBLESHOOTING \ BINSPECIAL= INSTALL.binary Makefile.binary.in libtool SUDODEP = $(srcdir)/sudo.h $(srcdir)/compat.h $(srcdir)/defaults.h \ - $(srcdir)/error.h $(srcdir)/logging.h $(devdir)/def_data.h \ - pathnames.h config.h + $(srcdir)/error.h $(srcdir)/list.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(devdir)/def_data.h pathnames.h config.h AUTHDEP = $(SUDODEP) $(authdir)/sudo_auth.h diff --git a/ldap.c b/ldap.c index 70f419366..af657ac2a 100644 --- a/ldap.c +++ b/ldap.c @@ -115,7 +115,7 @@ struct ldap_config_table { }; /* ldap configuration structure */ -struct ldap_config { +static struct ldap_config { int port; int version; int debug; @@ -145,7 +145,7 @@ struct ldap_config { char *krb5_ccname; } ldap_conf; -struct ldap_config_table ldap_conf_table[] = { +static struct ldap_config_table ldap_conf_table[] = { { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug }, { "host", CONF_STR, FALSE, -1, &ldap_conf.host }, { "port", CONF_INT, FALSE, -1, &ldap_conf.port }, @@ -217,6 +217,17 @@ struct ldap_config_table ldap_conf_table[] = { { NULL } }; +/* XXX - add display_cmnd and display_privs */ +struct sudo_nss sudo_nss_ldap = { + &sudo_nss_ldap, + NULL, + sudo_ldap_open, + sudo_ldap_close, + sudo_ldap_parse, + sudo_ldap_setdefs, + sudo_ldap_lookup +}; + /* * Walk through search results and return TRUE if we have a matching * netgroup, else FALSE. @@ -1146,9 +1157,11 @@ sudo_ldap_set_options(ld) /* * Open a connection to the LDAP server. + * Returns 0 on success and non-zero on failure. */ -void * -sudo_ldap_open() +int +sudo_ldap_open(nss) + struct sudo_nss *nss; { LDAP *ld; const char *old_ccname = user_ccname; @@ -1158,7 +1171,7 @@ sudo_ldap_open() #endif if (!sudo_ldap_read_config()) - return(NULL); + return(-1); #ifdef HAVE_LDAPSSL_INIT if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { @@ -1170,7 +1183,7 @@ sudo_ldap_open() if (rc != LDAP_SUCCESS) { warningx("unable to initialize SSL cert and key db: %s", ldapssl_err2string(rc)); - return(NULL); + return(-1); } } #endif /* HAVE_LDAPSSL_INIT */ @@ -1182,7 +1195,7 @@ sudo_ldap_open() rc = ldap_initialize(&ld, ldap_conf.uri); if (rc != LDAP_SUCCESS) { warningx("unable to initialize LDAP: %s", ldap_err2string(rc)); - return(NULL); + return(-1); } } else #endif /* HAVE_LDAP_INITIALIZE */ @@ -1198,20 +1211,20 @@ sudo_ldap_open() #endif if (ld == NULL) { warning("unable to initialize LDAP"); - return(NULL); + return(-1); } } /* Set LDAP options */ if (sudo_ldap_set_options(ld) < 0) - return(NULL); + return(-1); if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { #ifdef HAVE_LDAP_START_TLS_S rc = ldap_start_tls_s(ld, NULL, NULL); if (rc != LDAP_SUCCESS) { warningx("ldap_start_tls_s(): %s", ldap_err2string(rc)); - return(NULL); + return(-1); } DPRINTF(("ldap_start_tls_s() ok"), 1); #else @@ -1251,7 +1264,7 @@ sudo_ldap_open() } if (rc != LDAP_SUCCESS) { warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc)); - return(NULL); + return(-1); } DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1); } else @@ -1260,22 +1273,26 @@ sudo_ldap_open() /* Actually connect */ if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) { warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc)); - return(NULL); + return(-1); } DPRINTF(("ldap_simple_bind_s() ok"), 1); } - return((void *) ld); + nss->handle = ld; + return(0); } -void -sudo_ldap_update_defaults(v) - void *v; +int +sudo_ldap_setdefs(nss) + struct sudo_nss *nss; { - LDAP *ld = (LDAP *) v; + LDAP *ld = (LDAP *) nss->handle; LDAPMessage *entry = NULL, *result = NULL; /* used for searches */ int rc; /* temp return value */ + if (ld == NULL) + return(-1); + rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, "cn=defaults", NULL, 0, &result); if (rc == 0 && (entry = ldap_first_entry(ld, result))) { @@ -1286,17 +1303,19 @@ sudo_ldap_update_defaults(v) if (result) ldap_msgfree(result); + + return(0); } /* * like sudoers_lookup() - only LDAP style */ int -sudo_ldap_check(v, pwflag) - void *v; +sudo_ldap_lookup(nss, pwflag) + struct sudo_nss *nss; int pwflag; { - LDAP *ld = (LDAP *) v; + LDAP *ld = (LDAP *) nss->handle; LDAPMessage *entry = NULL, *result = NULL; /* used for searches */ char *filt; /* used to parse attributes */ int do_netgr, rc, ret; /* temp/final return values */ @@ -1452,10 +1471,22 @@ done: /* * shut down LDAP connection */ -void -sudo_ldap_close(v) - void *v; +int +sudo_ldap_close(nss) + struct sudo_nss *nss; { - if (v != NULL) - ldap_unbind_s((LDAP *) v); + if (nss->handle != NULL) + ldap_unbind_s((LDAP *) nss->handle); + nss->handle = NULL; + return(0); +} + +/* + * STUB + */ +int +sudo_ldap_parse(nss) + struct sudo_nss *nss; +{ + return(0); } diff --git a/list.c b/list.c index 89b715ed2..695523b91 100644 --- a/list.c +++ b/list.c @@ -30,7 +30,6 @@ #endif /* STDC_HEADERS */ #include "sudo.h" -#include "list.h" #ifndef lint __unused static const char rcsid[] = "$Sudo$"; diff --git a/parse.c b/parse.c index 5d7cd908d..cbf116574 100644 --- a/parse.c +++ b/parse.c @@ -55,6 +55,24 @@ __unused static const char rcsid[] = "$Sudo$"; /* Characters that must be quoted in sudoers */ #define SUDOERS_QUOTED ":\\,=#\"" +/* sudoers nsswitch routines */ +struct sudo_nss sudo_nss_file = { + &sudo_nss_file, + NULL, + sudo_file_open, + sudo_file_close, + sudo_file_parse, + sudo_file_setdefs, + sudo_file_lookup +}; + +/* + * Parser externs. + */ +extern FILE *yyin; +extern char *errorfile; +extern int errorlineno, parse_error; + /* * Local prototypes. */ @@ -62,18 +80,59 @@ static void print_member __P((struct lbuf *, char *, int, int, int)); static void display_defaults __P((struct passwd *)); static void display_bound_defaults __P((int)); +int +sudo_file_open(nss) + struct sudo_nss *nss; +{ + /* XXX - open_sudoers() errors out if cannot open */ + nss->handle = open_sudoers(_PATH_SUDOERS, NULL); + return(nss->handle ? 0 : -1); +} + +int +sudo_file_close(nss) + struct sudo_nss *nss; +{ + /* XXX - free up data structures */ + if (nss->handle != NULL) { + fclose(nss->handle); + nss->handle = NULL; + yyin = NULL; + } + return(0); +} + /* * Parse the specified sudoers file. */ int -parse_sudoers(path) - const char *path; +sudo_file_parse(nss) + struct sudo_nss *nss; { - extern FILE *yyin; + if (nss->handle == NULL) + return(-1); - yyin = open_sudoers(_PATH_SUDOERS, NULL); init_parser(_PATH_SUDOERS, 0); - return(yyparse()); + yyin = nss->handle; + /* XXX - log_error() is terminal */ + if (yyparse() != 0 || parse_error) { + log_error(0, "parse error in %s near line %d", errorfile, errorlineno); + return(-1); + } + return(0); +} + +int +sudo_file_setdefs(nss) + struct sudo_nss *nss; +{ + if (nss->handle == NULL) + return(-1); + + /* XXX - move guts of update_defaults here */ + if (!update_defaults(SKIP_CMND)) + return(-1); + return(0); } /* @@ -81,7 +140,8 @@ parse_sudoers(path) * allowed to run the specified command on this host as the target user. */ int -sudoers_lookup(pwflag) +sudo_file_lookup(nss, pwflag) + struct sudo_nss *nss; int pwflag; { int validated, match, host_match, runas_match, cmnd_match; @@ -285,6 +345,7 @@ display_privs(v, pw) } lbuf_destroy(&lbuf); } + /* XXX - nss */ #ifdef HAVE_LDAP if (v != NULL) sudo_ldap_display_privs(v, pw); @@ -434,6 +495,7 @@ display_cmnd(v, pw) int rval = 1; int host_match, runas_match, cmnd_match; + /* XXX - nss */ #ifdef HAVE_LDAP if (v != NULL) rval = sudo_ldap_display_cmnd(v, pw); diff --git a/parse.h b/parse.h index ab20de4bb..76395e8fe 100644 --- a/parse.h +++ b/parse.h @@ -20,8 +20,6 @@ #ifndef _SUDO_PARSE_H #define _SUDO_PARSE_H -#include "list.h" - #undef UNSPEC #define UNSPEC -1 #undef DENY diff --git a/sudo.c b/sudo.c index 9f3dde9b7..c70ed0013 100644 --- a/sudo.c +++ b/sudo.c @@ -150,7 +150,7 @@ char *login_style; sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; static char *runas_user; static char *runas_group; -static void *ldap_conn; +static struct sudo_nss_list *snl; int main(argc, argv, envp) @@ -165,7 +165,7 @@ main(argc, argv, envp) extern char *malloc_options; malloc_options = "AFGJPR"; #endif - const unsigned char *nss, *nss_base; + struct sudo_nss *nss; #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); @@ -267,31 +267,14 @@ main(argc, argv, envp) init_vars(sudo_mode, envp); /* XXX - move this later? */ /* 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"); + snl = read_nss(_PATH_NSSWITCH_CONF); /* 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 - 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"); - } + tq_foreach_fwd(snl, nss) { + /* XXX - remove from tailq if open or parse fails? */ + if (nss->open(nss) == 0 && nss->parse(nss) == 0) + nss->setdefs(nss); } /* XXX - collect post-sudoers parse settings into a function */ @@ -340,16 +323,11 @@ 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 - else if (ISSET(*nss, SUDO_NSS_LDAP)) - rc = sudo_ldap_check(ldap_conn, pwflag); -#endif + tq_foreach_fwd(snl, nss) { + /* XXX - should lookup check handle instead? */ + if (!nss->handle) + continue; + rc = nss->lookup(nss, pwflag); /* XXX - rethink this logic */ if (validated == 0 || ISSET(rc, VALIDATE_OK)) @@ -358,7 +336,7 @@ main(argc, argv, envp) validated |= rc; /* Handle [NOTFOUND=return] */ - if (!ISSET(rc, VALIDATE_OK) && ISSET(*nss, SUDO_NSS_RETURN)) + if (!ISSET(rc, VALIDATE_OK) && nss->ret_notfound) break; } if (safe_cmnd == NULL) @@ -443,16 +421,13 @@ main(argc, argv, envp) log_auth(validated, 1); if (sudo_mode == MODE_CHECK) - rc = display_cmnd(ldap_conn, list_pw ? list_pw : sudo_user.pw); + rc = display_cmnd(NULL, list_pw ? list_pw : sudo_user.pw); else if (sudo_mode == MODE_LIST) - display_privs(ldap_conn, list_pw ? list_pw : sudo_user.pw); + display_privs(NULL, list_pw ? list_pw : sudo_user.pw); -#ifdef HAVE_LDAP - if (ldap_conn != NULL) { - sudo_ldap_close(ldap_conn); - ldap_conn = NULL; - } -#endif + /* Cleanup sudoers sources */ + tq_foreach_fwd(snl, nss) + nss->close(nss); /* Deferred exit due to sudo_ldap_close() */ if (sudo_mode == MODE_VALIDATE || sudo_mode == MODE_CHECK || @@ -1382,16 +1357,14 @@ void cleanup(gotsignal) int gotsignal; { + struct sudo_nss *nss; + if (!gotsignal) { + tq_foreach_fwd(snl, nss) + nss->close(nss); sudo_endpwent(); sudo_endgrent(); } -#ifdef HAVE_LDAP - if (ldap_conn != NULL) { - sudo_ldap_close(ldap_conn); - ldap_conn = NULL; - } -#endif } /* diff --git a/sudo.h b/sudo.h index 70ebcba1b..43f46578d 100644 --- a/sudo.h +++ b/sudo.h @@ -27,8 +27,9 @@ #include #include #include "compat.h" -#include "error.h" #include "defaults.h" +#include "error.h" +#include "list.h" #include "logging.h" #include "sudo_nss.h" @@ -225,15 +226,21 @@ char *tgetpass __P((const char *, int, int)); int find_path __P((char *, char **, struct stat *, char *)); void check_user __P((int)); void verify_user __P((struct passwd *, char *)); -int sudoers_lookup __P((int)); -int parse_sudoers __P((const char *)); #ifdef HAVE_LDAP -int sudo_ldap_check __P((void *, int)); void sudo_ldap_display_privs __P((void *, struct passwd *)); int sudo_ldap_display_cmnd __P((void *, struct passwd *)); -void sudo_ldap_update_defaults __P((void *)); -void *sudo_ldap_open __P((void)); -void sudo_ldap_close __P((void *)); +int sudo_ldap_open __P((struct sudo_nss *)); +int sudo_ldap_close __P((struct sudo_nss *)); +int sudo_ldap_setdefs __P((struct sudo_nss *)); +int sudo_ldap_lookup __P((struct sudo_nss *, int)); +int sudo_ldap_parse __P((struct sudo_nss *)); +#endif +#if 1 +int sudo_file_open __P((struct sudo_nss *)); +int sudo_file_close __P((struct sudo_nss *)); +int sudo_file_setdefs __P((struct sudo_nss *)); +int sudo_file_lookup __P((struct sudo_nss *, int)); +int sudo_file_parse __P((struct sudo_nss *)); #endif void set_perms __P((int)); void remove_timestamp __P((int));