]> granicus.if.org Git - sudo/commitdiff
Add option to prune non-matching entries from cvtsudoers output with -m
authorTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 4 Apr 2018 15:51:05 +0000 (09:51 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 4 Apr 2018 15:51:05 +0000 (09:51 -0600)
option is used.

doc/cvtsudoers.cat
doc/cvtsudoers.man.in
doc/cvtsudoers.mdoc.in
plugins/sudoers/cvtsudoers.c
plugins/sudoers/cvtsudoers.h
plugins/sudoers/match.c
plugins/sudoers/parse.h

index 7b72eb7f682825d01a7fcc54515a0521dbb0c4d9..4e7283d0ee8de2638b101d3d278394cbf726d9ff 100644 (file)
@@ -4,7 +4,7 @@ N\bNA\bAM\bME\bE
      c\bcv\bvt\bts\bsu\bud\bdo\boe\ber\brs\bs - convert between sudoers file formats
 
 S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
-     c\bcv\bvt\bts\bsu\bud\bdo\boe\ber\brs\bs [-\b-e\beh\bhM\bMV\bV] [-\b-b\bb _\bd_\bn] [-\b-c\bc _\bc_\bo_\bn_\bf_\b__\bf_\bi_\bl_\be] [-\b-d\bd _\bd_\be_\bf_\bt_\by_\bp_\be_\bs]
+     c\bcv\bvt\bts\bsu\bud\bdo\boe\ber\brs\bs [-\b-e\beh\bhM\bMp\bpV\bV] [-\b-b\bb _\bd_\bn] [-\b-c\bc _\bc_\bo_\bn_\bf_\b__\bf_\bi_\bl_\be] [-\b-d\bd _\bd_\be_\bf_\bt_\by_\bp_\be_\bs]
                 [-\b-f\bf _\bo_\bu_\bt_\bp_\bu_\bt_\b__\bf_\bo_\br_\bm_\ba_\bt] [-\b-i\bi _\bi_\bn_\bp_\bu_\bt_\b__\bf_\bo_\br_\bm_\ba_\bt] [-\b-I\bI _\bi_\bn_\bc_\br_\be_\bm_\be_\bn_\bt]
                 [-\b-m\bm _\bf_\bi_\bl_\bt_\be_\br] [-\b-o\bo _\bo_\bu_\bt_\bp_\bu_\bt_\b__\bf_\bi_\bl_\be] [-\b-O\bO _\bs_\bt_\ba_\br_\bt_\b__\bp_\bo_\bi_\bn_\bt] [-\b-s\bs _\bs_\be_\bc_\bt_\bi_\bo_\bn_\bs]
                 [_\bi_\bn_\bp_\bu_\bt_\b__\bf_\bi_\bl_\be]
@@ -147,6 +147,11 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                  point of 0 will disable the generation of sudoOrder
                  attributes in the resulting LDIF file.
 
+     -\b-p\bp, -\b--\b-p\bpr\bru\bun\bne\be-\b-m\bma\bat\btc\bch\bhe\bes\bs
+                 When the -\b-m\bm option is also specified, c\bcv\bvt\bts\bsu\bud\bdo\boe\ber\brs\bs will prune
+                 out non-matching users, groups and hosts from matching
+                 entries.
+
      -\b-s\bs _\bs_\be_\bc_\bt_\bi_\bo_\bn_\bs, -\b--\b-s\bsu\bup\bpp\bpr\bre\bes\bss\bs=_\bs_\be_\bc_\bt_\bi_\bo_\bn_\bs
                  Suppress the output of specific _\bs_\be_\bc_\bt_\bi_\bo_\bn_\bs of the security
                  policy.  One or more section names may be specified,
@@ -182,6 +187,9 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
      o\bou\but\btp\bpu\but\bt_\b_f\bfo\bor\brm\bma\bat\bt =\b= _\bj_\bs_\bo_\bn | _\bl_\bd_\bi_\bf | _\bs_\bu_\bd_\bo_\be_\br_\bs
            See the description of the -\b-f\bf command line option.
 
+     p\bpr\bru\bun\bne\be_\b_m\bma\bat\btc\bch\bhe\bes\bs =\b= _\by_\be_\bs | _\bn_\bo
+           See the description of the -\b-p\bp command line option.
+
      s\bsu\bud\bdo\boe\ber\brs\bs_\b_b\bba\bas\bse\be =\b= _\bd_\bn
            See the description of the -\b-b\bb command line option.
 
@@ -223,4 +231,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.23                     March 30, 2018                     Sudo 1.8.23
+Sudo 1.8.23                      April 4, 2018                     Sudo 1.8.23
index 754dcac6e04c10c83820551c61e244082e97cc61..de472a19acb802b9d1b4ee93aa92d1087f623502 100644 (file)
@@ -16,7 +16,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "CVTSUDOERS" "1" "March 30, 2018" "Sudo @PACKAGE_VERSION@" "General Commands Manual"
+.TH "CVTSUDOERS" "1" "April 4, 2018" "Sudo @PACKAGE_VERSION@" "General Commands Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -25,7 +25,7 @@
 .SH "SYNOPSIS"
 .HP 11n
 \fBcvtsudoers\fR
-[\fB\-ehMV\fR]
+[\fB\-ehMpV\fR]
 [\fB\-b\fR\ \fIdn\fR]
 [\fB\-c\fR\ \fIconf_file\fR]
 [\fB\-d\fR\ \fIdeftypes\fR]
@@ -277,6 +277,14 @@ Defaults to a starting point of 1.
 A starting point of 0 will disable the generation of sudoOrder
 attributes in the resulting LDIF file.
 .TP 12n
+\fB\-p\fR, \fB\--prune-matches\fR
+When the
+\fB\-m\fR
+option is also specified,
+\fBcvtsudoers\fR
+will prune out non-matching users, groups and hosts from
+matching entries.
+.TP 12n
 \fB\-s\fR \fIsections\fR, \fB\--suppress\fR=\fIsections\fR
 Suppress the output of specific
 \fIsections\fR
@@ -340,6 +348,11 @@ See the description of the
 \fB\-f\fR
 command line option.
 .TP 6n
+\fBprune_matches =\fR \fIyes\fR | \fIno\fR
+See the description of the
+\fB\-p\fR
+command line option.
+.TP 6n
 \fBsudoers_base =\fR \fIdn\fR
 See the description of the
 \fB\-b\fR
index 4b6e2ff222159bad105f36840be9b60233b7e6af..467fe8dacbe420a12dc3fe349d01eeb0f2e37b18 100644 (file)
@@ -14,7 +14,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd March 30, 2018
+.Dd April 4, 2018
 .Dt CVTSUDOERS 1
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -22,7 +22,7 @@
 .Nd convert between sudoers file formats
 .Sh SYNOPSIS
 .Nm cvtsudoers
-.Op Fl ehMV
+.Op Fl ehMpV
 .Op Fl b Ar dn
 .Op Fl c Ar conf_file
 .Op Fl d Ar deftypes
@@ -228,6 +228,13 @@ option for details.
 Defaults to a starting point of 1.
 A starting point of 0 will disable the generation of sudoOrder
 attributes in the resulting LDIF file.
+.It Fl p , Fl -prune-matches
+When the
+.Fl m
+option is also specified,
+.Nm
+will prune out non-matching users, groups and hosts from
+matching entries.
 .It Fl s Ar sections , Fl -suppress Ns = Ns Ar sections
 Suppress the output of specific
 .Ar sections
@@ -284,6 +291,10 @@ command line option.
 See the description of the
 .Fl f
 command line option.
+.It Sy prune_matches = Ar yes | no
+See the description of the
+.Fl p
+command line option.
 .It Sy sudoers_base = Ar dn
 See the description of the
 .Fl b
index c432c572b6d5d44e01dad29ee944cb2d1742870b..dbe07a5453395f040afc9b03e93d9eb3e272a053 100644 (file)
@@ -56,7 +56,7 @@
 struct cvtsudoers_filter *filters;
 struct sudo_user sudo_user;
 struct passwd *list_pw;
-static const char short_opts[] =  "b:c:d:ef:hi:I:m:Mo:O:s:V";
+static const char short_opts[] =  "b:c:d:ef:hi:I:m:Mo:O:ps:V";
 static struct option long_opts[] = {
     { "base",          required_argument,      NULL,   'b' },
     { "config",                required_argument,      NULL,   'c' },
@@ -68,6 +68,7 @@ static struct option long_opts[] = {
     { "increment",     required_argument,      NULL,   'I' },
     { "match",         required_argument,      NULL,   'm' },
     { "match-local",   no_argument,            NULL,   'M' },
+    { "prune-matches", no_argument,            NULL,   'p' },
     { "order-start",   required_argument,      NULL,   'O' },
     { "output",                required_argument,      NULL,   'o' },
     { "suppress",      required_argument,      NULL,   's' },
@@ -85,7 +86,7 @@ static struct cvtsudoers_config *cvtsudoers_conf_read(const char *conf_file);
 static void cvtsudoers_conf_free(struct cvtsudoers_config *conf);
 static int cvtsudoers_parse_defaults(char *expression);
 static int cvtsudoers_parse_suppression(char *expression);
-static void filter_userspecs(void);
+static void filter_userspecs(struct cvtsudoers_config *conf);
 static void filter_defaults(struct cvtsudoers_config *conf);
 static void alias_remove_unused(void);
 
@@ -207,6 +208,9 @@ main(int argc, char *argv[])
                usage(1);
            }
            break;
+       case 'p':
+           conf->prune_matches = true;
+           break;
        case 's':
            conf->supstr = optarg;
            break;
@@ -317,7 +321,7 @@ main(int argc, char *argv[])
     }
 
     /* Apply filters. */
-    filter_userspecs();
+    filter_userspecs(conf);
     filter_defaults(conf);
     if (filters != NULL || conf->defaults != CVT_DEFAULTS_ALL)
        alias_remove_unused();
@@ -355,7 +359,8 @@ static struct cvtsudoers_conf_table cvtsudoers_conf_vars[] = {
     { "match", CONF_STR, &cvtsudoers_config.filter },
     { "defaults", CONF_STR, &cvtsudoers_config.defstr },
     { "suppress", CONF_STR, &cvtsudoers_config.supstr },
-    { "expand_aliases", CONF_BOOL, &cvtsudoers_config.expand_aliases }
+    { "expand_aliases", CONF_BOOL, &cvtsudoers_config.expand_aliases },
+    { "prune_matches", CONF_BOOL, &cvtsudoers_config.prune_matches }
 };
 
 /*
@@ -669,86 +674,144 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
 }
 
 static bool
-userlist_matches_filter(struct member_list *userlist)
+userlist_matches_filter(struct member_list *users, bool remove_nonmatching)
 {
     struct cvtsudoers_string *s;
-    bool matches = false;
+    struct member *m, *next;
+    bool ret = false;
     debug_decl(userlist_matches_filter, SUDOERS_DEBUG_UTIL)
 
     if (filters == NULL ||
        (STAILQ_EMPTY(&filters->users) && STAILQ_EMPTY(&filters->groups)))
        debug_return_bool(true);
 
-    if (STAILQ_EMPTY(&filters->users)) {
-       struct passwd pw;
+    TAILQ_FOREACH_REVERSE_SAFE(m, users, member_list, entries, next) {
+       bool matched = false;
 
-       /*
-        * Only groups in filter, make a dummy user so userlist_matches()
-        * can do its thing.
-        */
-       memset(&pw, 0, sizeof(pw));
-       pw.pw_name = "_nobody";
-       pw.pw_uid = (uid_t)-1;
-       pw.pw_gid = (gid_t)-1;
-       if (userlist_matches(&pw, userlist) == true)
-           matches = true;
-    }
+       if (STAILQ_EMPTY(&filters->users)) {
+           struct passwd pw;
+
+           /*
+            * Only groups in filter, make a dummy user so userlist_matches()
+            * can do its thing.
+            */
+           memset(&pw, 0, sizeof(pw));
+           pw.pw_name = "_nobody";
+           pw.pw_uid = (uid_t)-1;
+           pw.pw_gid = (gid_t)-1;
 
-    STAILQ_FOREACH(s, &filters->users, entries) {
-       struct passwd *pw = NULL;
-        if (s->str[0] == '#') {
-           const char *errstr;
-            uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
-            if (errstr == NULL)
-                pw = sudo_getpwuid(uid);
+           if (user_matches(&pw, m) == true) {
+               matched = true;
+               ret = true;
+           }
+       } else {
+           STAILQ_FOREACH(s, &filters->users, entries) {
+               struct passwd *pw = NULL;
+
+               if (s->str[0] == '#') {
+                   const char *errstr;
+                   uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
+                   if (errstr == NULL)
+                       pw = sudo_getpwuid(uid);
+               }
+               if (pw == NULL)
+                   pw = sudo_getpwnam(s->str);
+               if (pw == NULL)
+                   continue;
+
+               if (user_matches(pw, m) == true)
+                   matched = true;
+               sudo_pw_delref(pw);
+
+               /* Only need one user in the filter to match. */
+               if (matched) {
+                   ret = true;
+                   break;
+               }
+           }
+       }
+
+       if (!matched && remove_nonmatching) {
+           TAILQ_REMOVE(users, m, entries);
+           free_member(m);
        }
-       if (pw == NULL)
-           pw = sudo_getpwnam(s->str);
-       if (pw == NULL)
-           continue;
-       if (userlist_matches(pw, userlist) == true)
-           matches = true;
-       sudo_pw_delref(pw);
-       if (matches)
-           break;
     }
 
-    debug_return_bool(matches);
+    debug_return_bool(ret);
 }
 
 static bool
-hostlist_matches_filter(struct member_list *hostlist)
+hostlist_matches_filter(struct member_list *hostlist, bool remove_nonmatching)
 {
     struct cvtsudoers_string *s;
-    bool matches = false;
+    struct member *m, *next;
+    char *lhost, *shost;
+    bool ret = false;
+    char **shosts;
+    int n = 0;
     debug_decl(hostlist_matches_filter, SUDOERS_DEBUG_UTIL)
 
     if (filters == NULL || STAILQ_EMPTY(&filters->hosts))
        debug_return_bool(true);
 
+    /* Create an array of short host names. */
     STAILQ_FOREACH(s, &filters->hosts, entries) {
-       user_runhost = s->str;
-       if ((user_srunhost = strchr(user_runhost, '.')) != NULL) {
-           user_srunhost = strndup(user_runhost,
-               (size_t)(user_srunhost - user_runhost));
-           if (user_srunhost == NULL) {
+       n++;
+    }
+    shosts = reallocarray(NULL, n, sizeof(char *));
+    if (shosts == NULL)
+       sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    n = 0;
+    STAILQ_FOREACH(s, &filters->hosts, entries) {
+       lhost = s->str;
+       if ((shost = strchr(lhost, '.')) != NULL) {
+           shost = strndup(lhost, (size_t)(shost - lhost));
+           if (shost == NULL) {
                sudo_fatalx(U_("%s: %s"), __func__,
                    U_("unable to allocate memory"));
            }
        } else {
-           user_srunhost = user_runhost;
+           shost = lhost;
+       }
+       shosts[n++] = shost;
+    }
+
+    TAILQ_FOREACH_REVERSE_SAFE(m, hostlist, member_list, entries, next) {
+       bool matched = false;
+       n = 0;
+       STAILQ_FOREACH(s, &filters->hosts, entries) {
+           lhost = s->str;
+           shost = shosts[n++];
+
+           /* XXX - can't use netgroup_tuple with NULL pw */
+           if (host_matches(NULL, lhost, shost, m) == true)
+               matched = true;
+
+           /* Only need one host in the filter to match. */
+           if (matched) {
+               ret = true;
+               break;
+           }
+       }
+
+       /* Short-circuit unless removing non-matches. */
+       if (!matched && remove_nonmatching) {
+           TAILQ_REMOVE(hostlist, m, entries);
+           free_member(m);
        }
-       /* XXX - can't use netgroup_tuple with NULL pw */
-       if (hostlist_matches(NULL, hostlist) == true)
-           matches = true;
-       if (user_srunhost != user_runhost)
-           free(user_srunhost);
-       user_runhost = user_host;
-       user_srunhost = user_shost;
-       if (matches)
-           break;
     }
-    debug_return_bool(matches);
+
+    /* Free shosts array and its contents. */
+    n = 0;
+    STAILQ_FOREACH(s, &filters->hosts, entries) {
+       lhost = s->str;
+       shost = shosts[n++];
+       if (shost != lhost)
+           free(shost);
+    }
+    free(shosts);
+
+    debug_return_bool(ret == true);
 }
 
 /*
@@ -811,7 +874,7 @@ convert_sudoers_output(const char *buf)
  * Apply filters to userspecs, removing non-matching entries.
  */
 static void
-filter_userspecs(void)
+filter_userspecs(struct cvtsudoers_config *conf)
 {
     struct userspec *us, *next_us;
     struct privilege *priv, *next_priv;
@@ -826,13 +889,13 @@ filter_userspecs(void)
      * In the future, we may want to add a prune option.
      */
     TAILQ_FOREACH_SAFE(us, &userspecs, entries, next_us) {
-       if (!userlist_matches_filter(&us->users)) {
+       if (!userlist_matches_filter(&us->users, conf->prune_matches)) {
            TAILQ_REMOVE(&userspecs, us, entries);
            free_userspec(us);
            continue;
        }
        TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, next_priv) {
-           if (!hostlist_matches_filter(&priv->hostlist)) {
+           if (!hostlist_matches_filter(&priv->hostlist, conf->prune_matches)) {
                TAILQ_REMOVE(&us->privileges, priv, entries);
                free_privilege(priv);
            }
@@ -869,7 +932,7 @@ filter_defaults(struct cvtsudoers_config *conf)
            break;
        case DEFAULTS_USER:
            if (!ISSET(conf->defaults, CVT_DEFAULTS_USER) ||
-               !userlist_matches_filter(def->binding))
+               !userlist_matches_filter(def->binding, conf->prune_matches))
                keep = false;
            break;
        case DEFAULTS_RUNAS:
@@ -878,7 +941,7 @@ filter_defaults(struct cvtsudoers_config *conf)
            break;
        case DEFAULTS_HOST:
            if (!ISSET(conf->defaults, CVT_DEFAULTS_HOST) ||
-               !hostlist_matches_filter(def->binding))
+               !hostlist_matches_filter(def->binding, conf->prune_matches))
                keep = false;
            break;
        case DEFAULTS_CMND:
@@ -998,7 +1061,7 @@ done:
 static void
 usage(int fatal)
 {
-    (void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehMV] [-b dn] "
+    (void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehMpV] [-b dn] "
        "[-c conf_file ] [-d deftypes] [-f output_format] [-i input_format] "
        "[-I increment] [-m filter] [-o output_file] [-O start_point] "
        "[-s sections] [input_file]\n", getprogname());
@@ -1023,6 +1086,7 @@ help(void)
        "  -M, --match-local          match filter uses passwd and group databases\n"
        "  -o, --output=output_file   write converted sudoers to output_file\n"
        "  -O, --order-start=num      starting point for first sudoOrder\n"
+       "  -p, --prune-matches        prune non-matching users, groups and hosts\n"
        "  -s, --suppress=sections    suppress output of certain sections\n"
        "  -V, --version              display version information and exit"));
     exit(0);
index 4993821272597305c251576d330ff2e0891d4a00..cc3b4462bbdf50fdd54633b89308d35c33c41938 100644 (file)
@@ -58,6 +58,7 @@ struct cvtsudoers_config {
     short suppress;
     bool expand_aliases;
     bool store_options;
+    bool prune_matches;
     char *sudoers_base;
     char *input_format;
     char *output_format;
@@ -67,7 +68,7 @@ struct cvtsudoers_config {
 };
 
 /* Initial config settings for above. */
-#define INITIAL_CONFIG { 1, 1, CVT_DEFAULTS_ALL, 0, false, true }
+#define INITIAL_CONFIG { 1, 1, CVT_DEFAULTS_ALL, 0, false, true, false }
 
 #define CONF_BOOL      0
 #define CONF_UINT      1
index e67809a533fa710acef5df0e58326364436d01e5..1ccbc1f0a8cbb182e6c97a3dd9e429794ecbed8b 100644 (file)
@@ -89,6 +89,48 @@ static bool digest_matches(int fd, const char *file, const struct sudo_digest *s
  */
 #define has_meta(s)    (strpbrk(s, "\\?*[]") != NULL)
 
+/*
+ * Check whether user described by pw matches member.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+int
+user_matches(const struct passwd *pw, const struct member *m)
+{
+    struct alias *a;
+    int matched = UNSPEC;
+    debug_decl(user_matches, SUDOERS_DEBUG_MATCH)
+
+    switch (m->type) {
+       case ALL:
+           matched = !m->negated;
+           break;
+       case NETGROUP:
+           if (netgr_matches(m->name,
+               def_netgroup_tuple ? user_runhost : NULL,
+               def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name))
+               matched = !m->negated;
+           break;
+       case USERGROUP:
+           if (usergr_matches(m->name, pw->pw_name, pw))
+               matched = !m->negated;
+           break;
+       case ALIAS:
+           if ((a = alias_get(m->name, USERALIAS)) != NULL) {
+               int rc = userlist_matches(pw, &a->members);
+               if (rc != UNSPEC)
+                   matched = m->negated ? !rc : rc;
+               alias_put(a);
+               break;
+           }
+           /* FALLTHROUGH */
+       case WORD:
+           if (userpw_matches(m->name, pw->pw_name, pw))
+               matched = !m->negated;
+           break;
+    }
+    debug_return_int(matched);
+}
+
 /*
  * Check for user described by pw in a list of members.
  * Returns ALLOW, DENY or UNSPEC.
@@ -97,40 +139,11 @@ int
 userlist_matches(const struct passwd *pw, const struct member_list *list)
 {
     struct member *m;
-    struct alias *a;
-    int rc, matched = UNSPEC;
+    int matched = UNSPEC;
     debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH)
 
     TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
-       switch (m->type) {
-           case ALL:
-               matched = !m->negated;
-               break;
-           case NETGROUP:
-               if (netgr_matches(m->name,
-                   def_netgroup_tuple ? user_runhost : NULL,
-                   def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name))
-                   matched = !m->negated;
-               break;
-           case USERGROUP:
-               if (usergr_matches(m->name, pw->pw_name, pw))
-                   matched = !m->negated;
-               break;
-           case ALIAS:
-               if ((a = alias_get(m->name, USERALIAS)) != NULL) {
-                   rc = userlist_matches(pw, &a->members);
-                   if (rc != UNSPEC)
-                       matched = m->negated ? !rc : rc;
-                   alias_put(a);
-                   break;
-               }
-               /* FALLTHROUGH */
-           case WORD:
-               if (userpw_matches(m->name, pw->pw_name, pw))
-                   matched = !m->negated;
-               break;
-       }
-       if (matched != UNSPEC)
+       if ((matched = user_matches(pw, m)) != UNSPEC)
            break;
     }
     debug_return_int(matched);
@@ -256,46 +269,72 @@ runaslist_matches(const struct member_list *user_list,
 }
 
 /*
- * Check for host and shost in a list of members.
+ * Check for lhost and shost in a list of members.
  * Returns ALLOW, DENY or UNSPEC.
  */
-int
-hostlist_matches(const struct passwd *pw, const struct member_list *list)
+static int
+hostlist_matches_int(const struct passwd *pw, const char *lhost,
+    const char *shost, const struct member_list *list)
 {
     struct member *m;
-    struct alias *a;
-    int rc, matched = UNSPEC;
+    int matched = UNSPEC;
     debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH)
 
     TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
-       switch (m->type) {
-           case ALL:
+       matched = host_matches(pw, lhost, shost, m);
+       if (matched != UNSPEC)
+           break;
+    }
+    debug_return_int(matched);
+}
+
+/*
+ * Check for user_runhost and user_srunhost in a list of members.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+int
+hostlist_matches(const struct passwd *pw, const struct member_list *list)
+{
+    return hostlist_matches_int(pw, user_runhost, user_srunhost, list);
+}
+
+/*
+ * Check whether host or shost matches member.
+ * Returns ALLOW, DENY or UNSPEC.
+ */
+int
+host_matches(const struct passwd *pw, const char *lhost, const char *shost,
+    const struct member *m)
+{
+    struct alias *a;
+    int matched = UNSPEC;
+    debug_decl(host_matches, SUDOERS_DEBUG_MATCH)
+
+    switch (m->type) {
+       case ALL:
+           matched = !m->negated;
+           break;
+       case NETGROUP:
+           if (netgr_matches(m->name, lhost, shost,
+               def_netgroup_tuple ? pw->pw_name : NULL))
                matched = !m->negated;
+           break;
+       case NTWKADDR:
+           if (addr_matches(m->name))
+               matched = !m->negated;
+           break;
+       case ALIAS:
+           if ((a = alias_get(m->name, HOSTALIAS)) != NULL) {
+               int rc = hostlist_matches_int(pw, lhost, shost, &a->members);
+               if (rc != UNSPEC)
+                   matched = m->negated ? !rc : rc;
+               alias_put(a);
                break;
-           case NETGROUP:
-               if (netgr_matches(m->name, user_runhost, user_srunhost,
-                   def_netgroup_tuple ? pw->pw_name : NULL))
-                   matched = !m->negated;
-               break;
-           case NTWKADDR:
-               if (addr_matches(m->name))
-                   matched = !m->negated;
-               break;
-           case ALIAS:
-               if ((a = alias_get(m->name, HOSTALIAS)) != NULL) {
-                   rc = hostlist_matches(pw, &a->members);
-                   if (rc != UNSPEC)
-                       matched = m->negated ? !rc : rc;
-                   alias_put(a);
-                   break;
-               }
-               /* FALLTHROUGH */
-           case WORD:
-               if (hostname_matches(user_srunhost, user_runhost, m->name))
-                   matched = !m->negated;
-               break;
-       }
-       if (matched != UNSPEC)
+           }
+           /* FALLTHROUGH */
+       case WORD:
+           if (hostname_matches(shost, lhost, m->name))
+               matched = !m->negated;
            break;
     }
     debug_return_int(matched);
index 91555af917e8f4a5ead4557987307a90996767ca..f3dfaef6c152ad94f98369c641235e29d8e0aa2c 100644 (file)
@@ -286,8 +286,10 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw
 bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw);
 int cmnd_matches(const struct member *m);
 int cmndlist_matches(const struct member_list *list);
+int host_matches(const struct passwd *pw, const char *host, const char *shost, const struct member *m);
 int hostlist_matches(const struct passwd *pw, const struct member_list *list);
 int runaslist_matches(const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group);
+int user_matches(const struct passwd *pw, const struct member *m);
 int userlist_matches(const struct passwd *pw, const struct member_list *list);
 const char *sudo_getdomainname(void);