Add option to prune non-matching entries from cvtsudoers output with -m
option is used.
This commit is contained in:
@@ -4,7 +4,7 @@ NNAAMMEE
|
|||||||
ccvvttssuuddooeerrss - convert between sudoers file formats
|
ccvvttssuuddooeerrss - convert between sudoers file formats
|
||||||
|
|
||||||
SSYYNNOOPPSSIISS
|
SSYYNNOOPPSSIISS
|
||||||
ccvvttssuuddooeerrss [--eehhMMVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--dd _d_e_f_t_y_p_e_s]
|
ccvvttssuuddooeerrss [--eehhMMppVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--dd _d_e_f_t_y_p_e_s]
|
||||||
[--ff _o_u_t_p_u_t___f_o_r_m_a_t] [--ii _i_n_p_u_t___f_o_r_m_a_t] [--II _i_n_c_r_e_m_e_n_t]
|
[--ff _o_u_t_p_u_t___f_o_r_m_a_t] [--ii _i_n_p_u_t___f_o_r_m_a_t] [--II _i_n_c_r_e_m_e_n_t]
|
||||||
[--mm _f_i_l_t_e_r] [--oo _o_u_t_p_u_t___f_i_l_e] [--OO _s_t_a_r_t___p_o_i_n_t] [--ss _s_e_c_t_i_o_n_s]
|
[--mm _f_i_l_t_e_r] [--oo _o_u_t_p_u_t___f_i_l_e] [--OO _s_t_a_r_t___p_o_i_n_t] [--ss _s_e_c_t_i_o_n_s]
|
||||||
[_i_n_p_u_t___f_i_l_e]
|
[_i_n_p_u_t___f_i_l_e]
|
||||||
@@ -147,6 +147,11 @@ DDEESSCCRRIIPPTTIIOONN
|
|||||||
point of 0 will disable the generation of sudoOrder
|
point of 0 will disable the generation of sudoOrder
|
||||||
attributes in the resulting LDIF file.
|
attributes in the resulting LDIF file.
|
||||||
|
|
||||||
|
--pp, ----pprruunnee--mmaattcchheess
|
||||||
|
When the --mm option is also specified, ccvvttssuuddooeerrss will prune
|
||||||
|
out non-matching users, groups and hosts from matching
|
||||||
|
entries.
|
||||||
|
|
||||||
--ss _s_e_c_t_i_o_n_s, ----ssuupppprreessss=_s_e_c_t_i_o_n_s
|
--ss _s_e_c_t_i_o_n_s, ----ssuupppprreessss=_s_e_c_t_i_o_n_s
|
||||||
Suppress the output of specific _s_e_c_t_i_o_n_s of the security
|
Suppress the output of specific _s_e_c_t_i_o_n_s of the security
|
||||||
policy. One or more section names may be specified,
|
policy. One or more section names may be specified,
|
||||||
@@ -182,6 +187,9 @@ DDEESSCCRRIIPPTTIIOONN
|
|||||||
oouuttppuutt__ffoorrmmaatt == _j_s_o_n | _l_d_i_f | _s_u_d_o_e_r_s
|
oouuttppuutt__ffoorrmmaatt == _j_s_o_n | _l_d_i_f | _s_u_d_o_e_r_s
|
||||||
See the description of the --ff command line option.
|
See the description of the --ff command line option.
|
||||||
|
|
||||||
|
pprruunnee__mmaattcchheess == _y_e_s | _n_o
|
||||||
|
See the description of the --pp command line option.
|
||||||
|
|
||||||
ssuuddooeerrss__bbaassee == _d_n
|
ssuuddooeerrss__bbaassee == _d_n
|
||||||
See the description of the --bb command line option.
|
See the description of the --bb command line option.
|
||||||
|
|
||||||
@@ -223,4 +231,4 @@ DDIISSCCLLAAIIMMEERR
|
|||||||
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
||||||
complete details.
|
complete details.
|
||||||
|
|
||||||
Sudo 1.8.23 March 30, 2018 Sudo 1.8.23
|
Sudo 1.8.23 April 4, 2018 Sudo 1.8.23
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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
|
.nh
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
.HP 11n
|
.HP 11n
|
||||||
\fBcvtsudoers\fR
|
\fBcvtsudoers\fR
|
||||||
[\fB\-ehMV\fR]
|
[\fB\-ehMpV\fR]
|
||||||
[\fB\-b\fR\ \fIdn\fR]
|
[\fB\-b\fR\ \fIdn\fR]
|
||||||
[\fB\-c\fR\ \fIconf_file\fR]
|
[\fB\-c\fR\ \fIconf_file\fR]
|
||||||
[\fB\-d\fR\ \fIdeftypes\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
|
A starting point of 0 will disable the generation of sudoOrder
|
||||||
attributes in the resulting LDIF file.
|
attributes in the resulting LDIF file.
|
||||||
.TP 12n
|
.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
|
\fB\-s\fR \fIsections\fR, \fB\--suppress\fR=\fIsections\fR
|
||||||
Suppress the output of specific
|
Suppress the output of specific
|
||||||
\fIsections\fR
|
\fIsections\fR
|
||||||
@@ -340,6 +348,11 @@ See the description of the
|
|||||||
\fB\-f\fR
|
\fB\-f\fR
|
||||||
command line option.
|
command line option.
|
||||||
.TP 6n
|
.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
|
\fBsudoers_base =\fR \fIdn\fR
|
||||||
See the description of the
|
See the description of the
|
||||||
\fB\-b\fR
|
\fB\-b\fR
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd March 30, 2018
|
.Dd April 4, 2018
|
||||||
.Dt CVTSUDOERS 1
|
.Dt CVTSUDOERS 1
|
||||||
.Os Sudo @PACKAGE_VERSION@
|
.Os Sudo @PACKAGE_VERSION@
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
.Nd convert between sudoers file formats
|
.Nd convert between sudoers file formats
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm cvtsudoers
|
.Nm cvtsudoers
|
||||||
.Op Fl ehMV
|
.Op Fl ehMpV
|
||||||
.Op Fl b Ar dn
|
.Op Fl b Ar dn
|
||||||
.Op Fl c Ar conf_file
|
.Op Fl c Ar conf_file
|
||||||
.Op Fl d Ar deftypes
|
.Op Fl d Ar deftypes
|
||||||
@@ -228,6 +228,13 @@ option for details.
|
|||||||
Defaults to a starting point of 1.
|
Defaults to a starting point of 1.
|
||||||
A starting point of 0 will disable the generation of sudoOrder
|
A starting point of 0 will disable the generation of sudoOrder
|
||||||
attributes in the resulting LDIF file.
|
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
|
.It Fl s Ar sections , Fl -suppress Ns = Ns Ar sections
|
||||||
Suppress the output of specific
|
Suppress the output of specific
|
||||||
.Ar sections
|
.Ar sections
|
||||||
@@ -284,6 +291,10 @@ command line option.
|
|||||||
See the description of the
|
See the description of the
|
||||||
.Fl f
|
.Fl f
|
||||||
command line option.
|
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
|
.It Sy sudoers_base = Ar dn
|
||||||
See the description of the
|
See the description of the
|
||||||
.Fl b
|
.Fl b
|
||||||
|
@@ -56,7 +56,7 @@
|
|||||||
struct cvtsudoers_filter *filters;
|
struct cvtsudoers_filter *filters;
|
||||||
struct sudo_user sudo_user;
|
struct sudo_user sudo_user;
|
||||||
struct passwd *list_pw;
|
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[] = {
|
static struct option long_opts[] = {
|
||||||
{ "base", required_argument, NULL, 'b' },
|
{ "base", required_argument, NULL, 'b' },
|
||||||
{ "config", required_argument, NULL, 'c' },
|
{ "config", required_argument, NULL, 'c' },
|
||||||
@@ -68,6 +68,7 @@ static struct option long_opts[] = {
|
|||||||
{ "increment", required_argument, NULL, 'I' },
|
{ "increment", required_argument, NULL, 'I' },
|
||||||
{ "match", required_argument, NULL, 'm' },
|
{ "match", required_argument, NULL, 'm' },
|
||||||
{ "match-local", no_argument, NULL, 'M' },
|
{ "match-local", no_argument, NULL, 'M' },
|
||||||
|
{ "prune-matches", no_argument, NULL, 'p' },
|
||||||
{ "order-start", required_argument, NULL, 'O' },
|
{ "order-start", required_argument, NULL, 'O' },
|
||||||
{ "output", required_argument, NULL, 'o' },
|
{ "output", required_argument, NULL, 'o' },
|
||||||
{ "suppress", required_argument, NULL, 's' },
|
{ "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 void cvtsudoers_conf_free(struct cvtsudoers_config *conf);
|
||||||
static int cvtsudoers_parse_defaults(char *expression);
|
static int cvtsudoers_parse_defaults(char *expression);
|
||||||
static int cvtsudoers_parse_suppression(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 filter_defaults(struct cvtsudoers_config *conf);
|
||||||
static void alias_remove_unused(void);
|
static void alias_remove_unused(void);
|
||||||
|
|
||||||
@@ -207,6 +208,9 @@ main(int argc, char *argv[])
|
|||||||
usage(1);
|
usage(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
conf->prune_matches = true;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
conf->supstr = optarg;
|
conf->supstr = optarg;
|
||||||
break;
|
break;
|
||||||
@@ -317,7 +321,7 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Apply filters. */
|
/* Apply filters. */
|
||||||
filter_userspecs();
|
filter_userspecs(conf);
|
||||||
filter_defaults(conf);
|
filter_defaults(conf);
|
||||||
if (filters != NULL || conf->defaults != CVT_DEFAULTS_ALL)
|
if (filters != NULL || conf->defaults != CVT_DEFAULTS_ALL)
|
||||||
alias_remove_unused();
|
alias_remove_unused();
|
||||||
@@ -355,7 +359,8 @@ static struct cvtsudoers_conf_table cvtsudoers_conf_vars[] = {
|
|||||||
{ "match", CONF_STR, &cvtsudoers_config.filter },
|
{ "match", CONF_STR, &cvtsudoers_config.filter },
|
||||||
{ "defaults", CONF_STR, &cvtsudoers_config.defstr },
|
{ "defaults", CONF_STR, &cvtsudoers_config.defstr },
|
||||||
{ "suppress", CONF_STR, &cvtsudoers_config.supstr },
|
{ "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,16 +674,20 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
userlist_matches_filter(struct member_list *userlist)
|
userlist_matches_filter(struct member_list *users, bool remove_nonmatching)
|
||||||
{
|
{
|
||||||
struct cvtsudoers_string *s;
|
struct cvtsudoers_string *s;
|
||||||
bool matches = false;
|
struct member *m, *next;
|
||||||
|
bool ret = false;
|
||||||
debug_decl(userlist_matches_filter, SUDOERS_DEBUG_UTIL)
|
debug_decl(userlist_matches_filter, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
if (filters == NULL ||
|
if (filters == NULL ||
|
||||||
(STAILQ_EMPTY(&filters->users) && STAILQ_EMPTY(&filters->groups)))
|
(STAILQ_EMPTY(&filters->users) && STAILQ_EMPTY(&filters->groups)))
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE_SAFE(m, users, member_list, entries, next) {
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
if (STAILQ_EMPTY(&filters->users)) {
|
if (STAILQ_EMPTY(&filters->users)) {
|
||||||
struct passwd pw;
|
struct passwd pw;
|
||||||
|
|
||||||
@@ -690,12 +699,15 @@ userlist_matches_filter(struct member_list *userlist)
|
|||||||
pw.pw_name = "_nobody";
|
pw.pw_name = "_nobody";
|
||||||
pw.pw_uid = (uid_t)-1;
|
pw.pw_uid = (uid_t)-1;
|
||||||
pw.pw_gid = (gid_t)-1;
|
pw.pw_gid = (gid_t)-1;
|
||||||
if (userlist_matches(&pw, userlist) == true)
|
|
||||||
matches = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (user_matches(&pw, m) == true) {
|
||||||
|
matched = true;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||||
struct passwd *pw = NULL;
|
struct passwd *pw = NULL;
|
||||||
|
|
||||||
if (s->str[0] == '#') {
|
if (s->str[0] == '#') {
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
||||||
@@ -706,49 +718,100 @@ userlist_matches_filter(struct member_list *userlist)
|
|||||||
pw = sudo_getpwnam(s->str);
|
pw = sudo_getpwnam(s->str);
|
||||||
if (pw == NULL)
|
if (pw == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (userlist_matches(pw, userlist) == true)
|
|
||||||
matches = true;
|
if (user_matches(pw, m) == true)
|
||||||
|
matched = true;
|
||||||
sudo_pw_delref(pw);
|
sudo_pw_delref(pw);
|
||||||
if (matches)
|
|
||||||
|
/* Only need one user in the filter to match. */
|
||||||
|
if (matched) {
|
||||||
|
ret = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug_return_bool(matches);
|
if (!matched && remove_nonmatching) {
|
||||||
|
TAILQ_REMOVE(users, m, entries);
|
||||||
|
free_member(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
hostlist_matches_filter(struct member_list *hostlist)
|
hostlist_matches_filter(struct member_list *hostlist, bool remove_nonmatching)
|
||||||
{
|
{
|
||||||
struct cvtsudoers_string *s;
|
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)
|
debug_decl(hostlist_matches_filter, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
if (filters == NULL || STAILQ_EMPTY(&filters->hosts))
|
if (filters == NULL || STAILQ_EMPTY(&filters->hosts))
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
|
|
||||||
|
/* Create an array of short host names. */
|
||||||
STAILQ_FOREACH(s, &filters->hosts, entries) {
|
STAILQ_FOREACH(s, &filters->hosts, entries) {
|
||||||
user_runhost = s->str;
|
n++;
|
||||||
if ((user_srunhost = strchr(user_runhost, '.')) != NULL) {
|
}
|
||||||
user_srunhost = strndup(user_runhost,
|
shosts = reallocarray(NULL, n, sizeof(char *));
|
||||||
(size_t)(user_srunhost - user_runhost));
|
if (shosts == NULL)
|
||||||
if (user_srunhost == 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__,
|
sudo_fatalx(U_("%s: %s"), __func__,
|
||||||
U_("unable to allocate memory"));
|
U_("unable to allocate memory"));
|
||||||
}
|
}
|
||||||
} else {
|
} 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 */
|
/* XXX - can't use netgroup_tuple with NULL pw */
|
||||||
if (hostlist_matches(NULL, hostlist) == true)
|
if (host_matches(NULL, lhost, shost, m) == true)
|
||||||
matches = true;
|
matched = true;
|
||||||
if (user_srunhost != user_runhost)
|
|
||||||
free(user_srunhost);
|
/* Only need one host in the filter to match. */
|
||||||
user_runhost = user_host;
|
if (matched) {
|
||||||
user_srunhost = user_shost;
|
ret = true;
|
||||||
if (matches)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
debug_return_bool(matches);
|
}
|
||||||
|
|
||||||
|
/* Short-circuit unless removing non-matches. */
|
||||||
|
if (!matched && remove_nonmatching) {
|
||||||
|
TAILQ_REMOVE(hostlist, m, entries);
|
||||||
|
free_member(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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.
|
* Apply filters to userspecs, removing non-matching entries.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
filter_userspecs(void)
|
filter_userspecs(struct cvtsudoers_config *conf)
|
||||||
{
|
{
|
||||||
struct userspec *us, *next_us;
|
struct userspec *us, *next_us;
|
||||||
struct privilege *priv, *next_priv;
|
struct privilege *priv, *next_priv;
|
||||||
@@ -826,13 +889,13 @@ filter_userspecs(void)
|
|||||||
* In the future, we may want to add a prune option.
|
* In the future, we may want to add a prune option.
|
||||||
*/
|
*/
|
||||||
TAILQ_FOREACH_SAFE(us, &userspecs, entries, next_us) {
|
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);
|
TAILQ_REMOVE(&userspecs, us, entries);
|
||||||
free_userspec(us);
|
free_userspec(us);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, next_priv) {
|
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);
|
TAILQ_REMOVE(&us->privileges, priv, entries);
|
||||||
free_privilege(priv);
|
free_privilege(priv);
|
||||||
}
|
}
|
||||||
@@ -869,7 +932,7 @@ filter_defaults(struct cvtsudoers_config *conf)
|
|||||||
break;
|
break;
|
||||||
case DEFAULTS_USER:
|
case DEFAULTS_USER:
|
||||||
if (!ISSET(conf->defaults, CVT_DEFAULTS_USER) ||
|
if (!ISSET(conf->defaults, CVT_DEFAULTS_USER) ||
|
||||||
!userlist_matches_filter(def->binding))
|
!userlist_matches_filter(def->binding, conf->prune_matches))
|
||||||
keep = false;
|
keep = false;
|
||||||
break;
|
break;
|
||||||
case DEFAULTS_RUNAS:
|
case DEFAULTS_RUNAS:
|
||||||
@@ -878,7 +941,7 @@ filter_defaults(struct cvtsudoers_config *conf)
|
|||||||
break;
|
break;
|
||||||
case DEFAULTS_HOST:
|
case DEFAULTS_HOST:
|
||||||
if (!ISSET(conf->defaults, CVT_DEFAULTS_HOST) ||
|
if (!ISSET(conf->defaults, CVT_DEFAULTS_HOST) ||
|
||||||
!hostlist_matches_filter(def->binding))
|
!hostlist_matches_filter(def->binding, conf->prune_matches))
|
||||||
keep = false;
|
keep = false;
|
||||||
break;
|
break;
|
||||||
case DEFAULTS_CMND:
|
case DEFAULTS_CMND:
|
||||||
@@ -998,7 +1061,7 @@ done:
|
|||||||
static void
|
static void
|
||||||
usage(int fatal)
|
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] "
|
"[-c conf_file ] [-d deftypes] [-f output_format] [-i input_format] "
|
||||||
"[-I increment] [-m filter] [-o output_file] [-O start_point] "
|
"[-I increment] [-m filter] [-o output_file] [-O start_point] "
|
||||||
"[-s sections] [input_file]\n", getprogname());
|
"[-s sections] [input_file]\n", getprogname());
|
||||||
@@ -1023,6 +1086,7 @@ help(void)
|
|||||||
" -M, --match-local match filter uses passwd and group databases\n"
|
" -M, --match-local match filter uses passwd and group databases\n"
|
||||||
" -o, --output=output_file write converted sudoers to output_file\n"
|
" -o, --output=output_file write converted sudoers to output_file\n"
|
||||||
" -O, --order-start=num starting point for first sudoOrder\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"
|
" -s, --suppress=sections suppress output of certain sections\n"
|
||||||
" -V, --version display version information and exit"));
|
" -V, --version display version information and exit"));
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@@ -58,6 +58,7 @@ struct cvtsudoers_config {
|
|||||||
short suppress;
|
short suppress;
|
||||||
bool expand_aliases;
|
bool expand_aliases;
|
||||||
bool store_options;
|
bool store_options;
|
||||||
|
bool prune_matches;
|
||||||
char *sudoers_base;
|
char *sudoers_base;
|
||||||
char *input_format;
|
char *input_format;
|
||||||
char *output_format;
|
char *output_format;
|
||||||
@@ -67,7 +68,7 @@ struct cvtsudoers_config {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Initial config settings for above. */
|
/* 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_BOOL 0
|
||||||
#define CONF_UINT 1
|
#define CONF_UINT 1
|
||||||
|
@@ -90,18 +90,16 @@ static bool digest_matches(int fd, const char *file, const struct sudo_digest *s
|
|||||||
#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL)
|
#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for user described by pw in a list of members.
|
* Check whether user described by pw matches member.
|
||||||
* Returns ALLOW, DENY or UNSPEC.
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
userlist_matches(const struct passwd *pw, const struct member_list *list)
|
user_matches(const struct passwd *pw, const struct member *m)
|
||||||
{
|
{
|
||||||
struct member *m;
|
|
||||||
struct alias *a;
|
struct alias *a;
|
||||||
int rc, matched = UNSPEC;
|
int matched = UNSPEC;
|
||||||
debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH)
|
debug_decl(user_matches, SUDOERS_DEBUG_MATCH)
|
||||||
|
|
||||||
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
@@ -118,7 +116,7 @@ userlist_matches(const struct passwd *pw, const struct member_list *list)
|
|||||||
break;
|
break;
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
if ((a = alias_get(m->name, USERALIAS)) != NULL) {
|
if ((a = alias_get(m->name, USERALIAS)) != NULL) {
|
||||||
rc = userlist_matches(pw, &a->members);
|
int rc = userlist_matches(pw, &a->members);
|
||||||
if (rc != UNSPEC)
|
if (rc != UNSPEC)
|
||||||
matched = m->negated ? !rc : rc;
|
matched = m->negated ? !rc : rc;
|
||||||
alias_put(a);
|
alias_put(a);
|
||||||
@@ -130,7 +128,22 @@ userlist_matches(const struct passwd *pw, const struct member_list *list)
|
|||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (matched != UNSPEC)
|
debug_return_int(matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for user described by pw in a list of members.
|
||||||
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
userlist_matches(const struct passwd *pw, const struct member_list *list)
|
||||||
|
{
|
||||||
|
struct member *m;
|
||||||
|
int matched = UNSPEC;
|
||||||
|
debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH)
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
|
if ((matched = user_matches(pw, m)) != UNSPEC)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
debug_return_int(matched);
|
debug_return_int(matched);
|
||||||
@@ -256,24 +269,53 @@ 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.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hostlist_matches_int(const struct passwd *pw, const char *lhost,
|
||||||
|
const char *shost, const struct member_list *list)
|
||||||
|
{
|
||||||
|
struct member *m;
|
||||||
|
int matched = UNSPEC;
|
||||||
|
debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH)
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
|
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.
|
* Returns ALLOW, DENY or UNSPEC.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
hostlist_matches(const struct passwd *pw, const struct member_list *list)
|
hostlist_matches(const struct passwd *pw, const struct member_list *list)
|
||||||
{
|
{
|
||||||
struct member *m;
|
return hostlist_matches_int(pw, user_runhost, user_srunhost, list);
|
||||||
struct alias *a;
|
}
|
||||||
int rc, matched = UNSPEC;
|
|
||||||
debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH)
|
/*
|
||||||
|
* 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)
|
||||||
|
|
||||||
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
case ALL:
|
case ALL:
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
case NETGROUP:
|
case NETGROUP:
|
||||||
if (netgr_matches(m->name, user_runhost, user_srunhost,
|
if (netgr_matches(m->name, lhost, shost,
|
||||||
def_netgroup_tuple ? pw->pw_name : NULL))
|
def_netgroup_tuple ? pw->pw_name : NULL))
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
@@ -283,7 +325,7 @@ hostlist_matches(const struct passwd *pw, const struct member_list *list)
|
|||||||
break;
|
break;
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
if ((a = alias_get(m->name, HOSTALIAS)) != NULL) {
|
if ((a = alias_get(m->name, HOSTALIAS)) != NULL) {
|
||||||
rc = hostlist_matches(pw, &a->members);
|
int rc = hostlist_matches_int(pw, lhost, shost, &a->members);
|
||||||
if (rc != UNSPEC)
|
if (rc != UNSPEC)
|
||||||
matched = m->negated ? !rc : rc;
|
matched = m->negated ? !rc : rc;
|
||||||
alias_put(a);
|
alias_put(a);
|
||||||
@@ -291,13 +333,10 @@ hostlist_matches(const struct passwd *pw, const struct member_list *list)
|
|||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case WORD:
|
case WORD:
|
||||||
if (hostname_matches(user_srunhost, user_runhost, m->name))
|
if (hostname_matches(shost, lhost, m->name))
|
||||||
matched = !m->negated;
|
matched = !m->negated;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (matched != UNSPEC)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
debug_return_int(matched);
|
debug_return_int(matched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw);
|
||||||
int cmnd_matches(const struct member *m);
|
int cmnd_matches(const struct member *m);
|
||||||
int cmndlist_matches(const struct member_list *list);
|
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 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 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);
|
int userlist_matches(const struct passwd *pw, const struct member_list *list);
|
||||||
const char *sudo_getdomainname(void);
|
const char *sudo_getdomainname(void);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user