]> granicus.if.org Git - sudo/commitdiff
Move common bits of ldap to sudoers conversion into ldap_common.c
authorTodd C. Miller <Todd.Miller@sudo.ws>
Sat, 10 Feb 2018 01:21:40 +0000 (18:21 -0700)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Sat, 10 Feb 2018 01:21:40 +0000 (18:21 -0700)
and use it in sssd.c.

12 files changed:
MANIFEST
configure
configure.ac
mkdep.pl
plugins/sudoers/Makefile.in
plugins/sudoers/gram.c
plugins/sudoers/gram.y
plugins/sudoers/ldap.c
plugins/sudoers/ldap_common.c [new file with mode: 0644]
plugins/sudoers/parse.h
plugins/sudoers/sssd.c
plugins/sudoers/sudo_ldap.h [new file with mode: 0644]

index 1ce3f8091a52233d9564f607974f554dbc6aeaf0..d4ec2d6d71ec3c934287c47d6e6da1ff0d620689 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -303,6 +303,7 @@ plugins/sudoers/iolog.c
 plugins/sudoers/iolog.h
 plugins/sudoers/iolog_path.c
 plugins/sudoers/ldap.c
+plugins/sudoers/ldap_common.c
 plugins/sudoers/linux_audit.c
 plugins/sudoers/linux_audit.h
 plugins/sudoers/locale.c
@@ -550,6 +551,7 @@ plugins/sudoers/solaris_audit.h
 plugins/sudoers/sssd.c
 plugins/sudoers/starttime.c
 plugins/sudoers/stubs.c
+plugins/sudoers/sudo_ldap.h
 plugins/sudoers/sudo_nss.c
 plugins/sudoers/sudo_nss.h
 plugins/sudoers/sudo_printf.c
index a368b0aeb253277c46bf0f055556698eb1103be8..900203b2ce464270c1cf286161459800582060f5 100755 (executable)
--- a/configure
+++ b/configure
@@ -4617,6 +4617,10 @@ fi
 if test "${with_sssd+set}" = set; then :
   withval=$with_sssd; case $with_sssd in
     yes)       SUDOERS_OBJS="${SUDOERS_OBJS} sssd.lo"
+               case "$SUDOERS_OBJS" in
+                   *ldap_common.lo*) ;;
+                   *) SUDOERS_OBJS="${SUDOERS_OBJS} ldap_common.lo";;
+               esac
                $as_echo "#define HAVE_SSSD 1" >>confdefs.h
 
                ;;
        with_ldap=yes
     fi
     SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo"
+    case "$SUDOERS_OBJS" in
+       *ldap_common.lo*) ;;
+       *) SUDOERS_OBJS="${SUDOERS_OBJS} ldap_common.lo";;
+    esac
     LDAP=""
 
     _LIBS="$LIBS"
index a008d323a0433e6f1c8358a70794c3b5c6b39f4f..4731be4e7056671509730604f7dbaab547286dda 100644 (file)
@@ -379,6 +379,10 @@ dnl
 AC_ARG_WITH(sssd, [AS_HELP_STRING([--with-sssd], [enable SSSD support])],
 [case $with_sssd in
     yes)       SUDOERS_OBJS="${SUDOERS_OBJS} sssd.lo"
+               case "$SUDOERS_OBJS" in
+                   *ldap_common.lo*) ;;
+                   *) SUDOERS_OBJS="${SUDOERS_OBJS} ldap_common.lo";;
+               esac
                AC_DEFINE(HAVE_SSSD)
                ;;
     no)                ;;
@@ -3727,6 +3731,10 @@ if test ${with_ldap-'no'} != "no"; then
        with_ldap=yes
     fi
     SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo"
+    case "$SUDOERS_OBJS" in
+       *ldap_common.lo*) ;;
+       *) SUDOERS_OBJS="${SUDOERS_OBJS} ldap_common.lo";;
+    esac
     LDAP=""
 
     _LIBS="$LIBS"
index fd51d8f7211f67a339528ffe147762f40042a028..4b4d85fbd24113fd86ba8a02ef0aa94bd8925643 100755 (executable)
--- a/mkdep.pl
+++ b/mkdep.pl
@@ -79,7 +79,7 @@ sub mkdep {
     $makefile =~ s:\@DEV\@::g;
     $makefile =~ s:\@COMMON_OBJS\@:aix.lo event_poll.lo event_select.lo:;
     $makefile =~ s:\@SUDO_OBJS\@:openbsd.o preload.o selinux.o sesh.o solaris.o:;
-    $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo solaris_audit.lo sssd.lo:;
+    $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo ldap_common.lo solaris_audit.lo sssd.lo:;
     # XXX - fill in AUTH_OBJS from contents of the auth dir instead
     $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
     $makefile =~ s:\@FILEDIGEST\@:filedigest.lo filedigest_openssl.lo filedigest_gcrypt.lo:;
index 232fa2754ba83c4ceec96f160dbfdf1bde91cef0..f6ea6f40c7f600a0b384e50c28fc4038762b69e7 100644 (file)
@@ -710,13 +710,12 @@ cvtsudoers.o: $(srcdir)/cvtsudoers.c $(devdir)/def_data.h $(devdir)/gram.h \
               $(incdir)/compat/getopt.h $(incdir)/compat/stdbool.h \
               $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
               $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
-              $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
-              $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
-              $(srcdir)/defaults.h $(srcdir)/interfaces.h $(srcdir)/logging.h \
-              $(srcdir)/parse.h $(srcdir)/redblack.h $(srcdir)/sudo_nss.h \
-              $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
-              $(srcdir)/sudoers_version.h $(top_builddir)/config.h \
-              $(top_builddir)/pathnames.h
+              $(incdir)/sudo_gettext.h $(incdir)/sudo_lbuf.h \
+              $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
+              $(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
+              $(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+              $(srcdir)/sudoers_debug.h $(srcdir)/sudoers_version.h \
+              $(top_builddir)/config.h $(top_builddir)/pathnames.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/cvtsudoers.c
 cvtsudoers_json.o: $(srcdir)/cvtsudoers_json.c $(devdir)/def_data.h \
                    $(devdir)/gram.h $(incdir)/compat/stdbool.h \
@@ -736,9 +735,9 @@ cvtsudoers_ldif.o: $(srcdir)/cvtsudoers_ldif.c $(devdir)/def_data.h \
                    $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
                    $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
                    $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
-                   $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
-                   $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
-                   $(top_builddir)/pathnames.h
+                   $(srcdir)/redblack.h $(srcdir)/sudo_nss.h \
+                   $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
+                   $(top_builddir)/config.h $(top_builddir)/pathnames.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/cvtsudoers_ldif.c
 dce.lo: $(authdir)/dce.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
         $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
@@ -955,15 +954,27 @@ kerb5.lo: $(authdir)/kerb5.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
           $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
           $(top_builddir)/config.h $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(authdir)/kerb5.c
-ldap.lo: $(srcdir)/ldap.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
-         $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
-         $(incdir)/sudo_dso.h $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
-         $(incdir)/sudo_lbuf.h $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
-         $(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
-         $(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+ldap.lo: $(srcdir)/ldap.c $(devdir)/def_data.h $(devdir)/gram.h \
+         $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+         $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_dso.h \
+         $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h $(incdir)/sudo_lbuf.h \
+         $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+         $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
+         $(srcdir)/sudo_ldap.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
          $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
          $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/ldap.c
+ldap_common.lo: $(srcdir)/ldap_common.c $(devdir)/def_data.h $(devdir)/gram.h \
+                $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+                $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
+                $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
+                $(incdir)/sudo_lbuf.h $(incdir)/sudo_plugin.h \
+                $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+                $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
+                $(srcdir)/sudo_ldap.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+                $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
+                $(top_builddir)/pathnames.h
+       $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/ldap_common.c
 linux_audit.lo: $(srcdir)/linux_audit.c $(devdir)/def_data.h \
                 $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
                 $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
@@ -1181,12 +1192,13 @@ solaris_audit.lo: $(srcdir)/solaris_audit.c $(devdir)/def_data.h \
                   $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
                   $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/solaris_audit.c
-sssd.lo: $(srcdir)/sssd.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
-         $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
-         $(incdir)/sudo_dso.h $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
-         $(incdir)/sudo_lbuf.h $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \
-         $(incdir)/sudo_util.h $(srcdir)/defaults.h $(srcdir)/logging.h \
-         $(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
+sssd.lo: $(srcdir)/sssd.c $(devdir)/def_data.h $(devdir)/gram.h \
+         $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+         $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_dso.h \
+         $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h $(incdir)/sudo_lbuf.h \
+         $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+         $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
+         $(srcdir)/sudo_ldap.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
          $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
          $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sssd.c
index bb7c3ae45cb437505b5443148af9d15111058944..dca7253ae511b04fca304ee6536ce884ca96afbe 100644 (file)
@@ -864,70 +864,76 @@ free_members(struct member_list *members)
 }
 
 void
-free_userspec(struct userspec *us)
+free_privilege(struct privilege *priv)
 {
-    struct privilege *priv;
-
-    free_members(&us->users);
-    while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
-       struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
-       struct cmndspec *cs;
-       struct defaults *def;
+    struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
+    struct cmndspec *cs;
+    struct defaults *def;
 #ifdef HAVE_SELINUX
-       char *role = NULL, *type = NULL;
+    char *role = NULL, *type = NULL;
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
-       char *privs = NULL, *limitprivs = NULL;
+    char *privs = NULL, *limitprivs = NULL;
 #endif /* HAVE_PRIV_SET */
 
-       TAILQ_REMOVE(&us->privileges, priv, entries);
-       free(priv->ldap_role);
-       free_members(&priv->hostlist);
-       while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
-           TAILQ_REMOVE(&priv->cmndlist, cs, entries);
+    free(priv->ldap_role);
+    free_members(&priv->hostlist);
+    while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
+       TAILQ_REMOVE(&priv->cmndlist, cs, entries);
 #ifdef HAVE_SELINUX
-           /* Only free the first instance of a role/type. */
-           if (cs->role != role) {
-               role = cs->role;
-               free(cs->role);
-           }
-           if (cs->type != type) {
-               type = cs->type;
-               free(cs->type);
-           }
+       /* Only free the first instance of a role/type. */
+       if (cs->role != role) {
+           role = cs->role;
+           free(cs->role);
+       }
+       if (cs->type != type) {
+           type = cs->type;
+           free(cs->type);
+       }
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
-           /* Only free the first instance of privs/limitprivs. */
-           if (cs->privs != privs) {
-               privs = cs->privs;
-               free(cs->privs);
-           }
-           if (cs->limitprivs != limitprivs) {
-               limitprivs = cs->limitprivs;
-               free(cs->limitprivs);
-           }
+       /* Only free the first instance of privs/limitprivs. */
+       if (cs->privs != privs) {
+           privs = cs->privs;
+           free(cs->privs);
+       }
+       if (cs->limitprivs != limitprivs) {
+           limitprivs = cs->limitprivs;
+           free(cs->limitprivs);
+       }
 #endif /* HAVE_PRIV_SET */
-           /* Only free the first instance of runas user/group lists. */
-           if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
-               runasuserlist = cs->runasuserlist;
-               free_members(runasuserlist);
-               free(runasuserlist);
-           }
-           if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
-               runasgrouplist = cs->runasgrouplist;
-               free_members(runasgrouplist);
-               free(runasgrouplist);
-           }
-           free_member(cs->cmnd);
-           free(cs);
+       /* Only free the first instance of runas user/group lists. */
+       if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
+           runasuserlist = cs->runasuserlist;
+           free_members(runasuserlist);
+           free(runasuserlist);
        }
-       while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) {
-           TAILQ_REMOVE(&priv->defaults, def, entries);
-           free(def->var);
-           free(def->val);
-           free(def);
+       if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
+           runasgrouplist = cs->runasgrouplist;
+           free_members(runasgrouplist);
+           free(runasgrouplist);
        }
-       free(priv);
+       free_member(cs->cmnd);
+       free(cs);
+    }
+    while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) {
+       TAILQ_REMOVE(&priv->defaults, def, entries);
+       free(def->var);
+       free(def->val);
+       free(def);
+    }
+    free(priv);
+}
+
+void
+free_userspec(struct userspec *us)
+{
+    struct privilege *priv;
+
+    free_members(&us->users);
+    while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
+       TAILQ_REMOVE(&us->privileges, priv, entries);
+       free_privilege(priv);
     }
     rcstr_delref(us->file);
     free(us);
@@ -1010,7 +1016,7 @@ init_options(struct command_options *opts)
     opts->limitprivs = NULL;
 #endif
 }
-#line 961 "gram.c"
+#line 967 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -2135,7 +2141,7 @@ case 116:
                            }
                        }
 break;
-#line 2086 "gram.c"
+#line 2092 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index a85c3027bfa4346566350327d95cbe4f384abee6..5bc1003d379793fc6e5a20e46e8abff30acb37c3 100644 (file)
@@ -1092,70 +1092,76 @@ free_members(struct member_list *members)
 }
 
 void
-free_userspec(struct userspec *us)
+free_privilege(struct privilege *priv)
 {
-    struct privilege *priv;
-
-    free_members(&us->users);
-    while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
-       struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
-       struct cmndspec *cs;
-       struct defaults *def;
+    struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
+    struct cmndspec *cs;
+    struct defaults *def;
 #ifdef HAVE_SELINUX
-       char *role = NULL, *type = NULL;
+    char *role = NULL, *type = NULL;
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
-       char *privs = NULL, *limitprivs = NULL;
+    char *privs = NULL, *limitprivs = NULL;
 #endif /* HAVE_PRIV_SET */
 
-       TAILQ_REMOVE(&us->privileges, priv, entries);
-       free(priv->ldap_role);
-       free_members(&priv->hostlist);
-       while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
-           TAILQ_REMOVE(&priv->cmndlist, cs, entries);
+    free(priv->ldap_role);
+    free_members(&priv->hostlist);
+    while ((cs = TAILQ_FIRST(&priv->cmndlist)) != NULL) {
+       TAILQ_REMOVE(&priv->cmndlist, cs, entries);
 #ifdef HAVE_SELINUX
-           /* Only free the first instance of a role/type. */
-           if (cs->role != role) {
-               role = cs->role;
-               free(cs->role);
-           }
-           if (cs->type != type) {
-               type = cs->type;
-               free(cs->type);
-           }
+       /* Only free the first instance of a role/type. */
+       if (cs->role != role) {
+           role = cs->role;
+           free(cs->role);
+       }
+       if (cs->type != type) {
+           type = cs->type;
+           free(cs->type);
+       }
 #endif /* HAVE_SELINUX */
 #ifdef HAVE_PRIV_SET
-           /* Only free the first instance of privs/limitprivs. */
-           if (cs->privs != privs) {
-               privs = cs->privs;
-               free(cs->privs);
-           }
-           if (cs->limitprivs != limitprivs) {
-               limitprivs = cs->limitprivs;
-               free(cs->limitprivs);
-           }
+       /* Only free the first instance of privs/limitprivs. */
+       if (cs->privs != privs) {
+           privs = cs->privs;
+           free(cs->privs);
+       }
+       if (cs->limitprivs != limitprivs) {
+           limitprivs = cs->limitprivs;
+           free(cs->limitprivs);
+       }
 #endif /* HAVE_PRIV_SET */
-           /* Only free the first instance of runas user/group lists. */
-           if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
-               runasuserlist = cs->runasuserlist;
-               free_members(runasuserlist);
-               free(runasuserlist);
-           }
-           if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
-               runasgrouplist = cs->runasgrouplist;
-               free_members(runasgrouplist);
-               free(runasgrouplist);
-           }
-           free_member(cs->cmnd);
-           free(cs);
+       /* Only free the first instance of runas user/group lists. */
+       if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
+           runasuserlist = cs->runasuserlist;
+           free_members(runasuserlist);
+           free(runasuserlist);
        }
-       while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) {
-           TAILQ_REMOVE(&priv->defaults, def, entries);
-           free(def->var);
-           free(def->val);
-           free(def);
+       if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
+           runasgrouplist = cs->runasgrouplist;
+           free_members(runasgrouplist);
+           free(runasgrouplist);
        }
-       free(priv);
+       free_member(cs->cmnd);
+       free(cs);
+    }
+    while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) {
+       TAILQ_REMOVE(&priv->defaults, def, entries);
+       free(def->var);
+       free(def->val);
+       free(def);
+    }
+    free(priv);
+}
+
+void
+free_userspec(struct userspec *us)
+{
+    struct privilege *priv;
+
+    free_members(&us->users);
+    while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
+       TAILQ_REMOVE(&us->privileges, priv, entries);
+       free_privilege(priv);
     }
     rcstr_delref(us->file);
     free(us);
index 65e3eb46fa1078bdd3d09dd59a8444367295f80a..ed852065479f6a96347b6a05796d29990fa176d1 100644 (file)
@@ -61,6 +61,7 @@
 #include "parse.h"
 #include "gram.h"
 #include "sudo_lbuf.h"
+#include "sudo_ldap.h"
 #include "sudo_dso.h"
 
 /* Older Netscape LDAP SDKs don't prototype ldapssl_set_strength() */
@@ -715,28 +716,6 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
     debug_return_bool(ret);
 }
 
-/*
- * Returns true if the string pointed to by valp begins with an
- * odd number of '!' characters.  Intervening blanks are ignored.
- * Stores the address of the string after '!' removal in valp.
- */
-static bool
-sudo_ldap_is_negated(char **valp)
-{
-    char *val = *valp;
-    bool ret = false;
-    debug_decl(sudo_ldap_is_negated, SUDOERS_DEBUG_LDAP)
-
-    while (*val == '!') {
-       ret = !ret;
-       do {
-           val++;
-       } while (isblank((unsigned char)*val));
-    }
-    *valp = val;
-    debug_return_bool(ret);
-}
-
 /*
 * Walk through search results and return true if we have a
 * host match, else false.
@@ -933,67 +912,6 @@ sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry)
     debug_return_bool(group_matched != false && user_matched != false);
 }
 
-static struct sudo_digest *
-sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest)
-{
-    char *ep, *cp = *cmnd;
-    int digest_type = SUDO_DIGEST_INVALID;
-    debug_decl(sudo_ldap_extract_digest, SUDOERS_DEBUG_LDAP)
-
-    /*
-     * Check for and extract a digest prefix, e.g.
-     * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
-     */
-    if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
-       switch (cp[3]) {
-       case '2':
-           if (cp[4] == '2' && cp[5] == '4')
-               digest_type = SUDO_DIGEST_SHA224;
-           else if (cp[4] == '5' && cp[5] == '6')
-               digest_type = SUDO_DIGEST_SHA256;
-           break;
-       case '3':
-           if (cp[4] == '8' && cp[5] == '4')
-               digest_type = SUDO_DIGEST_SHA384;
-           break;
-       case '5':
-           if (cp[4] == '1' && cp[5] == '2')
-               digest_type = SUDO_DIGEST_SHA512;
-           break;
-       }
-       if (digest_type != SUDO_DIGEST_INVALID) {
-           cp += 6;
-           while (isblank((unsigned char)*cp))
-               cp++;
-           if (*cp == ':') {
-               cp++;
-               while (isblank((unsigned char)*cp))
-                   cp++;
-               ep = cp;
-               while (*ep != '\0' && !isblank((unsigned char)*ep))
-                   ep++;
-               if (*ep != '\0') {
-                   digest->digest_type = digest_type;
-                   digest->digest_str = strndup(cp, (size_t)(ep - cp));
-                   if (digest->digest_str == NULL) {
-                       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                       debug_return_ptr(NULL);
-                   }
-                   cp = ep + 1;
-                   while (isblank((unsigned char)*cp))
-                       cp++;
-                   *cmnd = cp;
-                   DPRINTF1("%s digest %s for %s",
-                       digest_type_to_name(digest_type),
-                       digest->digest_str, cp);
-                   debug_return_ptr(digest);
-               }
-           }
-       }
-    }
-    debug_return_ptr(NULL);
-}
-
 /*
  * Walk through search results and return true if we have a command match,
  * false if disallowed and UNSPEC if not matched.
@@ -1097,58 +1015,6 @@ sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
     debug_return_int(ret);
 }
 
-/*
- * Parse an option string into a defaults structure.
- * The members of def are pointers into optstr (which is modified).
- */
-static int
-sudo_ldap_parse_option(char *optstr, char **varp, char **valp)
-{
-    char *cp, *val = NULL;
-    char *var = optstr;
-    int op;
-    debug_decl(sudo_ldap_parse_option, SUDOERS_DEBUG_LDAP)
-
-    DPRINTF2("ldap sudoOption: '%s'", optstr);
-
-    /* check for equals sign past first char */
-    cp = strchr(var, '=');
-    if (cp > var) {
-       val = cp + 1;
-       op = cp[-1];    /* peek for += or -= cases */
-       if (op == '+' || op == '-') {
-           /* case var+=val or var-=val */
-           cp--;
-       } else {
-           /* case var=val */
-           op = true;
-       }
-       /* Trim whitespace between var and operator. */
-       while (cp > var && isblank((unsigned char)cp[-1]))
-           cp--;
-       /* Truncate variable name. */
-       *cp = '\0';
-       /* Trim leading whitespace from val. */
-       while (isblank((unsigned char)*val))
-           val++;
-       /* Strip double quotes if present. */
-       if (*val == '"') {
-           char *ep = val + strlen(val);
-           if (ep != val && ep[-1] == '"') {
-               val++;
-               ep[-1] = '\0';
-           }
-       }
-    } else {
-       /* Boolean value, either true or false. */
-       op = sudo_ldap_is_negated(&var) ? false : true;
-    }
-    *varp = var;
-    *valp = val;
-
-    debug_return_int(op);
-}
-
 /*
  * Read sudoOption and modify the defaults as we go.  This is used once
  * from the cn=defaults entry and also once when a final sudoRole is matched.
@@ -2467,73 +2333,14 @@ sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
     debug_return_int(0);
 }
 
-/*
- * Convert an array of struct berval to a member list.
- */
-static struct member_list *
-bv_to_member_list(struct berval **bv)
-{
-    struct member_list *members;
-    struct berval **p;
-    struct member *m;
-    debug_decl(bv_to_member_list, SUDOERS_DEBUG_LDAP)
-
-    if ((members = calloc(1, sizeof(*members))) == NULL)
-       return NULL;
-    TAILQ_INIT(members);                      
-
-    for (p = bv; *p != NULL; p++) {
-       if ((m = calloc(1, sizeof(*m))) == NULL)
-           goto bad;
-
-       char *val = (*p)->bv_val;
-       switch (val[0]) {
-       case '\0':
-           /* Empty RunAsUser means run as the invoking user. */
-           m->type = MYSELF;
-           break;
-       case 'A':
-           if (strcmp(val, "ALL") == 0) {
-               m->type = ALL;
-               break;
-           }
-           /* FALLTHROUGH */
-       default:
-           m->type = WORD;
-           m->name = strdup(val);
-           if (m->name == NULL) {
-               free(m);
-               goto bad;
-           }
-           break;
-       }
-       TAILQ_INSERT_TAIL(members, m, entries);
-    }
-    debug_return_ptr(members);
-bad:
-    while ((m = TAILQ_FIRST(members)) != NULL) {
-       TAILQ_REMOVE(members, m, entries);
-       free(m->name);
-       free(m);
-    }
-    free(members);
-    debug_return_ptr(NULL);
-}
-
 static struct userspec_list *
-ldap2sudoers(LDAP *ld, struct ldap_result *lres)
+ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
 {
     struct userspec_list *ldap_userspecs;
-    struct cmndspec *cmndspec = NULL;
-    struct sudo_command *c;
-    struct privilege *priv;
     struct userspec *us;
     struct member *m;
-    struct berval **bv, **p;
-    struct berval **cmnd_bv, **cmnd; /* XXX - naming */
-    char *cn;
     unsigned int i;
-    debug_decl(ldap2sudoers, SUDOERS_DEBUG_LDAP)
+    debug_decl(ldap_to_sudoers, SUDOERS_DEBUG_LDAP)
 
     if ((ldap_userspecs = calloc(1, sizeof(*ldap_userspecs))) == NULL)
        goto oom;
@@ -2554,217 +2361,63 @@ ldap2sudoers(LDAP *ld, struct ldap_result *lres)
 
     /* Treat each sudoRole as a separate privilege. */
     for (i = 0; i < lres->nentries; i++) {
-       struct cmndspec *prev_cmndspec = NULL;
        LDAPMessage *entry = lres->entries[i].entry;
+       struct berval **cmnds, **runasusers, **runasgroups;
+       struct berval **opts, **notbefore, **notafter;
+       struct privilege *priv;
+       char *cn;
 
        /* Ignore sudoRole without sudoCommand. */
-       cmnd_bv = ldap_get_values_len(ld, entry, "sudoCommand");
-       if (cmnd_bv == NULL)
+       cmnds = ldap_get_values_len(ld, entry, "sudoCommand");
+       if (cmnds == NULL)
            continue;
 
-       if ((priv = calloc(1, sizeof(*priv))) == NULL)
-           goto oom;
-       TAILQ_INIT(&priv->hostlist);
-       TAILQ_INIT(&priv->cmndlist);
-       TAILQ_INIT(&priv->defaults);
-       TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
-
        /* Get the entry's dn for long format printing. */
        cn = sudo_ldap_get_first_rdn(ld, entry);
-       priv->ldap_role = strdup(cn ? cn : "UNKNOWN");
-       if (cn != NULL)
-           ldap_memfree(cn);
-       if (priv->ldap_role == NULL)
-           goto oom;
 
-       /* The host has already matched, use ALL as wildcard. */
-       if ((m = calloc(1, sizeof(*m))) == NULL)
-           goto oom;
-       m->type = ALL;
-       TAILQ_INSERT_TAIL(&priv->hostlist, m, entries);
-
-       /* Parse sudoCommands and add to cmndlist. */
-       for (cmnd = cmnd_bv; *cmnd != NULL; cmnd++) {
-           char *args;
-
-           /* Allocate storage upfront. */
-           cmndspec = calloc(1, sizeof(*cmndspec));
-           c = calloc(1, sizeof(*c));
-           m = calloc(1, sizeof(*m));
-           if (cmndspec == NULL || c == NULL || m == NULL) {
-               free(c);
-               free(m);
-               goto oom;
-           }
-           TAILQ_INSERT_TAIL(&priv->cmndlist, cmndspec, entries);
-
-           /* Initialize cmndspec */
-           TAGS_INIT(cmndspec->tags);
-           cmndspec->notbefore = UNSPEC;
-           cmndspec->notafter = UNSPEC;
-           cmndspec->timeout = UNSPEC;
-
-           /* Fill in command. */
-           if ((args = strpbrk((*cmnd)->bv_val, " \t")) != NULL) {
-               *args++ = '\0';
-               if ((c->args = strdup(args)) == NULL) {
-                   free(c);
-                   free(m);
-                   goto oom;
-               }
-           }
-           if ((c->cmnd = strdup((*cmnd)->bv_val)) == NULL) {
-               free(c->args);
-               free(c);
-               free(m);
-               goto oom;
-           }
-           m->type = COMMAND;
-           m->name = (char *)c;
-           cmndspec->cmnd = m;
-
-           if (prev_cmndspec != NULL) {
-               /* Inherit values from prior cmndspec */
-               cmndspec->runasuserlist = prev_cmndspec->runasuserlist;
-               cmndspec->runasgrouplist = prev_cmndspec->runasgrouplist;
-               cmndspec->notbefore = prev_cmndspec->notbefore;
-               cmndspec->notafter = prev_cmndspec->notafter;
-               cmndspec->tags = prev_cmndspec->tags;
-           } else {
-               /* Parse sudoRunAsUser / sudoRunAs */
-               bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
-               if (bv == NULL)
-                   bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
-               if (bv != NULL) {
-                   cmndspec->runasuserlist = bv_to_member_list(bv);
-                   if (cmndspec->runasuserlist == NULL)
-                       goto oom;
-                   ldap_value_free_len(bv);
-                   bv = NULL;
-               }
-
-               /* Parse sudoRunAsGroup */
-               bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
-               if (bv != NULL) {
-                   cmndspec->runasgrouplist = bv_to_member_list(bv);
-                   if (cmndspec->runasgrouplist == NULL)
-                       goto oom;
-                   ldap_value_free_len(bv);
-                   bv = NULL;
-               }
+       /* Get sudoRunAsUser / sudoRunAsGroup */
+       runasusers = ldap_get_values_len(ld, entry, "sudoRunAsUser");
+       if (runasusers == NULL)
+           runasusers = ldap_get_values_len(ld, entry, "sudoRunAs");
+       runasgroups = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
 
-               /* Parse sudoNotBefore */
-               bv = ldap_get_values_len(ld, entry, "sudoNotBefore");
-               if (bv != NULL) {
-                   /* Only takes the last entry. */
-                   for (p = bv; *p != NULL; p++) {
-                       cmndspec->notbefore = parse_gentime((*p)->bv_val);
-                   }
-                   ldap_value_free_len(bv);
-                   bv = NULL;
-               }
+       /* Get sudoNotBefore / sudoNotAfter */
+       notbefore = ldap_get_values_len(ld, entry, "sudoNotBefore");
+       notafter = ldap_get_values_len(ld, entry, "sudoNotAfter");
 
-               /* Parse sudoNotAfter */
-               bv = ldap_get_values_len(ld, entry, "sudoNotAfter");
-               if (bv != NULL) {
-                   /* Only takes the last entry. */
-                   for (p = bv; *p != NULL; p++) {
-                       cmndspec->notafter = parse_gentime((*p)->bv_val);
-                   }
-                   ldap_value_free_len(bv);
-                   bv = NULL;
-               }
+       /* Parse sudoOptions. */
+       opts = ldap_get_values_len(ld, entry, "sudoOption");
 
-               /* Parse sudoOptions. */
-               bv = ldap_get_values_len(ld, entry, "sudoOption");
-               if (bv != NULL) {
-                   for (p = bv; *p != NULL; p++) {
-                       char *var, *val;
-                       int op;
-
-                       op = sudo_ldap_parse_option((*p)->bv_val, &var, &val);
-                       if (strcmp(var, "command_timeout") == 0) {
-                           if (op == '=')
-                               cmndspec->timeout = parse_timeout(val);
-#ifdef HAVE_SELINUX
-                       } else if (strcmp(var, "role") == 0) {
-                           if (op == '=') {
-                               if ((cmndspec->role = strdup(val)) == NULL)
-                                   goto oom;
-                           }
-                       } else if (strcmp(var, "type") == 0) {
-                           if (op == '=') {
-                               if ((cmndspec->type = strdup(val)) == NULL)
-                                   goto oom;
-                           }
-#endif /* HAVE_SELINUX */
-#ifdef HAVE_PRIV_SET
-                       } else if (strcmp(var, "privs") == 0) {
-                           if (op == '=') {
-                               if ((cmndspec->privs = strdup(val)) == NULL)
-                                   goto oom;
-                           }
-                       } else if (strcmp(val, "limitprivs") == 0) {
-                           if (op == '=') {
-                               if ((cmndspec->limitprivs = strdup(val)) == NULL)
-                                   goto oom;
-                           }
-#endif /* HAVE_PRIV_SET */
-                       } else if (long_list) {
-                           struct defaults *def = calloc(1, sizeof(*def));
-                           if (def == NULL)
-                               goto oom;
-                           def->op = op;
-                           if ((def->var = strdup(var)) == NULL) {
-                               free(def);
-                               goto oom;
-                           }
-                           if (val != NULL) {
-                               if ((def->val = strdup(val)) == NULL) {
-                                   free(def->var);
-                                   free(def);
-                                   goto oom;
-                               }
-                           }
-                           TAILQ_INSERT_TAIL(&priv->defaults, def, entries);
-                       } else {
-                           /* Convert to tags. */
-                           if (op != true && op != false)
-                               continue;
-                           if (strcmp(var, "authenticate") == 0) {
-                               cmndspec->tags.nopasswd = op == false;
-                           } else if (strcmp(var, "sudoedit_follow") == 0) {
-                               cmndspec->tags.follow = op == true;
-                           } else if (strcmp(var, "noexec") == 0) {
-                               cmndspec->tags.noexec = op == true;
-                           } else if (strcmp(var, "setenv") == 0) {
-                               cmndspec->tags.setenv = op == true;
-                           } else if (strcmp(var, "mail_all_cmnds") == 0 ||
-                               strcmp(var, "mail_always") == 0) {
-                               cmndspec->tags.send_mail = op == true;
-                           }
-                       }
-                   }
-                   ldap_value_free_len(bv);
-                   bv = NULL;
-               }
+       priv = sudo_ldap_role_to_priv(cn, runasusers, runasgroups,
+           cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL,
+           notafter ? notafter[0]->bv_val : NULL,
+           sizeof(struct berval *), offsetof(struct berval, bv_val));
 
-               /* So we can inherit previous values. */
-               prev_cmndspec = cmndspec;
-           }
-       }
-       ldap_value_free_len(cmnd_bv);
-       cmnd_bv = NULL;
+       /* Cleanup */
+       if (cn != NULL)
+           ldap_memfree(cn);
+       if (cmnds != NULL)
+           ldap_value_free_len(cmnds);
+       if (runasusers != NULL)
+           ldap_value_free_len(runasusers);
+       if (runasgroups != NULL)
+           ldap_value_free_len(runasgroups);
+       if (opts != NULL)
+           ldap_value_free_len(opts);
+       if (notbefore != NULL)
+           ldap_value_free_len(notbefore);
+       if (notafter != NULL)
+           ldap_value_free_len(notafter);
+
+       if (priv == NULL)
+           goto oom;
+       TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
     }
 
     debug_return_ptr(ldap_userspecs);
 
 oom:
     sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-    if (cmnd_bv != NULL)
-       ldap_value_free_len(cmnd_bv);
-    if (bv != NULL)
-       ldap_value_free_len(bv);
     if (ldap_userspecs != NULL) {
        while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
            TAILQ_REMOVE(ldap_userspecs, us, entries);
@@ -2799,7 +2452,7 @@ sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
        goto done;
 
     /* Convert to sudoers parse tree. */
-    if ((ldap_userspecs = ldap2sudoers(ld, lres)) == NULL) {
+    if ((ldap_userspecs = ldap_to_sudoers(ld, lres)) == NULL) {
        ret = -1;
        goto done;
     }
diff --git a/plugins/sudoers/ldap_common.c b/plugins/sudoers/ldap_common.c
new file mode 100644 (file)
index 0000000..fa14308
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2013, 2016, 2018 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * This code is derived from software contributed by Aaron Spangler.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <ctype.h>
+#ifdef HAVE_LBER_H
+# include <lber.h>
+#endif
+#include <ldap.h>
+
+#include "sudoers.h"
+#include "parse.h"
+#include "gram.h"
+#include "sudo_lbuf.h"
+#include "sudo_ldap.h"
+
+/*
+ * Returns true if the string pointed to by valp begins with an
+ * odd number of '!' characters.  Intervening blanks are ignored.
+ * Stores the address of the string after '!' removal in valp.
+ */
+bool
+sudo_ldap_is_negated(char **valp)
+{
+    char *val = *valp;
+    bool ret = false;
+    debug_decl(sudo_ldap_is_negated, SUDOERS_DEBUG_LDAP)
+
+    while (*val == '!') {
+       ret = !ret;
+       do {
+           val++;
+       } while (isblank((unsigned char)*val));
+    }
+    *valp = val;
+    debug_return_bool(ret);
+}
+
+/*
+ * Parse an option string into a defaults structure.
+ * The members of def are pointers into optstr (which is modified).
+ */
+int
+sudo_ldap_parse_option(char *optstr, char **varp, char **valp)
+{
+    char *cp, *val = NULL;
+    char *var = optstr;
+    int op;
+    debug_decl(sudo_ldap_parse_option, SUDOERS_DEBUG_LDAP)
+
+    /* check for equals sign past first char */
+    cp = strchr(var, '=');
+    if (cp > var) {
+       val = cp + 1;
+       op = cp[-1];    /* peek for += or -= cases */
+       if (op == '+' || op == '-') {
+           /* case var+=val or var-=val */
+           cp--;
+       } else {
+           /* case var=val */
+           op = true;
+       }
+       /* Trim whitespace between var and operator. */
+       while (cp > var && isblank((unsigned char)cp[-1]))
+           cp--;
+       /* Truncate variable name. */
+       *cp = '\0';
+       /* Trim leading whitespace from val. */
+       while (isblank((unsigned char)*val))
+           val++;
+       /* Strip double quotes if present. */
+       if (*val == '"') {
+           char *ep = val + strlen(val);
+           if (ep != val && ep[-1] == '"') {
+               val++;
+               ep[-1] = '\0';
+           }
+       }
+    } else {
+       /* Boolean value, either true or false. */
+       op = sudo_ldap_is_negated(&var) ? false : true;
+    }
+    *varp = var;
+    *valp = val;
+
+    debug_return_int(op);
+}
+
+/*
+ * Convert an array to a member list.
+ * The caller is responsible for freeing the returned struct member_list.
+ */
+static struct member_list *
+array_to_member_list(void *a, size_t ele_size, size_t str_off)
+{
+    struct member_list *members;
+    struct member *m;
+    debug_decl(bv_to_member_list, SUDOERS_DEBUG_LDAP)
+
+    if ((members = calloc(1, sizeof(*members))) == NULL)
+       return NULL;
+    TAILQ_INIT(members);                      
+
+    for (;*((char **)a) != NULL; a = (char *)a + ele_size) {
+       char *val = *(char **)(*((char **)a) + str_off);
+
+       if ((m = calloc(1, sizeof(*m))) == NULL)
+           goto bad;
+
+       switch (val[0]) {
+       case '\0':
+           /* Empty RunAsUser means run as the invoking user. */
+           m->type = MYSELF;
+           break;
+       case 'A':
+           if (strcmp(val, "ALL") == 0) {
+               m->type = ALL;
+               break;
+           }
+           /* FALLTHROUGH */
+       default:
+           m->type = WORD;
+           m->name = strdup(val);
+           if (m->name == NULL) {
+               free(m);
+               goto bad;
+           }
+           break;
+       }
+       TAILQ_INSERT_TAIL(members, m, entries);
+    }
+    debug_return_ptr(members);
+bad:
+    while ((m = TAILQ_FIRST(members)) != NULL) {
+       TAILQ_REMOVE(members, m, entries);
+       free(m->name);
+       free(m);
+    }
+    free(members);
+    debug_return_ptr(NULL);
+}
+
+/*
+ * Convert an LDAP sudoRole to a sudoers privilege.
+ * Pass in struct berval ** for LDAP or char *** for SSSD.
+ */
+struct privilege *
+sudo_ldap_role_to_priv(const char *cn, void *runasusers, void *runasgroups,
+    void *cmnds, void *opts, const char *notbefore,
+    const char *notafter, size_t ele_size, size_t str_off)
+{
+    struct cmndspec *cmndspec = NULL;
+    struct cmndspec *prev_cmndspec = NULL;
+    struct sudo_command *c;
+    struct privilege *priv;
+    struct member *m;
+    debug_decl(sudo_ldap_role_to_priv, SUDOERS_DEBUG_LDAP)
+
+    if ((priv = calloc(1, sizeof(*priv))) == NULL)
+       goto oom;
+    TAILQ_INIT(&priv->hostlist);
+    TAILQ_INIT(&priv->cmndlist);
+    TAILQ_INIT(&priv->defaults);
+
+    priv->ldap_role = strdup(cn ? cn : "UNKNOWN");
+    if (priv->ldap_role == NULL)
+       goto oom;
+
+    /* The host has already matched, use ALL as wildcard. */
+    if ((m = calloc(1, sizeof(*m))) == NULL)
+       goto oom;
+    m->type = ALL;
+    TAILQ_INSERT_TAIL(&priv->hostlist, m, entries);
+
+    /*
+     * Parse sudoCommands and add to cmndlist.
+     * The convoluted pointer arithmetic is to support passing in
+     * either a struct berval ** or a char ***.
+     * An interator would probably be better.
+     */
+    for (;*((char **)cmnds) != NULL; cmnds = (char *)cmnds + ele_size) {
+       char *cmnd = *(char **)(*((char **)cmnds) + str_off);
+       char *args;
+
+       /* Allocate storage upfront. */
+       cmndspec = calloc(1, sizeof(*cmndspec));
+       c = calloc(1, sizeof(*c));
+       m = calloc(1, sizeof(*m));
+       if (cmndspec == NULL || c == NULL || m == NULL) {
+           free(cmndspec);
+           free(c);
+           free(m);
+           goto oom;
+       }
+       TAILQ_INSERT_TAIL(&priv->cmndlist, cmndspec, entries);
+
+       /* Initialize cmndspec */
+       TAGS_INIT(cmndspec->tags);
+       cmndspec->notbefore = UNSPEC;
+       cmndspec->notafter = UNSPEC;
+       cmndspec->timeout = UNSPEC;
+
+       /* Fill in command. */
+       if ((args = strpbrk(cmnd, " \t")) != NULL) {
+           *args++ = '\0';
+           if ((c->args = strdup(args)) == NULL) {
+               free(c);
+               free(m);
+               goto oom;
+           }
+       }
+       if ((c->cmnd = strdup(cmnd)) == NULL) {
+           free(c->args);
+           free(c);
+           free(m);
+           goto oom;
+       }
+       m->type = COMMAND;
+       m->name = (char *)c;
+       cmndspec->cmnd = m;
+
+       if (prev_cmndspec != NULL) {
+           /* Inherit values from prior cmndspec */
+           cmndspec->runasuserlist = prev_cmndspec->runasuserlist;
+           cmndspec->runasgrouplist = prev_cmndspec->runasgrouplist;
+           cmndspec->notbefore = prev_cmndspec->notbefore;
+           cmndspec->notafter = prev_cmndspec->notafter;
+           cmndspec->tags = prev_cmndspec->tags;
+       } else {
+           /* Parse sudoRunAsUser / sudoRunAs */
+           if (runasusers != NULL) {
+               cmndspec->runasuserlist =
+                   array_to_member_list(runasusers, ele_size, str_off);
+               if (cmndspec->runasuserlist == NULL)
+                   goto oom;
+           }
+
+           /* Parse sudoRunAsGroup */
+           if (runasgroups != NULL) {
+               cmndspec->runasgrouplist =
+                   array_to_member_list(runasgroups, ele_size, str_off);
+               if (cmndspec->runasgrouplist == NULL)
+                   goto oom;
+           }
+
+           /* Parse sudoNotBefore / sudoNotAfter */
+           if (notbefore != NULL)
+               cmndspec->notbefore = parse_gentime(notbefore);
+           if (notafter != NULL)
+               cmndspec->notbefore = parse_gentime(notafter);
+
+           /* Parse sudoOptions. */
+           if (opts != NULL) {
+               for (; *((char **)opts) != NULL; opts = (char *)opts + ele_size) {
+                   char *opt = *(char **)(*((char **)opts) + str_off);
+                   char *var, *val;
+                   int op;
+
+                   op = sudo_ldap_parse_option(opt, &var, &val);
+                   if (strcmp(var, "command_timeout") == 0) {
+                       if (op == '=')
+                           cmndspec->timeout = parse_timeout(val);
+#ifdef HAVE_SELINUX
+                   } else if (strcmp(var, "role") == 0) {
+                       if (op == '=') {
+                           if ((cmndspec->role = strdup(val)) == NULL)
+                               goto oom;
+                       }
+                   } else if (strcmp(var, "type") == 0) {
+                       if (op == '=') {
+                           if ((cmndspec->type = strdup(val)) == NULL)
+                               goto oom;
+                       }
+#endif /* HAVE_SELINUX */
+#ifdef HAVE_PRIV_SET
+                   } else if (strcmp(var, "privs") == 0) {
+                       if (op == '=') {
+                           if ((cmndspec->privs = strdup(val)) == NULL)
+                               goto oom;
+                       }
+                   } else if (strcmp(val, "limitprivs") == 0) {
+                       if (op == '=') {
+                           if ((cmndspec->limitprivs = strdup(val)) == NULL)
+                               goto oom;
+                       }
+#endif /* HAVE_PRIV_SET */
+                   } else if (long_list) {
+                       struct defaults *def = calloc(1, sizeof(*def));
+                       if (def == NULL)
+                           goto oom;
+                       def->op = op;
+                       if ((def->var = strdup(var)) == NULL) {
+                           free(def);
+                           goto oom;
+                       }
+                       if (val != NULL) {
+                           if ((def->val = strdup(val)) == NULL) {
+                               free(def->var);
+                               free(def);
+                               goto oom;
+                           }
+                       }
+                       TAILQ_INSERT_TAIL(&priv->defaults, def, entries);
+                   } else {
+                       /* Convert to tags. */
+                       if (op != true && op != false)
+                           continue;
+                       if (strcmp(var, "authenticate") == 0) {
+                           cmndspec->tags.nopasswd = op == false;
+                       } else if (strcmp(var, "sudoedit_follow") == 0) {
+                           cmndspec->tags.follow = op == true;
+                       } else if (strcmp(var, "noexec") == 0) {
+                           cmndspec->tags.noexec = op == true;
+                       } else if (strcmp(var, "setenv") == 0) {
+                           cmndspec->tags.setenv = op == true;
+                       } else if (strcmp(var, "mail_all_cmnds") == 0 ||
+                           strcmp(var, "mail_always") == 0) {
+                           cmndspec->tags.send_mail = op == true;
+                       }
+                   }
+               }
+           }
+
+           /* So we can inherit previous values. */
+           prev_cmndspec = cmndspec;
+       }
+    }
+    debug_return_ptr(priv);
+
+oom:
+    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    if (priv != NULL)
+       free_privilege(priv);
+    debug_return_ptr(NULL);
+}
+
+/*
+ * If a digest prefix is present, fills in struct sudo_digest
+ * and returns a pointer to it, updating cmnd to point to the
+ * command after the digest.
+ */
+struct sudo_digest *
+sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest)
+{
+    char *ep, *cp = *cmnd;
+    int digest_type = SUDO_DIGEST_INVALID;
+    debug_decl(sudo_ldap_check_command, SUDOERS_DEBUG_LDAP)
+
+    /*
+     * Check for and extract a digest prefix, e.g.
+     * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
+     */
+    if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
+       switch (cp[3]) {
+       case '2':
+           if (cp[4] == '2' && cp[5] == '4')
+               digest_type = SUDO_DIGEST_SHA224;
+           else if (cp[4] == '5' && cp[5] == '6')
+               digest_type = SUDO_DIGEST_SHA256;
+           break;
+       case '3':
+           if (cp[4] == '8' && cp[5] == '4')
+               digest_type = SUDO_DIGEST_SHA384;
+           break;
+       case '5':
+           if (cp[4] == '1' && cp[5] == '2')
+               digest_type = SUDO_DIGEST_SHA512;
+           break;
+       }
+       if (digest_type != SUDO_DIGEST_INVALID) {
+           cp += 6;
+           while (isblank((unsigned char)*cp))
+               cp++;
+           if (*cp == ':') {
+               cp++;
+               while (isblank((unsigned char)*cp))
+                   cp++;
+               ep = cp;
+               while (*ep != '\0' && !isblank((unsigned char)*ep))
+                   ep++;
+               if (*ep != '\0') {
+                   digest->digest_type = digest_type;
+                   digest->digest_str = strndup(cp, (size_t)(ep - cp));
+                   if (digest->digest_str == NULL) {
+                       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+                       debug_return_ptr(NULL);
+                   }
+                   cp = ep + 1;
+                   while (isblank((unsigned char)*cp))
+                       cp++;
+                   *cmnd = cp;
+                   sudo_debug_printf(SUDO_DEBUG_INFO,
+                       "%s digest %s for %s",
+                       digest_type_to_name(digest_type),
+                       digest->digest_str, cp);
+                   debug_return_ptr(digest);
+               }
+           }
+       }
+    }
+    debug_return_ptr(NULL);
+}
index 275071eaa1ec52dd4061304fc492c66bb1ca7f13..f37a838c11a806ca1540164de76fae9790a03e9d 100644 (file)
@@ -259,6 +259,7 @@ bool init_aliases(void);
 bool init_parser(const char *path, bool quiet);
 void free_member(struct member *m);
 void free_members(struct member_list *members);
+void free_privilege(struct privilege *priv);
 void free_userspec(struct userspec *us);
 
 /* match_addr.c */
index 398f9a7588500fdae936ba9367c9360c5b3079aa..9278c7cd6e171928df1a23f28343b0a5e6286aab 100644 (file)
@@ -42,7 +42,9 @@
 
 #include "sudoers.h"
 #include "parse.h"
+#include "gram.h"
 #include "sudo_lbuf.h"
+#include "sudo_ldap.h"
 #include "sudo_dso.h"
 
 /* SSSD <--> SUDO interface - do not change */
@@ -540,28 +542,6 @@ bad:
     debug_return_int(-1);
 }
 
-/*
- * Returns true if the string pointed to by valp begins with an
- * odd number of '!' characters.  Intervening blanks are ignored.
- * Stores the address of the string after '!' removal in valp.
- */
-static bool
-sudo_sss_is_negated(char **valp)
-{
-    char *val = *valp;
-    bool ret = false;
-    debug_decl(sudo_sss_is_negated, SUDOERS_DEBUG_SSSD)
-
-    while (*val == '!') {
-       ret = !ret;
-       do {
-           val++;
-       } while (isblank((unsigned char)*val));
-    }
-    *valp = val;
-    debug_return_bool(ret);
-}
-
 static int
 sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
 {
@@ -804,7 +784,7 @@ sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
        val = val_array[i];
        sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
 
-       negated = sudo_sss_is_negated(&val);
+       negated = sudo_ldap_is_negated(&val);
 
        /* match any or address or netgroup or hostname */
        if (strcmp(val, "ALL") == 0 || addr_matches(val) ||
@@ -1009,7 +989,7 @@ sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
        var = val_array[i];
        sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
 
-       negated = sudo_sss_is_negated(&var);
+       negated = sudo_ldap_is_negated(&var);
        if (strcmp(var, option) == 0)
            ret = negated ? false : true;
     }
@@ -1019,73 +999,6 @@ sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
     debug_return_int(ret);
 }
 
-/*
- * If a digest prefix is present, fills in struct sudo_digest
- * and returns a pointer to it, updating cmnd to point to the
- * command after the digest.
- */
-static struct sudo_digest *
-sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
-{
-    char *ep, *cp = *cmnd;
-    int digest_type = SUDO_DIGEST_INVALID;
-    debug_decl(sudo_sss_check_command, SUDOERS_DEBUG_LDAP)
-
-    /*
-     * Check for and extract a digest prefix, e.g.
-     * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
-     */
-    if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
-       switch (cp[3]) {
-       case '2':
-           if (cp[4] == '2' && cp[5] == '4')
-               digest_type = SUDO_DIGEST_SHA224;
-           else if (cp[4] == '5' && cp[5] == '6')
-               digest_type = SUDO_DIGEST_SHA256;
-           break;
-       case '3':
-           if (cp[4] == '8' && cp[5] == '4')
-               digest_type = SUDO_DIGEST_SHA384;
-           break;
-       case '5':
-           if (cp[4] == '1' && cp[5] == '2')
-               digest_type = SUDO_DIGEST_SHA512;
-           break;
-       }
-       if (digest_type != SUDO_DIGEST_INVALID) {
-           cp += 6;
-           while (isblank((unsigned char)*cp))
-               cp++;
-           if (*cp == ':') {
-               cp++;
-               while (isblank((unsigned char)*cp))
-                   cp++;
-               ep = cp;
-               while (*ep != '\0' && !isblank((unsigned char)*ep))
-                   ep++;
-               if (*ep != '\0') {
-                   digest->digest_type = digest_type;
-                   digest->digest_str = strndup(cp, (size_t)(ep - cp));
-                   if (digest->digest_str == NULL) {
-                       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-                       debug_return_ptr(NULL);
-                   }
-                   cp = ep + 1;
-                   while (isblank((unsigned char)*cp))
-                       cp++;
-                   *cmnd = cp;
-                   sudo_debug_printf(SUDO_DEBUG_INFO,
-                       "%s digest %s for %s",
-                       digest_type_to_name(digest_type),
-                       digest->digest_str, cp);
-                   debug_return_ptr(digest);
-               }
-           }
-       }
-    }
-    debug_return_ptr(NULL);
-}
-
 /*
  * Walk through search results and return true if we have a command match,
  * false if disallowed and UNSPEC if not matched.
@@ -1132,11 +1045,11 @@ sudo_sss_check_command(struct sudo_sss_handle *handle,
        }
 
         /* check for sha-2 digest */
-       allowed_digest = sudo_sss_extract_digest(&val, &digest);
+       allowed_digest = sudo_ldap_extract_digest(&val, &digest);
 
        /* check for !command */
        allowed_cmnd = val;
-       negated = sudo_sss_is_negated(&allowed_cmnd);
+       negated = sudo_ldap_is_negated(&allowed_cmnd);
 
        /* split optional args away from command */
        allowed_args = strchr(allowed_cmnd, ' ');
@@ -1165,58 +1078,6 @@ sudo_sss_check_command(struct sudo_sss_handle *handle,
     debug_return_int(ret);
 }
 
-/*
- * Parse an option string into a defaults structure.
- * The members of def are pointers into optstr (which is modified).
- */
-static int
-sudo_sss_parse_option(char *optstr, char **varp, char **valp)
-{
-    char *cp, *val = NULL;
-    char *var = optstr;
-    int op;
-    debug_decl(sudo_sss_parse_option, SUDOERS_DEBUG_SSSD)
-
-    sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", optstr);
-
-    /* check for equals sign past first char */
-    cp = strchr(var, '=');
-    if (cp > var) {
-       val = cp + 1;
-       op = cp[-1];    /* peek for += or -= cases */
-       if (op == '+' || op == '-') {
-           /* case var+=val or var-=val */
-           cp--;
-       } else {
-           /* case var=val */
-           op = true;
-       }
-       /* Trim whitespace between var and operator. */
-       while (cp > var && isblank((unsigned char)cp[-1]))
-           cp--;
-       /* Truncate variable name. */
-       *cp = '\0';
-       /* Trim leading whitespace from val. */
-       while (isblank((unsigned char)*val))
-           val++;
-       /* Strip double quotes if present. */
-       if (*val == '"') {
-           char *ep = val + strlen(val);
-           if (ep != val && ep[-1] == '"') {
-               val++;
-               ep[-1] = '\0';
-           }
-       }
-    } else {
-       /* Boolean value, either true or false. */
-       op = sudo_sss_is_negated(&var) ? false : true;
-    }
-    *varp = var;
-    *valp = val;
-
-    debug_return_int(op);
-}
-
 static bool
 sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
 {
@@ -1263,7 +1124,7 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul
            sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
            goto done;
        }
-       op = sudo_sss_parse_option(copy, &var, &val);
+       op = sudo_ldap_parse_option(copy, &var, &val);
        early = is_early_default(var);
        if (early != NULL) {
            set_early_default(var, val, op,
@@ -1279,7 +1140,7 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul
            sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
            goto done;
        }
-       op = sudo_sss_parse_option(copy, &var, &val);
+       op = sudo_ldap_parse_option(copy, &var, &val);
        if (is_early_default(var) == NULL) {
            set_default(var, val, op,
                source ? source : "sudoRole UNKNOWN", 0, false);
@@ -1544,255 +1405,102 @@ sudo_sss_display_bound_defaults(struct sudo_nss *nss,
     debug_return_int(0);
 }
 
-static int
-sudo_sss_display_entry_long(struct sudo_sss_handle *handle,
-    struct sss_sudo_rule *rule, struct passwd *pw, struct sudo_lbuf *lbuf)
+static struct userspec_list *
+sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result)
 {
-    char **val_array = NULL;
-    bool no_runas_user = true;
-    int count = 0, i;
-    debug_decl(sudo_sss_display_entry_long, SUDOERS_DEBUG_SSSD);
-
-    switch (handle->fn_get_values(rule, "cn", &val_array)) {
-    case 0:
-       if (val_array[0] != NULL)
-           sudo_lbuf_append(lbuf, _("\nSSSD Role: %s\n"), val_array[0]);
-       handle->fn_free_values(val_array);
-       val_array = NULL;
-       break;
-    default:
-       sudo_lbuf_append(lbuf, _("\nSSSD Role: UNKNOWN\n"));
-    }
-
-    /* get the RunAsUser Values from the entry */
-    sudo_lbuf_append(lbuf, "    RunAsUsers: ");
-    switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
-    case 0:
-       for (i = 0; val_array[i] != NULL; ++i)
-           sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-       handle->fn_free_values(val_array);
-       no_runas_user = false;
-       break;
-    case ENOENT:
-       switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
-       case 0:
-           for (i = 0; val_array[i] != NULL; ++i)
-                sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-           handle->fn_free_values(val_array);
-           no_runas_user = false;
-           break;
-       case ENOENT:
-           sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-           break;
-       default:
-           sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAs): != 0");
-           debug_return_int(count);
-       }
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsUser): != 0");
-       debug_return_int(count);
-    }
+    struct userspec_list *sss_userspecs;
+    struct userspec *us;
+    struct member *m;
+    unsigned int i;
+    debug_decl(sss_to_sudoers, SUDOERS_DEBUG_SSSD)
 
-    /* get the RunAsGroup Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
-    case 0:
-       if (no_runas_user) {
-           /* finish printing sudoRunAs */
-           sudo_lbuf_append(lbuf, "%s", pw->pw_name);
-       }
-       sudo_lbuf_append(lbuf, "\n    RunAsGroups: ");
-       for (i = 0; val_array[i] != NULL; ++i)
-            sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-       handle->fn_free_values(val_array);
-       sudo_lbuf_append(lbuf, "\n");
-       break;
-    case ENOENT:
-       if (no_runas_user) {
-           /* finish printing sudoRunAs */
-           sudo_lbuf_append(lbuf, "%s", pw->pw_name);
-       }
-       sudo_lbuf_append(lbuf, "\n");
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoRunAsGroup): != 0");
-       debug_return_int(count);
-    }
+    if ((sss_userspecs = calloc(1, sizeof(*sss_userspecs))) == NULL)
+       goto oom;
+    TAILQ_INIT(sss_userspecs);
 
-    /* get the Option Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
-    case 0:
-       sudo_lbuf_append(lbuf, "    Options: ");
-       for (i = 0; val_array[i] != NULL; ++i)
-            sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-       handle->fn_free_values(val_array);
-       sudo_lbuf_append(lbuf, "\n");
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoOption): != 0");
-       debug_return_int(count);
-    }
+    /* We only have a single userspec */
+    if ((us = calloc(1, sizeof(*us))) == NULL)
+       goto oom;
+    TAILQ_INIT(&us->users);
+    TAILQ_INIT(&us->privileges);
+    TAILQ_INSERT_TAIL(sss_userspecs, us, entries);
 
-    /* Get the command values from the entry. */
-    switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
-    case 0:
-       sudo_lbuf_append(lbuf, _("    Commands:\n"));
-       for (i = 0; val_array[i] != NULL; ++i) {
-            sudo_lbuf_append(lbuf, "\t%s\n", val_array[i]);
-            count++;
-       }
-       handle->fn_free_values(val_array);
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoCommand): != 0");
-       debug_return_int(count);
-    }
+    /* The user has already matched, use ALL as wildcard. */
+    if ((m = calloc(1, sizeof(*m))) == NULL)
+       goto oom;
+    m->type = ALL;
+    TAILQ_INSERT_TAIL(&us->users, m, entries);
 
-    debug_return_int(count);
-}
+    /* Treat each sudoRole as a separate privilege. */
+    for (i = 0; i < sss_result->num_rules; i++) {
+       struct sss_sudo_rule *rule = sss_result->rules + i;
+       char **cmnds, **runasusers = NULL, **runasgroups = NULL;
+       char **opts = NULL, **notbefore = NULL, **notafter = NULL;
+       char **cn_array = NULL;
+       char *cn = NULL;
+       struct privilege *priv;
 
-static int
-sudo_sss_display_entry_short(struct sudo_sss_handle *handle,
-    struct sss_sudo_rule *rule, struct passwd *pw, struct sudo_lbuf *lbuf)
-{
-    char **val_array = NULL;
-    bool no_runas_user = true;
-    int count = 0, i;
-    debug_decl(sudo_sss_display_entry_short, SUDOERS_DEBUG_SSSD);
+       /* XXX - check for error vs. ENOENT */
 
-    sudo_lbuf_append(lbuf, "    (");
+       /* Ignore sudoRole without sudoCommand. */
+       if (handle->fn_get_values(rule, "sudoCommand", &cmnds) != 0)
+           continue;
 
-    /* get the RunAsUser Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoRunAsUser", &val_array)) {
-    case 0:
-       for (i = 0; val_array[i] != NULL; ++i)
-            sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-       handle->fn_free_values(val_array);
-       no_runas_user = false;
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result. Trying old style (sudoRunAs).");
-       /* try old style */
-       switch (handle->fn_get_values(rule, "sudoRunAs", &val_array)) {
-       case 0:
-           for (i = 0; val_array[i] != NULL; ++i)
-                sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-           handle->fn_free_values(val_array);
-           no_runas_user = false;
-           break;
-       case ENOENT:
-           sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-           break;
-       default:
-           sudo_debug_printf(SUDO_DEBUG_INFO,
-               "handle->fn_get_values(sudoRunAs): != 0");
-           debug_return_int(count);
-       }
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoRunAsUser): != 0");
-       debug_return_int(count);
-    }
+       /* Get the entry's dn for long format printing. */
+       if (handle->fn_get_values(rule, "cn", &cn_array) == 0)
+           cn = cn_array[0];
 
-    /* get the RunAsGroup Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoRunAsGroup", &val_array)) {
-    case 0:
-       if (no_runas_user) {
-           /* finish printing sudoRunAs */
-           sudo_lbuf_append(lbuf, "%s", pw->pw_name);
+       /* Get sudoRunAsUser / sudoRunAsGroup */
+       if (handle->fn_get_values(rule, "sudoRunAsUser", &runasusers) != 0) {
+           handle->fn_get_values(rule, "sudoRunAs", &runasusers);
        }
-       sudo_lbuf_append(lbuf, " : ");
-       for (i = 0; val_array[i] != NULL; ++i)
-            sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "", val_array[i]);
-       handle->fn_free_values(val_array);
-       break;
-    case ENOENT:
-       if (no_runas_user) {
-           /* finish printing sudoRunAs */
-           sudo_lbuf_append(lbuf, "%s", def_runas_default);
-       }
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoRunAsGroup): != 0");
-       debug_return_int(count);
+       handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups);
+
+       /* Get sudoNotBefore / sudoNotAfter */
+       handle->fn_get_values(rule, "sudoNotBefore", &notbefore);
+       handle->fn_get_values(rule, "sudoNotAfter", &notafter);
+
+       /* Parse sudoOptions. */
+       handle->fn_get_values(rule, "sudoOption", &opts);
+
+       priv = sudo_ldap_role_to_priv(cn, runasusers ? &runasusers : NULL,
+           runasgroups ? &runasgroups: NULL, &cmnds, opts ? &opts : NULL,
+           notbefore ? notbefore[0] : NULL, notafter ? notafter[0] : NULL,
+           sizeof(char **), 0);
+
+       /* Cleanup */
+       if (cn_array != NULL)
+           handle->fn_free_values(cn_array);
+       if (cmnds != NULL)
+           handle->fn_free_values(cmnds);
+       if (runasusers != NULL)
+           handle->fn_free_values(runasusers);
+       if (runasgroups != NULL)
+           handle->fn_free_values(runasgroups);
+       if (opts != NULL)
+           handle->fn_free_values(opts);
+       if (notbefore != NULL)
+           handle->fn_free_values(notbefore);
+       if (notafter != NULL)
+           handle->fn_free_values(notafter);
+
+       if (priv == NULL)
+           goto oom;
+       TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
     }
 
-    sudo_lbuf_append(lbuf, ") ");
+    debug_return_ptr(sss_userspecs);
 
-    /* get the Option Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
-    case 0:
-       for (i = 0; val_array[i] != NULL; ++i) {
-           char *val = val_array[i];
-           bool negated = sudo_sss_is_negated(&val);
-           if (strcmp(val, "authenticate") == 0)
-               sudo_lbuf_append(lbuf, negated ? "NOPASSWD: " : "PASSWD: ");
-           else if (strcmp(val, "sudoedit_follow") == 0)
-               sudo_lbuf_append(lbuf, negated ? "NOFOLLOW: " : "FOLLOW: ");
-           else if (strcmp(val, "noexec") == 0)
-               sudo_lbuf_append(lbuf, negated ? "EXEC: " : "NOEXEC: ");
-           else if (strcmp(val, "setenv") == 0)
-               sudo_lbuf_append(lbuf, negated ? "NOSETENV: " : "SETENV: ");
-           else if (strcmp(val, "mail_all_cmnds") == 0 || strcmp(val, "mail_always") == 0)
-               sudo_lbuf_append(lbuf, negated ? "NOMAIL: " : "MAIL: ");
-           else if (!negated && strncmp(val, "command_timeout=", 16) == 0)
-               sudo_lbuf_append(lbuf, "TIMEOUT=%s ", val + 16);
-#ifdef HAVE_SELINUX
-           else if (!negated && strncmp(val, "role=", 5) == 0)
-               sudo_lbuf_append(lbuf, "ROLE=%s ", val + 5);
-           else if (!negated && strncmp(val, "type=", 5) == 0)
-               sudo_lbuf_append(lbuf, "TYPE=%s ", val + 5);
-#endif /* HAVE_SELINUX */
-#ifdef HAVE_PRIV_SET
-           else if (!negated && strncmp(val, "privs=", 6) == 0)
-               sudo_lbuf_append(lbuf, "PRIVS=%s ", val + 6);
-           else if (!negated && strncmp(val, "limitprivs=", 11) == 0)
-               sudo_lbuf_append(lbuf, "LIMITPRIVS=%s ", val + 11);
-#endif /* HAVE_PRIV_SET */
+oom:
+    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    if (sss_userspecs != NULL) {
+       while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
+           TAILQ_REMOVE(sss_userspecs, us, entries);
+           free_userspec(us);
        }
-       handle->fn_free_values(val_array);
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoOption): != 0");
-       debug_return_int(count);
+       free(sss_userspecs);
     }
-
-    /* get the Command Values from the entry */
-    switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
-    case 0:
-       for (i = 0; val_array[i] != NULL; ++i) {
-           sudo_lbuf_append(lbuf, "%s%s", i != 0 ? ", " : "",
-               val_array[i][0] ? val_array[i] : user_name);
-           count++;
-       }
-       handle->fn_free_values(val_array);
-       break;
-    case ENOENT:
-       sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
-       break;
-    default:
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "handle->fn_get_values(sudoCommand): != 0");
-       debug_return_int(count);
-    }
-    sudo_lbuf_append(lbuf, "\n");
-
-    debug_return_int(count);
+    debug_return_ptr(NULL);
 }
 
 static int
@@ -1800,9 +1508,9 @@ sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
     struct sudo_lbuf *lbuf)
 {
     struct sudo_sss_handle *handle = nss->handle;
+    struct userspec_list *sss_userspecs = NULL;
     struct sss_sudo_result *sss_result = NULL;
-    struct sss_sudo_rule *rule;
-    unsigned int i, count = 0;
+    int ret = 0;
     debug_decl(sudo_sss_display_privs, SUDOERS_DEBUG_SSSD);
 
     if (handle == NULL)
@@ -1815,22 +1523,30 @@ sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
     sss_result = sudo_sss_result_get(nss, pw, NULL);
 
     if (sss_result == NULL)
-       debug_return_int(count);
+       debug_return_int(ret);
 
-    /* Display all matching entries. */
-    for (i = 0; i < sss_result->num_rules; ++i) {
-       rule = sss_result->rules + i;
-       if (long_list)
-           count += sudo_sss_display_entry_long(handle, rule, pw, lbuf);
-       else
-           count += sudo_sss_display_entry_short(handle, rule, pw, lbuf);
+    /* Convert to sudoers parse tree. */
+    if ((sss_userspecs = sss_to_sudoers(handle, sss_result)) == NULL) {
+       ret = -1;
+       goto done;
     }
 
-    handle->fn_free_result(sss_result);
+    /* Call common display code. */
+    ret = sudo_display_userspecs(sss_userspecs, pw, lbuf);
 
+done:
+    /* Cleanup */
+    handle->fn_free_result(sss_result);
+    if (sss_userspecs != NULL) {
+       struct userspec *us;
+       while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
+           TAILQ_REMOVE(sss_userspecs, us, entries);
+           free_userspec(us);
+       }
+       free(sss_userspecs);
+    }
     if (sudo_lbuf_error(lbuf))
        debug_return_int(-1);
-    debug_return_int(count);
+    debug_return_int(ret);
 }
-
 #endif /* HAVE_SSSD */
diff --git a/plugins/sudoers/sudo_ldap.h b/plugins/sudoers/sudo_ldap.h
new file mode 100644 (file)
index 0000000..8904433
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * 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.
+ */
+
+#ifndef SUDOERS_LDAP_H
+#define SUDOERS_LDAP_H
+
+bool sudo_ldap_is_negated(char **valp);
+int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
+struct privilege *sudo_ldap_role_to_priv(const char *cn, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, size_t ele_size, size_t str_off);
+struct sudo_digest *sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest);
+
+#endif /* SUDOERS_LDAP_H */