]> granicus.if.org Git - sudo/commitdiff
Use nsswitch to hide some sudoers vs. ldap implementation details
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 31 Dec 2007 12:39:52 +0000 (12:39 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 31 Dec 2007 12:39:52 +0000 (12:39 +0000)
and reduce the number of #ifdef LDAP
TODO: fix display routines and error handling

Makefile.in
ldap.c
list.c
parse.c
parse.h
sudo.c
sudo.h

index 5a37d02ff7e192a830b214ea9e58bb0fbb820af1..bb9b152e88095a1c4c8bdbd70c9f33e28e1454f8 100644 (file)
@@ -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 70f419366b5236af657dea986463ffbfb81a449a..af657ac2a4041af6193121d4d64149d47361b2d5 100644 (file)
--- 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 89b715ed287cc2a63929aa10529a028af91317f2..695523b91af8d7cdd2cc55511dd9fa80f2b0c78c 100644 (file)
--- 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 5d7cd908d83377e639505380493bc9802afdc025..cbf11657454bf16f349422e6caa7cb5055d45464 100644 (file)
--- 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 ab20de4bbecdcc7a45e0ee52d038b7ea72eb85f6..76395e8fe6d12f5815c7ae47de669ecfce2b71ca 100644 (file)
--- 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 9f3dde9b7ed1aa0146b6b5c6bd7429f97c1f869d..c70ed00137f66af5b89b963d608db91cd72d4443 100644 (file)
--- 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 70ebcba1b672d12351587a48496df4505a6d1e1d..43f46578d655b0a329dfc6d1e8463f1195481ee3 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -27,8 +27,9 @@
 #include <pathnames.h>
 #include <limits.h>
 #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));