From 14ee65c5255f7bfbe5917c6c27d3be2f66a8e2c0 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 22 Mar 2018 13:24:41 -0600 Subject: [PATCH] Add -M option to cvtsudoers to force the use of the local passwd and group databases when matching. --- doc/cvtsudoers.cat | 12 ++++++++- doc/cvtsudoers.man.in | 17 +++++++++++- doc/cvtsudoers.mdoc.in | 16 ++++++++++- plugins/sudoers/cvtsudoers.c | 22 +++++++++++---- plugins/sudoers/cvtsudoers.h | 26 ++++++++++-------- plugins/sudoers/cvtsudoers_pwutil.c | 8 +++--- plugins/sudoers/pwutil.c | 42 +++++++++++++++++++++++------ plugins/sudoers/sudoers.h | 5 ++++ 8 files changed, 117 insertions(+), 31 deletions(-) diff --git a/doc/cvtsudoers.cat b/doc/cvtsudoers.cat index eec3a9174..75d0cac50 100644 --- a/doc/cvtsudoers.cat +++ b/doc/cvtsudoers.cat @@ -4,7 +4,7 @@ NNAAMMEE ccvvttssuuddooeerrss - convert between sudoers file formats 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] [--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 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 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 diff --git a/doc/cvtsudoers.man.in b/doc/cvtsudoers.man.in index f08e7e328..1cff19d31 100644 --- a/doc/cvtsudoers.man.in +++ b/doc/cvtsudoers.man.in @@ -25,7 +25,7 @@ .SH "SYNOPSIS" .HP 11n \fBcvtsudoers\fR -[\fB\-ehV\fR] +[\fB\-ehMV\fR] [\fB\-b\fR\ \fIdn\fR] [\fB\-c\fR\ \fIconf_file\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 be displayed. .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 Write the converted output to \fIoutput_file\fR. diff --git a/doc/cvtsudoers.mdoc.in b/doc/cvtsudoers.mdoc.in index ce1e5630e..2792e1c72 100644 --- a/doc/cvtsudoers.mdoc.in +++ b/doc/cvtsudoers.mdoc.in @@ -22,7 +22,7 @@ .Nd convert between sudoers file formats .Sh SYNOPSIS .Nm cvtsudoers -.Op Fl ehV +.Op Fl ehMV .Op Fl b Ar dn .Op Fl c Ar conf_file .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. Only aliases that are referenced by the filtered policy rules will 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 Write the converted output to .Ar output_file . diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index 4cd556252..7ad26bbe3 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -56,7 +56,7 @@ struct cvtsudoers_filter *filters; struct sudo_user sudo_user; 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[] = { { "base", required_argument, NULL, 'b' }, { "config", required_argument, NULL, 'c' }, @@ -66,6 +66,7 @@ static struct option long_opts[] = { { "input-format", required_argument, NULL, 'i' }, { "increment", required_argument, NULL, 'I' }, { "match", required_argument, NULL, 'm' }, + { "match-local", no_argument, NULL, 'M' }, { "order-start", required_argument, NULL, 'O' }, { "output", required_argument, NULL, 'o' }, { "suppress", required_argument, NULL, 's' }, @@ -93,6 +94,7 @@ main(int argc, char *argv[]) enum sudoers_formats output_format = format_ldif; enum sudoers_formats input_format = format_sudoers; struct cvtsudoers_config *conf = NULL; + bool match_local = false; const char *input_file = "-"; const char *output_file = "-"; const char *conf_file = _PATH_CVTSUDOERS_CONF; @@ -187,6 +189,9 @@ main(int argc, char *argv[]) case 'm': conf->filter = optarg; break; + case 'M': + match_local = true; + break; case 'o': output_file = optarg; 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. */ get_hostname(); @@ -610,7 +621,7 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen) return fopen(sudoers, "r"); } -bool +static bool userlist_matches_filter(struct member_list *userlist) { struct cvtsudoers_string *s; @@ -658,7 +669,7 @@ userlist_matches_filter(struct member_list *userlist) debug_return_bool(matches); } -bool +static bool hostlist_matches_filter(struct member_list *hostlist) { struct cvtsudoers_string *s; @@ -1011,7 +1022,7 @@ done: static void 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] " "[-m filter] [-o output_file] [-O start_point] [-s sections] " "[input_file]\n", getprogname()); @@ -1031,7 +1042,8 @@ help(void) " -i, --input-format=format set input format: LDIF or sudoers\n" " -I, --increment=num amount to increase each sudoOrder by\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, --order-start=num starting point for first sudoOrder\n" " -s, --suppress=sections suppress output of certain sections\n" diff --git a/plugins/sudoers/cvtsudoers.h b/plugins/sudoers/cvtsudoers.h index c3ff522ee..4ec4f3bf1 100644 --- a/plugins/sudoers/cvtsudoers.h +++ b/plugins/sudoers/cvtsudoers.h @@ -74,21 +74,25 @@ struct cvtsudoers_filter { struct cvtsudoers_str_list hosts; }; -bool convert_sudoers_json(const char *output_file, struct cvtsudoers_config *conf); -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); - -struct member_list; -struct userspec_list; -bool userlist_matches_filter(struct member_list *userlist); -bool hostlist_matches_filter(struct member_list *hostlist); - +/* cvtsudoers.c */ +extern struct cvtsudoers_filter *filters; struct cvtsudoers_str_list *str_list_alloc(void); void str_list_free(void *v); struct cvtsudoers_string *cvtsudoers_string_alloc(const char *s); 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 */ diff --git a/plugins/sudoers/cvtsudoers_pwutil.c b/plugins/sudoers/cvtsudoers_pwutil.c index 4f8de07b5..9314b22c4 100644 --- a/plugins/sudoers/cvtsudoers_pwutil.c +++ b/plugins/sudoers/cvtsudoers_pwutil.c @@ -73,7 +73,7 @@ do { \ * to ENOMEM or ENOENT respectively. */ 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]; 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. */ 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]; 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). */ 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) { 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(). */ 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; size_t nsize, ngroups, total, len; diff --git a/plugins/sudoers/pwutil.c b/plugins/sudoers/pwutil.c index 26235812a..e170c31e5 100644 --- a/plugins/sudoers/pwutil.c +++ b/plugins/sudoers/pwutil.c @@ -54,6 +54,14 @@ static int cmp_pwuid(const void *, const void *); static int cmp_pwnam(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 /* @@ -68,6 +76,24 @@ static int cmp_grgid(const void *, const void *); # define getauthregistry(u, r) ((r)[0] = '\0') #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. * 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 aix_setauthdb(IDtouser(uid), key.registry); #endif - item = sudo_make_pwitem(uid, NULL); + item = make_pwitem(uid, NULL); #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif @@ -250,7 +276,7 @@ sudo_getpwnam(const char *name) #ifdef HAVE_SETAUTHDB aix_setauthdb((char *) name, key.registry); #endif - item = sudo_make_pwitem((uid_t)-1, name); + item = make_pwitem((uid_t)-1, name); #ifdef HAVE_SETAUTHDB aix_restoreauthdb(); #endif @@ -497,7 +523,7 @@ sudo_getgrgid(gid_t gid) /* * 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 (errno != ENOENT || (item = calloc(1, sizeof(*item))) == NULL) { 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. */ - item = sudo_make_gritem((gid_t)-1, name); + item = make_gritem((gid_t)-1, name); if (item == NULL) { const size_t len = strlen(name) + 1; 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. */ - item = sudo_make_grlist_item(pw, NULL); + item = make_grlist_item(pw, NULL); if (item == NULL) { /* Out of memory? */ debug_return_ptr(NULL); @@ -843,7 +869,7 @@ sudo_set_grlist(struct passwd *pw, char * const *groups) key.k.name = pw->pw_name; getauthregistry(NULL, key.registry); 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); 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. */ - item = sudo_make_gidlist_item(pw, NULL, type); + item = make_gidlist_item(pw, NULL, type); if (item == NULL) { /* Out of memory? */ debug_return_ptr(NULL); @@ -947,7 +973,7 @@ sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type) key.type = type; getauthregistry(NULL, key.registry); 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); debug_return_int(-1); } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 0825181f8..a8139f9e0 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -304,6 +304,10 @@ int display_privs(struct sudo_nss_list *, struct passwd *); int display_cmnd(struct sudo_nss_list *, struct passwd *); /* 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_getgrnam(const char *); __dso_public void sudo_gr_addref(struct group *); @@ -327,6 +331,7 @@ void sudo_pw_addref(struct passwd *); void sudo_pw_delref(struct passwd *); int sudo_set_gidlist(struct passwd *pw, char * const *gids, unsigned int type); 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); /* timestr.c */ -- 2.40.0