Add -M option to cvtsudoers to force the use of the local passwd

and group databases when matching.
This commit is contained in:
Todd C. Miller
2018-03-22 13:24:41 -06:00
parent 8a237eb07d
commit 14ee65c525
8 changed files with 117 additions and 31 deletions

View File

@@ -4,7 +4,7 @@ NNAAMMEE
ccvvttssuuddooeerrss - convert between sudoers file formats ccvvttssuuddooeerrss - convert between sudoers file formats
SSYYNNOOPPSSIISS SSYYNNOOPPSSIISS
ccvvttssuuddooeerrss [--eehhVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--ff _o_u_t_p_u_t___f_o_r_m_a_t] ccvvttssuuddooeerrss [--eehhMMVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--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] [--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] [_i_n_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]
@@ -99,6 +99,16 @@ DDEESSCCRRIIPPTTIIOONN
are referenced by the filtered policy rules will be are referenced by the filtered policy rules will be
displayed. displayed.
--MM, ----mmaattcchh--llooccaall
When the --mm option is also specified, use password and group
database information when matching users and groups in the
filter. Only users and groups in the filter that exist on
the local system will match, and a user's groups will
automatically be added to the filter. If the --MM is _n_o_t
specified, users and groups in the filter do not need to
exist on the local system, but all groups used for matching
must be explicitly listed in the filter.
--oo _o_u_t_p_u_t___f_i_l_e, ----oouuttppuutt=_o_u_t_p_u_t___f_i_l_e --oo _o_u_t_p_u_t___f_i_l_e, ----oouuttppuutt=_o_u_t_p_u_t___f_i_l_e
Write the converted output to _o_u_t_p_u_t___f_i_l_e. If no _o_u_t_p_u_t___f_i_l_e Write the converted output to _o_u_t_p_u_t___f_i_l_e. If no _o_u_t_p_u_t___f_i_l_e
is specified, or if it is `-', the converted _s_u_d_o_e_r_s policy is specified, or if it is `-', the converted _s_u_d_o_e_r_s policy

View File

@@ -25,7 +25,7 @@
.SH "SYNOPSIS" .SH "SYNOPSIS"
.HP 11n .HP 11n
\fBcvtsudoers\fR \fBcvtsudoers\fR
[\fB\-ehV\fR] [\fB\-ehMV\fR]
[\fB\-b\fR\ \fIdn\fR] [\fB\-b\fR\ \fIdn\fR]
[\fB\-c\fR\ \fIconf_file\fR] [\fB\-c\fR\ \fIconf_file\fR]
[\fB\-f\fR\ \fIoutput_format\fR] [\fB\-f\fR\ \fIoutput_format\fR]
@@ -191,6 +191,21 @@ on the local system.
Only aliases that are referenced by the filtered policy rules will Only aliases that are referenced by the filtered policy rules will
be displayed. be displayed.
.TP 12n .TP 12n
\fB\-M\fR, \fB\--match-local\fR
When the
\fB\-m\fR
option is also specified, use password and group database information
when matching users and groups in the filter.
Only users and groups in the filter that exist on the local system will match,
and a user's groups will automatically be added to the filter.
If the
\fB\-M\fR
is
\fInot\fR
specified, users and groups in the filter do not need to exist on the
local system, but all groups used for matching must be explicitly listed
in the filter.
.TP 12n
\fB\-o\fR \fIoutput_file\fR, \fB\--output\fR=\fIoutput_file\fR \fB\-o\fR \fIoutput_file\fR, \fB\--output\fR=\fIoutput_file\fR
Write the converted output to Write the converted output to
\fIoutput_file\fR. \fIoutput_file\fR.

View File

@@ -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 ehV .Op Fl ehMV
.Op Fl b Ar dn .Op Fl b Ar dn
.Op Fl c Ar conf_file .Op Fl c Ar conf_file
.Op Fl f Ar output_format .Op Fl f Ar output_format
@@ -155,6 +155,20 @@ against the filter so the users and groups do not need to be present
on the local system. on the local system.
Only aliases that are referenced by the filtered policy rules will Only aliases that are referenced by the filtered policy rules will
be displayed. be displayed.
.It Fl M , Fl -match-local
When the
.Fl m
option is also specified, use password and group database information
when matching users and groups in the filter.
Only users and groups in the filter that exist on the local system will match,
and a user's groups will automatically be added to the filter.
If the
.Fl M
is
.Em not
specified, users and groups in the filter do not need to exist on the
local system, but all groups used for matching must be explicitly listed
in the filter.
.It Fl o Ar output_file , Fl -output Ns = Ns Ar output_file .It Fl o Ar output_file , Fl -output Ns = Ns Ar output_file
Write the converted output to Write the converted output to
.Ar output_file . .Ar output_file .

View File

@@ -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:ef:hi:I:m:o:O:s:V"; static const char short_opts[] = "b:c:ef:hi:I:m:Mo:O:s: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' },
@@ -66,6 +66,7 @@ static struct option long_opts[] = {
{ "input-format", required_argument, NULL, 'i' }, { "input-format", required_argument, NULL, 'i' },
{ "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' },
{ "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' },
@@ -93,6 +94,7 @@ main(int argc, char *argv[])
enum sudoers_formats output_format = format_ldif; enum sudoers_formats output_format = format_ldif;
enum sudoers_formats input_format = format_sudoers; enum sudoers_formats input_format = format_sudoers;
struct cvtsudoers_config *conf = NULL; struct cvtsudoers_config *conf = NULL;
bool match_local = false;
const char *input_file = "-"; const char *input_file = "-";
const char *output_file = "-"; const char *output_file = "-";
const char *conf_file = _PATH_CVTSUDOERS_CONF; const char *conf_file = _PATH_CVTSUDOERS_CONF;
@@ -187,6 +189,9 @@ main(int argc, char *argv[])
case 'm': case 'm':
conf->filter = optarg; conf->filter = optarg;
break; break;
case 'M':
match_local = true;
break;
case 'o': case 'o':
output_file = optarg; output_file = optarg;
break; break;
@@ -272,6 +277,12 @@ main(int argc, char *argv[])
} }
} }
/* Set pwutil backend to use the filter data. */
if (conf->filter != NULL && !match_local) {
sudo_pwutil_set_backend(cvtsudoers_make_pwitem, cvtsudoers_make_gritem,
cvtsudoers_make_gidlist_item, cvtsudoers_make_grlist_item);
}
/* We may need the hostname to resolve %h escapes in include files. */ /* We may need the hostname to resolve %h escapes in include files. */
get_hostname(); get_hostname();
@@ -610,7 +621,7 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
return fopen(sudoers, "r"); return fopen(sudoers, "r");
} }
bool static bool
userlist_matches_filter(struct member_list *userlist) userlist_matches_filter(struct member_list *userlist)
{ {
struct cvtsudoers_string *s; struct cvtsudoers_string *s;
@@ -658,7 +669,7 @@ userlist_matches_filter(struct member_list *userlist)
debug_return_bool(matches); debug_return_bool(matches);
} }
bool static bool
hostlist_matches_filter(struct member_list *hostlist) hostlist_matches_filter(struct member_list *hostlist)
{ {
struct cvtsudoers_string *s; struct cvtsudoers_string *s;
@@ -1011,7 +1022,7 @@ done:
static void static void
usage(int fatal) usage(int fatal)
{ {
(void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehV] [-b dn] " (void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehMV] [-b dn] "
"[-c conf_file ] [-f output_format] [-i input_format] [-I increment] " "[-c conf_file ] [-f output_format] [-i input_format] [-I increment] "
"[-m filter] [-o output_file] [-O start_point] [-s sections] " "[-m filter] [-o output_file] [-O start_point] [-s sections] "
"[input_file]\n", getprogname()); "[input_file]\n", getprogname());
@@ -1031,7 +1042,8 @@ help(void)
" -i, --input-format=format set input format: LDIF or sudoers\n" " -i, --input-format=format set input format: LDIF or sudoers\n"
" -I, --increment=num amount to increase each sudoOrder by\n" " -I, --increment=num amount to increase each sudoOrder by\n"
" -h, --help display help message and exit\n" " -h, --help display help message and exit\n"
" -m, --match=filter only convert entries that match the filter expression\n" " -m, --match=filter only convert entries that match the filter\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"
" -s, --suppress=sections suppress output of certain sections\n" " -s, --suppress=sections suppress output of certain sections\n"

View File

@@ -74,21 +74,25 @@ struct cvtsudoers_filter {
struct cvtsudoers_str_list hosts; struct cvtsudoers_str_list hosts;
}; };
bool convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf); /* cvtsudoers.c */
bool convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf); extern struct cvtsudoers_filter *filters;
bool parse_ldif(const char *input_file, struct cvtsudoers_config *conf);
void get_hostname(void);
struct member_list;
struct userspec_list;
bool userlist_matches_filter(struct member_list *userlist);
bool hostlist_matches_filter(struct member_list *hostlist);
struct cvtsudoers_str_list *str_list_alloc(void); struct cvtsudoers_str_list *str_list_alloc(void);
void str_list_free(void *v); void str_list_free(void *v);
struct cvtsudoers_string *cvtsudoers_string_alloc(const char *s); struct cvtsudoers_string *cvtsudoers_string_alloc(const char *s);
void cvtsudoers_string_free(struct cvtsudoers_string *ls); void cvtsudoers_string_free(struct cvtsudoers_string *ls);
extern struct cvtsudoers_filter *filters; /* cvtsudoers_json.c */
bool convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf);
/* cvtsudoers_ldif.c */
bool convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf);
bool parse_ldif(const char *input_file, struct cvtsudoers_config *conf);
void get_hostname(void);
/* cvtsudoers_pwutil.c */
struct cache_item *cvtsudoers_make_pwitem(uid_t uid, const char *name);
struct cache_item *cvtsudoers_make_gritem(gid_t gid, const char *name);
struct cache_item *cvtsudoers_make_gidlist_item(const struct passwd *pw, char * const *unused1, unsigned int type);
struct cache_item *cvtsudoers_make_grlist_item(const struct passwd *pw, char * const *unused1);
#endif /* SUDOERS_CVTSUDOERS_H */ #endif /* SUDOERS_CVTSUDOERS_H */

View File

@@ -73,7 +73,7 @@ do { \
* to ENOMEM or ENOENT respectively. * to ENOMEM or ENOENT respectively.
*/ */
struct cache_item * struct cache_item *
sudo_make_pwitem(uid_t uid, const char *name) cvtsudoers_make_pwitem(uid_t uid, const char *name)
{ {
char *cp, uidstr[MAX_UID_T_LEN + 2]; char *cp, uidstr[MAX_UID_T_LEN + 2];
size_t nsize, psize, csize, gsize, dsize, ssize, total; size_t nsize, psize, csize, gsize, dsize, ssize, total;
@@ -179,7 +179,7 @@ sudo_make_pwitem(uid_t uid, const char *name)
* to ENOMEM or ENOENT respectively. * to ENOMEM or ENOENT respectively.
*/ */
struct cache_item * struct cache_item *
sudo_make_gritem(gid_t gid, const char *name) cvtsudoers_make_gritem(gid_t gid, const char *name)
{ {
char *cp, gidstr[MAX_UID_T_LEN + 2]; char *cp, gidstr[MAX_UID_T_LEN + 2];
size_t nsize, psize, nmem, total, len; size_t nsize, psize, nmem, total, len;
@@ -292,7 +292,7 @@ static struct cache_item_gidlist *gidlist_item;
* elements. Fills in datum from user_gids or from getgrouplist(3). * elements. Fills in datum from user_gids or from getgrouplist(3).
*/ */
struct cache_item * struct cache_item *
sudo_make_gidlist_item(const struct passwd *pw, char * const *unused1, cvtsudoers_make_gidlist_item(const struct passwd *pw, char * const *unused1,
unsigned int type) unsigned int type)
{ {
char *cp; char *cp;
@@ -391,7 +391,7 @@ static struct cache_item_gidlist *grlist_item;
* elements. Fills in group names from a call to sudo_get_gidlist(). * elements. Fills in group names from a call to sudo_get_gidlist().
*/ */
struct cache_item * struct cache_item *
sudo_make_grlist_item(const struct passwd *pw, char * const *unused1) cvtsudoers_make_grlist_item(const struct passwd *pw, char * const *unused1)
{ {
char *cp; char *cp;
size_t nsize, ngroups, total, len; size_t nsize, ngroups, total, len;

View File

@@ -54,6 +54,14 @@ static int cmp_pwuid(const void *, const void *);
static int cmp_pwnam(const void *, const void *); static int cmp_pwnam(const void *, const void *);
static int cmp_grgid(const void *, const void *); static int cmp_grgid(const void *, const void *);
/*
* Default functions for building cache items.
*/
static sudo_make_pwitem_t make_pwitem = sudo_make_pwitem;
static sudo_make_gritem_t make_gritem = sudo_make_gritem;
static sudo_make_gidlist_item_t make_gidlist_item = sudo_make_gidlist_item;
static sudo_make_grlist_item_t make_grlist_item = sudo_make_grlist_item;
#define cmp_grnam cmp_pwnam #define cmp_grnam cmp_pwnam
/* /*
@@ -68,6 +76,24 @@ static int cmp_grgid(const void *, const void *);
# define getauthregistry(u, r) ((r)[0] = '\0') # define getauthregistry(u, r) ((r)[0] = '\0')
#endif #endif
/*
* Change the default pwutil backend functions.
* The default functions query the password and group databases.
*/
void
sudo_pwutil_set_backend(sudo_make_pwitem_t pwitem, sudo_make_gritem_t gritem,
sudo_make_gidlist_item_t gidlist_item, sudo_make_grlist_item_t grlist_item)
{
debug_decl(sudo_pwutil_set_backend, SUDOERS_DEBUG_NSS)
make_pwitem = pwitem;
make_gritem = gritem;
make_gidlist_item = gidlist_item;
make_grlist_item = grlist_item;
debug_return;
}
/* /*
* Compare by user ID. * Compare by user ID.
* v1 is the key to find or data to insert, v2 is in-tree data. * v1 is the key to find or data to insert, v2 is in-tree data.
@@ -179,7 +205,7 @@ sudo_getpwuid(uid_t uid)
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
aix_setauthdb(IDtouser(uid), key.registry); aix_setauthdb(IDtouser(uid), key.registry);
#endif #endif
item = sudo_make_pwitem(uid, NULL); item = make_pwitem(uid, NULL);
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
aix_restoreauthdb(); aix_restoreauthdb();
#endif #endif
@@ -250,7 +276,7 @@ sudo_getpwnam(const char *name)
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
aix_setauthdb((char *) name, key.registry); aix_setauthdb((char *) name, key.registry);
#endif #endif
item = sudo_make_pwitem((uid_t)-1, name); item = make_pwitem((uid_t)-1, name);
#ifdef HAVE_SETAUTHDB #ifdef HAVE_SETAUTHDB
aix_restoreauthdb(); aix_restoreauthdb();
#endif #endif
@@ -497,7 +523,7 @@ sudo_getgrgid(gid_t gid)
/* /*
* Cache group db entry if it exists or a negative response if not. * Cache group db entry if it exists or a negative response if not.
*/ */
item = sudo_make_gritem(gid, NULL); item = make_gritem(gid, NULL);
if (item == NULL) { if (item == NULL) {
if (errno != ENOENT || (item = calloc(1, sizeof(*item))) == NULL) { if (errno != ENOENT || (item = calloc(1, sizeof(*item))) == NULL) {
sudo_warnx(U_("unable to cache gid %u, out of memory"), sudo_warnx(U_("unable to cache gid %u, out of memory"),
@@ -562,7 +588,7 @@ sudo_getgrnam(const char *name)
/* /*
* Cache group db entry if it exists or a negative response if not. * Cache group db entry if it exists or a negative response if not.
*/ */
item = sudo_make_gritem((gid_t)-1, name); item = make_gritem((gid_t)-1, name);
if (item == NULL) { if (item == NULL) {
const size_t len = strlen(name) + 1; const size_t len = strlen(name) + 1;
if (errno != ENOENT || (item = calloc(1, sizeof(*item) + len)) == NULL) { if (errno != ENOENT || (item = calloc(1, sizeof(*item) + len)) == NULL) {
@@ -789,7 +815,7 @@ sudo_get_grlist(const struct passwd *pw)
/* /*
* Cache group db entry if it exists or a negative response if not. * Cache group db entry if it exists or a negative response if not.
*/ */
item = sudo_make_grlist_item(pw, NULL); item = make_grlist_item(pw, NULL);
if (item == NULL) { if (item == NULL) {
/* Out of memory? */ /* Out of memory? */
debug_return_ptr(NULL); debug_return_ptr(NULL);
@@ -843,7 +869,7 @@ sudo_set_grlist(struct passwd *pw, char * const *groups)
key.k.name = pw->pw_name; key.k.name = pw->pw_name;
getauthregistry(NULL, key.registry); getauthregistry(NULL, key.registry);
if ((node = rbfind(grlist_cache, &key)) == NULL) { if ((node = rbfind(grlist_cache, &key)) == NULL) {
if ((item = sudo_make_grlist_item(pw, groups)) == NULL) { if ((item = make_grlist_item(pw, groups)) == NULL) {
sudo_warnx(U_("unable to parse groups for %s"), pw->pw_name); sudo_warnx(U_("unable to parse groups for %s"), pw->pw_name);
debug_return_int(-1); debug_return_int(-1);
} }
@@ -892,7 +918,7 @@ sudo_get_gidlist(const struct passwd *pw, unsigned int type)
/* /*
* Cache group db entry if it exists or a negative response if not. * Cache group db entry if it exists or a negative response if not.
*/ */
item = sudo_make_gidlist_item(pw, NULL, type); item = make_gidlist_item(pw, NULL, type);
if (item == NULL) { if (item == NULL) {
/* Out of memory? */ /* Out of memory? */
debug_return_ptr(NULL); debug_return_ptr(NULL);
@@ -947,7 +973,7 @@ sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type)
key.type = type; key.type = type;
getauthregistry(NULL, key.registry); getauthregistry(NULL, key.registry);
if ((node = rbfind(gidlist_cache, &key)) == NULL) { if ((node = rbfind(gidlist_cache, &key)) == NULL) {
if ((item = sudo_make_gidlist_item(pw, gids, type)) == NULL) { if ((item = make_gidlist_item(pw, gids, type)) == NULL) {
sudo_warnx(U_("unable to parse gids for %s"), pw->pw_name); sudo_warnx(U_("unable to parse gids for %s"), pw->pw_name);
debug_return_int(-1); debug_return_int(-1);
} }

View File

@@ -304,6 +304,10 @@ int display_privs(struct sudo_nss_list *, struct passwd *);
int display_cmnd(struct sudo_nss_list *, struct passwd *); int display_cmnd(struct sudo_nss_list *, struct passwd *);
/* pwutil.c */ /* pwutil.c */
typedef struct cache_item * (*sudo_make_pwitem_t)(uid_t uid, const char *user);
typedef struct cache_item * (*sudo_make_gritem_t)(gid_t gid, const char *group);
typedef struct cache_item * (*sudo_make_gidlist_item_t)(const struct passwd *pw, char * const *gids, unsigned int type);
typedef struct cache_item * (*sudo_make_grlist_item_t)(const struct passwd *pw, char * const *groups);
__dso_public struct group *sudo_getgrgid(gid_t); __dso_public struct group *sudo_getgrgid(gid_t);
__dso_public struct group *sudo_getgrnam(const char *); __dso_public struct group *sudo_getgrnam(const char *);
__dso_public void sudo_gr_addref(struct group *); __dso_public void sudo_gr_addref(struct group *);
@@ -327,6 +331,7 @@ void sudo_pw_addref(struct passwd *);
void sudo_pw_delref(struct passwd *); void sudo_pw_delref(struct passwd *);
int sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type); int sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type);
int sudo_set_grlist(struct passwd *pw, char * const *groups); int sudo_set_grlist(struct passwd *pw, char * const *groups);
void sudo_pwutil_set_backend(sudo_make_pwitem_t, sudo_make_gritem_t, sudo_make_gidlist_item_t, sudo_make_grlist_item_t);
void sudo_setspent(void); void sudo_setspent(void);
/* timestr.c */ /* timestr.c */