mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-22 01:49:11 +00:00
Initial support filtering by user, group and host in cvtsudoers.
Currently forces alias expansion when a filter is applied and the entire matching user or host list is printed, even the non-matching entries. This effectively allows you to grep sudoers by user, group and host.
This commit is contained in:
parent
bc5e2d06a7
commit
ff79de8592
@ -4,9 +4,9 @@ NNAAMMEE
|
||||
ccvvttssuuddooeerrss - convert between sudoers file formats
|
||||
|
||||
SSYYNNOOPPSSIISS
|
||||
ccvvttssuuddooeerrss [--eehhVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--II _i_n_c_r_e_m_e_n_t] [--ii _i_n_p_u_t___f_o_r_m_a_t]
|
||||
[--ff _o_u_t_p_u_t___f_o_r_m_a_t] [--OO _s_t_a_r_t___p_o_i_n_t] [--oo _o_u_t_p_u_t___f_i_l_e]
|
||||
[_i_n_p_u_t___f_i_l_e]
|
||||
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]
|
||||
[--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] [_i_n_p_u_t___f_i_l_e]
|
||||
|
||||
DDEESSCCRRIIPPTTIIOONN
|
||||
ccvvttssuuddooeerrss can be used to convert between _s_u_d_o_e_r_s security policy file
|
||||
@ -52,14 +52,13 @@ DDEESSCCRRIIPPTTIIOONN
|
||||
|
||||
Conversion to LDIF has the following limitations:
|
||||
|
||||
++oo Command, host, runas and user-specific
|
||||
Defaults lines cannot be translated as they
|
||||
don't have an equivalent in the sudoers LDAP
|
||||
schema.
|
||||
++oo Command, host, runas and user-specific Defaults
|
||||
lines cannot be translated as they don't have an
|
||||
equivalent in the sudoers LDAP schema.
|
||||
|
||||
++oo Command, host, runas and user aliases are not
|
||||
supported by the sudoers LDAP schema so they
|
||||
are expanded during the conversion.
|
||||
++oo Command, host, runas and user aliases are not
|
||||
supported by the sudoers LDAP schema so they are
|
||||
expanded during the conversion.
|
||||
|
||||
sudoers Traditional sudoers format. A new sudoers file
|
||||
will be reconstructed from the parsed input file.
|
||||
@ -68,11 +67,6 @@ DDEESSCCRRIIPPTTIIOONN
|
||||
|
||||
--hh, ----hheellpp Display a short help message to the standard output and exit.
|
||||
|
||||
--II _i_n_c_r_e_m_e_n_t, ----iinnccrreemmeenntt=_i_n_c_r_e_m_e_n_t
|
||||
When generating LDIF output, increment each sudoOrder
|
||||
attribute by the specified number. Defaults to an increment
|
||||
of 1.
|
||||
|
||||
--ii _i_n_p_u_t___f_o_r_m_a_t, ----iinnppuutt--ffoorrmmaatt=_i_n_p_u_t___f_o_r_m_a_t
|
||||
Specify the input format. The following formats are
|
||||
supported:
|
||||
@ -88,6 +82,28 @@ DDEESSCCRRIIPPTTIIOONN
|
||||
sudoers Traditional sudoers format. This is the default
|
||||
input format.
|
||||
|
||||
--II _i_n_c_r_e_m_e_n_t, ----iinnccrreemmeenntt=_i_n_c_r_e_m_e_n_t
|
||||
When generating LDIF output, increment each sudoOrder
|
||||
attribute by the specified number. Defaults to an increment
|
||||
of 1.
|
||||
|
||||
--mm _f_i_l_t_e_r, ----mmaattcchh=_f_i_l_t_e_r
|
||||
Only output rules that match the specified _f_i_l_t_e_r. A _f_i_l_t_e_r
|
||||
expression is made up of one or more kkeeyy == _v_a_l_u_e pairs,
|
||||
separated by a comma (`,'). The kkeeyy may be "user", "group"
|
||||
or "host". For example, uusseerr = _o_p_e_r_a_t_o_r or hhoosstt = _w_w_w.
|
||||
|
||||
The password and group databases are not consulted when
|
||||
matching 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.
|
||||
|
||||
--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
|
||||
will be written to the standard output.
|
||||
|
||||
--OO _s_t_a_r_t___p_o_i_n_t, ----oorrddeerr--ssttaarrtt=_s_t_a_r_t___p_o_i_n_t
|
||||
When generating LDIF output, use the number specified by
|
||||
_s_t_a_r_t___p_o_i_n_t in the sudoOrder attribute of the first sudoRole
|
||||
@ -97,11 +113,6 @@ DDEESSCCRRIIPPTTIIOONN
|
||||
point of 0 will disable the generation of sudoOrder
|
||||
attributes in the resulting LDIF file.
|
||||
|
||||
--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
|
||||
will be written to the standard output.
|
||||
|
||||
--VV, ----vveerrssiioonn
|
||||
Print the ccvvttssuuddooeerrss and _s_u_d_o_e_r_s grammar versions and exit.
|
||||
|
||||
@ -115,6 +126,9 @@ DDEESSCCRRIIPPTTIIOONN
|
||||
iinnppuutt__ffoorrmmaatt == _l_d_i_f | _s_u_d_o_e_r_s
|
||||
See the description of the --ii command line option.
|
||||
|
||||
mmaattcchh == _f_i_l_t_e_r
|
||||
See the description of the --mm command line option.
|
||||
|
||||
oorrddeerr__iinnccrreemmeenntt == _i_n_c_r_e_m_e_n_t
|
||||
See the description of the --II command line option.
|
||||
|
||||
@ -162,4 +176,4 @@ DDIISSCCLLAAIIMMEERR
|
||||
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
|
||||
complete details.
|
||||
|
||||
Sudo 1.8.23 February 23, 2018 Sudo 1.8.23
|
||||
Sudo 1.8.23 March 21, 2018 Sudo 1.8.23
|
||||
|
@ -16,7 +16,7 @@
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.TH "CVTSUDOERS" "8" "February 23, 2018" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
||||
.TH "CVTSUDOERS" "8" "March 21, 2018" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
||||
.nh
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@ -28,11 +28,12 @@
|
||||
[\fB\-ehV\fR]
|
||||
[\fB\-b\fR\ \fIdn\fR]
|
||||
[\fB\-c\fR\ \fIconf_file\fR]
|
||||
[\fB\-I\fR\ \fIincrement\fR]
|
||||
[\fB\-i\fR\ \fIinput_format\fR]
|
||||
[\fB\-f\fR\ \fIoutput_format\fR]
|
||||
[\fB\-O\fR\ \fIstart_point\fR]
|
||||
[\fB\-i\fR\ \fIinput_format\fR]
|
||||
[\fB\-I\fR\ \fIincrement\fR]
|
||||
[\fB\-m\fR\ \fIfilter\fR]
|
||||
[\fB\-o\fR\ \fIoutput_file\fR]
|
||||
[\fB\-O\fR\ \fIstart_point\fR]
|
||||
[\fIinput_file\fR]
|
||||
.SH "DESCRIPTION"
|
||||
\fBcvtsudoers\fR
|
||||
@ -105,12 +106,12 @@ Conversion to LDIF has the following limitations:
|
||||
.PP
|
||||
.RS 10n
|
||||
.PD 0
|
||||
.TP 6n
|
||||
.TP 3n
|
||||
\fB\(bu\fR
|
||||
Command, host, runas and user-specific Defaults lines cannot be
|
||||
translated as they don't have an equivalent in the sudoers LDAP schema.
|
||||
.PD
|
||||
.TP 6n
|
||||
.TP 3n
|
||||
\fB\(bu\fR
|
||||
Command, host, runas and user aliases are not supported by the
|
||||
sudoers LDAP schema so they are expanded during the conversion.
|
||||
@ -132,11 +133,6 @@ output inline.
|
||||
\fB\-h\fR, \fB\--help\fR
|
||||
Display a short help message to the standard output and exit.
|
||||
.TP 12n
|
||||
\fB\-I\fR \fIincrement\fR, \fB\--increment\fR=\fIincrement\fR
|
||||
When generating LDIF output, increment each sudoOrder attribute by
|
||||
the specified number.
|
||||
Defaults to an increment of 1.
|
||||
.TP 12n
|
||||
\fB\-i\fR \fIinput_format\fR, \fB\--input-format\fR=\fIinput_format\fR
|
||||
Specify the input format.
|
||||
The following formats are supported:
|
||||
@ -162,6 +158,49 @@ This is the default input format.
|
||||
.RE
|
||||
.PD
|
||||
.TP 12n
|
||||
\fB\-I\fR \fIincrement\fR, \fB\--increment\fR=\fIincrement\fR
|
||||
When generating LDIF output, increment each sudoOrder attribute by
|
||||
the specified number.
|
||||
Defaults to an increment of 1.
|
||||
.TP 12n
|
||||
\fB\-m\fR \fIfilter\fR, \fB\--match\fR=\fIfilter\fR
|
||||
Only output rules that match the specified
|
||||
\fIfilter\fR.
|
||||
A
|
||||
\fIfilter\fR
|
||||
expression is made up of one or more
|
||||
\fBkey =\fR \fIvalue\fR
|
||||
pairs, separated by a comma
|
||||
(\(oq\&,\(cq).
|
||||
The
|
||||
\fBkey\fR
|
||||
may be
|
||||
\(Lquser\(Rq,
|
||||
\(Lqgroup\(Rq
|
||||
or
|
||||
\(Lqhost\(Rq.
|
||||
For example,
|
||||
\fBuser\fR = \fIoperator\fR
|
||||
or
|
||||
\fBhost\fR = \fIwww\fR.
|
||||
.sp
|
||||
The password and group databases are not consulted when matching
|
||||
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.
|
||||
.TP 12n
|
||||
\fB\-o\fR \fIoutput_file\fR, \fB\--output\fR=\fIoutput_file\fR
|
||||
Write the converted output to
|
||||
\fIoutput_file\fR.
|
||||
If no
|
||||
\fIoutput_file\fR
|
||||
is specified, or if it is
|
||||
\(oq-\(cq,
|
||||
the converted
|
||||
\fIsudoers\fR
|
||||
policy will be written to the standard output.
|
||||
.TP 12n
|
||||
\fB\-O\fR \fIstart_point\fR, \fB\--order-start\fR=\fIstart_point\fR
|
||||
When generating LDIF output, use the number specified by
|
||||
\fIstart_point\fR
|
||||
@ -175,17 +214,6 @@ 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\-o\fR \fIoutput_file\fR, \fB\--output\fR=\fIoutput_file\fR
|
||||
Write the converted output to
|
||||
\fIoutput_file\fR.
|
||||
If no
|
||||
\fIoutput_file\fR
|
||||
is specified, or if it is
|
||||
\(oq-\(cq,
|
||||
the converted
|
||||
\fIsudoers\fR
|
||||
policy will be written to the standard output.
|
||||
.TP 12n
|
||||
\fB\-V\fR, \fB\--version\fR
|
||||
Print the
|
||||
\fBcvtsudoers\fR
|
||||
@ -210,6 +238,11 @@ See the description of the
|
||||
\fB\-i\fR
|
||||
command line option.
|
||||
.TP 6n
|
||||
\fBmatch =\fR \fIfilter\fR
|
||||
See the description of the
|
||||
\fB\-m\fR
|
||||
command line option.
|
||||
.TP 6n
|
||||
\fBorder_increment =\fR \fIincrement\fR
|
||||
See the description of the
|
||||
\fB\-I\fR
|
||||
|
@ -14,7 +14,7 @@
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd February 23, 2018
|
||||
.Dd March 21, 2018
|
||||
.Dt CVTSUDOERS @mansectsu@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@ -25,11 +25,12 @@
|
||||
.Op Fl ehV
|
||||
.Op Fl b Ar dn
|
||||
.Op Fl c Ar conf_file
|
||||
.Op Fl I Ar increment
|
||||
.Op Fl i Ar input_format
|
||||
.Op Fl f Ar output_format
|
||||
.Op Fl O Ar start_point
|
||||
.Op Fl i Ar input_format
|
||||
.Op Fl I Ar increment
|
||||
.Op Fl m Ar filter
|
||||
.Op Fl o Ar output_file
|
||||
.Op Fl O Ar start_point
|
||||
.Op Ar input_file
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
@ -91,7 +92,7 @@ server for use with
|
||||
.Xr sudoers.ldap @mansectform@ .
|
||||
.Pp
|
||||
Conversion to LDIF has the following limitations:
|
||||
.Bl -bullet -width 4n
|
||||
.Bl -bullet -width 1n
|
||||
.It
|
||||
Command, host, runas and user-specific Defaults lines cannot be
|
||||
translated as they don't have an equivalent in the sudoers LDAP schema.
|
||||
@ -107,10 +108,6 @@ output inline.
|
||||
.El
|
||||
.It Fl h , Fl -help
|
||||
Display a short help message to the standard output and exit.
|
||||
.It Fl I Ar increment , Fl -increment Ns = Ns Ar increment
|
||||
When generating LDIF output, increment each sudoOrder attribute by
|
||||
the specified number.
|
||||
Defaults to an increment of 1.
|
||||
.It Fl i Ar input_format , Fl -input-format Ns = Ns Ar input_format
|
||||
Specify the input format.
|
||||
The following formats are supported:
|
||||
@ -127,6 +124,46 @@ LDIF to sudoers format.
|
||||
Traditional sudoers format.
|
||||
This is the default input format.
|
||||
.El
|
||||
.It Fl I Ar increment , Fl -increment Ns = Ns Ar increment
|
||||
When generating LDIF output, increment each sudoOrder attribute by
|
||||
the specified number.
|
||||
Defaults to an increment of 1.
|
||||
.It Fl m Ar filter , Fl -match Ns = Ns Ar filter
|
||||
Only output rules that match the specified
|
||||
.Ar filter .
|
||||
A
|
||||
.Ar filter
|
||||
expression is made up of one or more
|
||||
.Sy key = Ar value
|
||||
pairs, separated by a comma
|
||||
.Pq Ql \&, .
|
||||
The
|
||||
.Sy key
|
||||
may be
|
||||
.Dq user ,
|
||||
.Dq group
|
||||
or
|
||||
.Dq host .
|
||||
For example,
|
||||
.Sy user No = Ar operator
|
||||
or
|
||||
.Sy host No = Ar www .
|
||||
.Pp
|
||||
The password and group databases are not consulted when matching
|
||||
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 o Ar output_file , Fl -output Ns = Ns Ar output_file
|
||||
Write the converted output to
|
||||
.Ar output_file .
|
||||
If no
|
||||
.Ar output_file
|
||||
is specified, or if it is
|
||||
.Ql - ,
|
||||
the converted
|
||||
.Em sudoers
|
||||
policy will be written to the standard output.
|
||||
.It Fl O Ar start_point , Fl -order-start Ns = Ns Ar start_point
|
||||
When generating LDIF output, use the number specified by
|
||||
.Ar start_point
|
||||
@ -139,16 +176,6 @@ 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 o Ar output_file , Fl -output Ns = Ns Ar output_file
|
||||
Write the converted output to
|
||||
.Ar output_file .
|
||||
If no
|
||||
.Ar output_file
|
||||
is specified, or if it is
|
||||
.Ql - ,
|
||||
the converted
|
||||
.Em sudoers
|
||||
policy will be written to the standard output.
|
||||
.It Fl V , -version
|
||||
Print the
|
||||
.Nm
|
||||
@ -172,6 +199,10 @@ command line option.
|
||||
See the description of the
|
||||
.Fl i
|
||||
command line option.
|
||||
.It Sy match = Ar filter
|
||||
See the description of the
|
||||
.Fl m
|
||||
command line option.
|
||||
.It Sy order_increment = Ar increment
|
||||
See the description of the
|
||||
.Fl I
|
||||
|
@ -163,7 +163,8 @@ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
|
||||
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o
|
||||
|
||||
CVTSUDOERS_OBJS = cvtsudoers.o cvtsudoers_json.o cvtsudoers_ldif.o \
|
||||
fmtsudoers.o locale.o stubs.o sudo_printf.o ldap_util.o
|
||||
cvtsudoers_pwutil.o fmtsudoers.o locale.o stubs.o \
|
||||
sudo_printf.o ldap_util.o
|
||||
|
||||
REPLAY_OBJS = getdate.o sudoreplay.o
|
||||
|
||||
@ -747,14 +748,26 @@ cvtsudoers_ldif.o: $(srcdir)/cvtsudoers_ldif.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_plugin.h \
|
||||
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
|
||||
$(srcdir)/cvtsudoers.h $(srcdir)/defaults.h \
|
||||
$(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/redblack.h \
|
||||
$(srcdir)/sudo_ldap.h $(srcdir)/sudo_nss.h \
|
||||
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.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)/cvtsudoers.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
|
||||
$(srcdir)/redblack.h $(srcdir)/sudo_ldap.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
|
||||
cvtsudoers_pwutil.o: $(srcdir)/cvtsudoers_pwutil.c $(devdir)/def_data.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)/cvtsudoers.h \
|
||||
$(srcdir)/defaults.h $(srcdir)/logging.h \
|
||||
$(srcdir)/pwutil.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_pwutil.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 \
|
||||
$(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
|
||||
@ -1321,10 +1334,10 @@ sudoreplay.o: $(srcdir)/sudoreplay.c $(incdir)/compat/getopt.h \
|
||||
$(top_builddir)/pathnames.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/sudoreplay.c
|
||||
testsudoers.o: $(srcdir)/testsudoers.c $(devdir)/def_data.h $(devdir)/gram.h \
|
||||
$(incdir)/compat/fnmatch.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)/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)/interfaces.h $(srcdir)/logging.h \
|
||||
$(srcdir)/parse.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
|
||||
|
@ -39,7 +39,7 @@
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
struct rbtree *aliases;
|
||||
static struct rbtree *aliases;
|
||||
|
||||
/*
|
||||
* Comparison function for the red-black tree.
|
||||
@ -166,6 +166,20 @@ no_aliases(void)
|
||||
debug_return_bool(rbisempty(aliases));
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace the aliases tree with a new one, returns the old.
|
||||
*/
|
||||
struct rbtree *
|
||||
replace_aliases(struct rbtree *new_aliases)
|
||||
{
|
||||
struct rbtree *old_aliases = aliases;
|
||||
debug_decl(replace_aliases, SUDOERS_DEBUG_ALIAS)
|
||||
|
||||
aliases = new_aliases;
|
||||
|
||||
debug_return_ptr(old_aliases);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free memory used by an alias struct and its members.
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "sudoers_version.h"
|
||||
#include "sudo_conf.h"
|
||||
#include "sudo_lbuf.h"
|
||||
#include "redblack.h"
|
||||
#include "cvtsudoers.h"
|
||||
#include <gram.h>
|
||||
|
||||
@ -51,9 +53,10 @@
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
struct cvtsudoers_filter *filters;
|
||||
struct sudo_user sudo_user;
|
||||
struct passwd *list_pw;
|
||||
static const char short_opts[] = "b:c:ef:hi:I:o:O:V";
|
||||
static const char short_opts[] = "b:c:ef:hi:I:m:o:O:V";
|
||||
static struct option long_opts[] = {
|
||||
{ "base", required_argument, NULL, 'b' },
|
||||
{ "config", required_argument, NULL, 'c' },
|
||||
@ -62,6 +65,7 @@ static struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "input-format", required_argument, NULL, 'i' },
|
||||
{ "increment", required_argument, NULL, 'I' },
|
||||
{ "match", required_argument, NULL, 'm' },
|
||||
{ "order-start", required_argument, NULL, 'O' },
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
@ -73,8 +77,12 @@ static void help(void) __attribute__((__noreturn__));
|
||||
static void usage(int);
|
||||
static bool convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf);
|
||||
static bool parse_sudoers(const char *input_file, struct cvtsudoers_config *conf);
|
||||
static bool parse_filter(char *expression);
|
||||
static bool alias_remove_unused(void);
|
||||
static struct cvtsudoers_config *cvtsudoers_conf_read(const char *conf_file);
|
||||
static void cvtsudoers_conf_free(struct cvtsudoers_config *conf);
|
||||
static void filter_userspecs(void);
|
||||
static void filter_defaults(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
@ -174,6 +182,9 @@ main(int argc, char *argv[])
|
||||
usage(1);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
conf->filter = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output_file = optarg;
|
||||
break;
|
||||
@ -223,6 +234,11 @@ main(int argc, char *argv[])
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
if (conf->filter != NULL) {
|
||||
/* We always expand aliases when filtering (may change in future). */
|
||||
if (!parse_filter(conf->filter))
|
||||
usage(1);
|
||||
}
|
||||
|
||||
/* If no base DN specified, check SUDOERS_BASE. */
|
||||
if (conf->sudoers_base == NULL) {
|
||||
@ -269,6 +285,15 @@ main(int argc, char *argv[])
|
||||
sudo_fatalx("error: unhandled input %d", input_format);
|
||||
}
|
||||
|
||||
/* Apply filters. */
|
||||
if (conf->filter != NULL) {
|
||||
filter_userspecs();
|
||||
|
||||
filter_defaults();
|
||||
|
||||
alias_remove_unused();
|
||||
}
|
||||
|
||||
switch (output_format) {
|
||||
case format_json:
|
||||
exitcode = !convert_sudoers_json(output_file, conf);
|
||||
@ -299,6 +324,7 @@ static struct cvtsudoers_conf_table cvtsudoers_conf_vars[] = {
|
||||
{ "sudoers_base", CONF_STR, &cvtsudoers_config.sudoers_base },
|
||||
{ "input_format", CONF_STR, &cvtsudoers_config.input_format },
|
||||
{ "output_format", CONF_STR, &cvtsudoers_config.output_format },
|
||||
{ "match", CONF_STR, &cvtsudoers_config.filter },
|
||||
{ "expand_aliases", CONF_BOOL, &cvtsudoers_config.expand_aliases }
|
||||
};
|
||||
|
||||
@ -410,6 +436,60 @@ cvtsudoers_conf_free(struct cvtsudoers_config *conf)
|
||||
debug_return;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_filter(char *expression)
|
||||
{
|
||||
char *last = NULL, *cp = expression;
|
||||
debug_decl(parse_filter, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (filters == NULL) {
|
||||
if ((filters = malloc(sizeof(*filters))) == NULL) {
|
||||
sudo_fatalx(U_("%s: %s"), __func__,
|
||||
U_("unable to allocate memory"));
|
||||
}
|
||||
STAILQ_INIT(&filters->users);
|
||||
STAILQ_INIT(&filters->groups);
|
||||
STAILQ_INIT(&filters->hosts);
|
||||
}
|
||||
|
||||
for ((cp = strtok_r(cp, ",", &last)); cp != NULL; (cp = strtok_r(NULL, ",", &last))) {
|
||||
/*
|
||||
* Filter expression:
|
||||
* user=foo,group=bar,host=baz
|
||||
*/
|
||||
char *keyword;
|
||||
struct cvtsudoers_string *s;
|
||||
|
||||
if ((s = malloc(sizeof(*s))) == NULL) {
|
||||
sudo_fatalx(U_("%s: %s"), __func__,
|
||||
U_("unable to allocate memory"));
|
||||
}
|
||||
|
||||
/* Parse keyword = value */
|
||||
keyword = cp;
|
||||
if ((cp = strchr(cp, '=')) == NULL) {
|
||||
sudo_warnx(U_("invalid filter: %s"), keyword);;
|
||||
debug_return_bool(false);
|
||||
}
|
||||
*cp++ = '\0';
|
||||
s->str = cp;
|
||||
|
||||
if (strcmp(keyword, "user") == 0 ){
|
||||
STAILQ_INSERT_TAIL(&filters->users, s, entries);
|
||||
} else if (strcmp(keyword, "group") == 0 ){
|
||||
STAILQ_INSERT_TAIL(&filters->groups, s, entries);
|
||||
} else if (strcmp(keyword, "host") == 0 ){
|
||||
STAILQ_INSERT_TAIL(&filters->hosts, s, entries);
|
||||
} else {
|
||||
sudo_warnx(U_("invalid filter: %s"), keyword);;
|
||||
free(s);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_sudoers(const char *input_file, struct cvtsudoers_config *conf)
|
||||
{
|
||||
@ -446,6 +526,89 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
|
||||
return fopen(sudoers, "r");
|
||||
}
|
||||
|
||||
bool
|
||||
userlist_matches_filter(struct member_list *userlist)
|
||||
{
|
||||
struct cvtsudoers_string *s;
|
||||
bool matches = 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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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 (userlist_matches(pw, userlist) == true)
|
||||
matches = true;
|
||||
sudo_pw_delref(pw);
|
||||
if (matches)
|
||||
break;
|
||||
}
|
||||
|
||||
debug_return_bool(matches);
|
||||
}
|
||||
|
||||
bool
|
||||
hostlist_matches_filter(struct member_list *hostlist)
|
||||
{
|
||||
struct cvtsudoers_string *s;
|
||||
bool matches = false;
|
||||
debug_decl(hostlist_matches_filter, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (filters == NULL || STAILQ_EMPTY(&filters->hosts))
|
||||
debug_return_bool(true);
|
||||
|
||||
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) {
|
||||
sudo_fatalx(U_("%s: %s"), __func__,
|
||||
U_("unable to allocate memory"));
|
||||
}
|
||||
} else {
|
||||
user_srunhost = user_runhost;
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display Defaults entries
|
||||
*/
|
||||
@ -502,6 +665,195 @@ convert_sudoers_output(const char *buf)
|
||||
return fputs(buf, output_fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply filters to userspecs, removing non-matching entries.
|
||||
*/
|
||||
static void
|
||||
filter_userspecs(void)
|
||||
{
|
||||
struct userspec *us, *next_us;
|
||||
struct privilege *priv, *next_priv;
|
||||
debug_decl(filter_userspecs, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
/*
|
||||
* Does not currently prune out non-matching entries in the user or
|
||||
* host lists. It acts more like a grep than a true filter.
|
||||
* 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)) {
|
||||
TAILQ_REMOVE(&userspecs, us, entries);
|
||||
free_userspec(us);
|
||||
continue;
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, next_priv) {
|
||||
if (!hostlist_matches_filter(&priv->hostlist)) {
|
||||
TAILQ_REMOVE(&us->privileges, priv, entries);
|
||||
free_privilege(priv);
|
||||
}
|
||||
}
|
||||
if (TAILQ_EMPTY(&us->privileges)) {
|
||||
TAILQ_REMOVE(&userspecs, us, entries);
|
||||
free_userspec(us);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply filters to host/user-based Defaults, removing non-matching entries.
|
||||
*/
|
||||
static void
|
||||
filter_defaults(void)
|
||||
{
|
||||
struct defaults *def, *next;
|
||||
struct member_list *binding = NULL;
|
||||
debug_decl(filter_defaults, SUDOERS_DEBUG_DEFAULTS)
|
||||
|
||||
TAILQ_FOREACH_SAFE(def, &defaults, entries, next) {
|
||||
switch (def->type) {
|
||||
case DEFAULTS_USER:
|
||||
if (!userlist_matches_filter(def->binding)) {
|
||||
TAILQ_REMOVE(&defaults, def, entries);
|
||||
binding = free_default(def, binding);
|
||||
} else {
|
||||
binding = def->binding;
|
||||
}
|
||||
break;
|
||||
case DEFAULTS_HOST:
|
||||
if (!hostlist_matches_filter(def->binding)) {
|
||||
TAILQ_REMOVE(&defaults, def, entries);
|
||||
binding = free_default(def, binding);
|
||||
} else {
|
||||
binding = def->binding;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the alias of the specified type as well as any other aliases
|
||||
* referenced by that alias.
|
||||
* XXX - share with visudo
|
||||
*/
|
||||
static bool
|
||||
alias_remove_recursive(char *name, int type, struct rbtree *freelist)
|
||||
{
|
||||
struct member *m;
|
||||
struct alias *a;
|
||||
bool ret = true;
|
||||
debug_decl(alias_remove_recursive, SUDOERS_DEBUG_ALIAS)
|
||||
|
||||
if ((a = alias_remove(name, type)) != NULL) {
|
||||
TAILQ_FOREACH(m, &a->members, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, type, freelist))
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
if (rbinsert(freelist, a, NULL) != 0)
|
||||
ret = false;
|
||||
}
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove unreferenced aliases.
|
||||
* XXX - share with visudo
|
||||
*/
|
||||
static bool
|
||||
alias_remove_unused(void)
|
||||
{
|
||||
struct cmndspec *cs;
|
||||
struct member *m;
|
||||
struct privilege *priv;
|
||||
struct userspec *us;
|
||||
struct defaults *d;
|
||||
int atype, errors = 0;
|
||||
struct rbtree *used_aliases;
|
||||
struct rbtree *unused_aliases;
|
||||
debug_decl(alias_remove_unused, SUDOERS_DEBUG_ALIAS)
|
||||
|
||||
used_aliases = rbcreate(alias_compare);
|
||||
if (used_aliases == NULL) {
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
||||
/* Move referenced aliases to used_aliases. */
|
||||
TAILQ_FOREACH(us, &userspecs, entries) {
|
||||
TAILQ_FOREACH(m, &us->users, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, USERALIAS, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH(priv, &us->privileges, entries) {
|
||||
TAILQ_FOREACH(m, &priv->hostlist, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, HOSTALIAS, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
|
||||
if (cs->runasuserlist != NULL) {
|
||||
TAILQ_FOREACH(m, cs->runasuserlist, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, RUNASALIAS, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cs->runasgrouplist != NULL) {
|
||||
TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, RUNASALIAS, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((m = cs->cmnd)->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, CMNDALIAS, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH(d, &defaults, entries) {
|
||||
switch (d->type) {
|
||||
case DEFAULTS_HOST:
|
||||
atype = HOSTALIAS;
|
||||
break;
|
||||
case DEFAULTS_USER:
|
||||
atype = USERALIAS;
|
||||
break;
|
||||
case DEFAULTS_RUNAS:
|
||||
atype = RUNASALIAS;
|
||||
break;
|
||||
case DEFAULTS_CMND:
|
||||
atype = CMNDALIAS;
|
||||
break;
|
||||
default:
|
||||
continue; /* not an alias */
|
||||
}
|
||||
TAILQ_FOREACH(m, d->binding, entries) {
|
||||
if (m->type == ALIAS) {
|
||||
if (!alias_remove_recursive(m->name, atype, used_aliases))
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
unused_aliases = replace_aliases(used_aliases);
|
||||
rbdestroy(unused_aliases, alias_free);
|
||||
|
||||
debug_return_int(errors ? false : true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert back to sudoers.
|
||||
*/
|
||||
@ -571,7 +923,7 @@ usage(int fatal)
|
||||
{
|
||||
(void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehV] [-b dn] "
|
||||
"[-c conf_file ] [-f output_format] [-i input_format] [-I increment] "
|
||||
"[-o output_file] [-O start_point] [input_file]\n",
|
||||
"[-m filter] [-o output_file] [-O start_point] [input_file]\n",
|
||||
getprogname());
|
||||
if (fatal)
|
||||
exit(1);
|
||||
@ -586,11 +938,12 @@ help(void)
|
||||
" -b, --base=dn the base DN for sudo LDAP queries\n"
|
||||
" -e, --expand-aliases expand aliases when converting\n"
|
||||
" -f, --output-format=format set output format: JSON, LDIF or sudoers\n"
|
||||
" -I, --increment=num amount to increase each sudoOrder by\n"
|
||||
" -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"
|
||||
" -O, --order-start=num starting point for first sudoOrder\n"
|
||||
" -m, --match=filter only convert entries that match the filter expression\n"
|
||||
" -o, --output=output_file write converted sudoers to output_file\n"
|
||||
" -O, --order-start=num starting point for first sudoOrder\n"
|
||||
" -V, --version display version information and exit"));
|
||||
exit(0);
|
||||
}
|
||||
|
@ -24,11 +24,26 @@ enum sudoers_formats {
|
||||
format_sudoers
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple string list with optional reference count.
|
||||
* XXX - move this so fmtsudoers can use it
|
||||
*/
|
||||
struct cvtsudoers_string {
|
||||
STAILQ_ENTRY(cvtsudoers_string) entries;
|
||||
char *str;
|
||||
};
|
||||
struct cvtsudoers_str_list {
|
||||
struct cvtsudoers_string *stqh_first;
|
||||
struct cvtsudoers_string **stqh_last;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
/* cvtsudoers.conf settings */
|
||||
struct cvtsudoers_config {
|
||||
char *sudoers_base;
|
||||
char *input_format;
|
||||
char *output_format;
|
||||
char *filter;
|
||||
unsigned int sudo_order;
|
||||
unsigned int order_increment;
|
||||
bool expand_aliases;
|
||||
@ -36,7 +51,7 @@ struct cvtsudoers_config {
|
||||
};
|
||||
|
||||
/* Initial config settings for above. */
|
||||
#define INITIAL_CONFIG { NULL, NULL, NULL, 1, 1, false, true }
|
||||
#define INITIAL_CONFIG { NULL, NULL, NULL, NULL, 1, 1, false, true }
|
||||
|
||||
#define CONF_BOOL 0
|
||||
#define CONF_UINT 1
|
||||
@ -48,9 +63,27 @@ struct cvtsudoers_conf_table {
|
||||
void *valp; /* pointer into cvtsudoers_config */
|
||||
};
|
||||
|
||||
struct cvtsudoers_filter {
|
||||
struct cvtsudoers_str_list users;
|
||||
struct cvtsudoers_str_list groups;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
#endif /* SUDOERS_CVTSUDOERS_H */
|
||||
|
@ -465,7 +465,7 @@ print_userspecs_ldif(FILE *fp, struct cvtsudoers_config *conf)
|
||||
{
|
||||
struct userspec *us;
|
||||
debug_decl(print_userspecs_ldif, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
|
||||
TAILQ_FOREACH(us, &userspecs, entries) {
|
||||
if (!print_userspec_ldif(fp, us, conf))
|
||||
debug_return_bool(false);
|
||||
@ -513,36 +513,27 @@ convert_sudoers_ldif(const char *output_file, struct cvtsudoers_config *conf)
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
struct ldif_string {
|
||||
STAILQ_ENTRY(ldif_string) entries;
|
||||
char *str;
|
||||
};
|
||||
struct ldif_str_list {
|
||||
struct ldif_string *stqh_first;
|
||||
struct ldif_string **stqh_last;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
struct sudo_role {
|
||||
STAILQ_ENTRY(sudo_role) entries;
|
||||
char *cn;
|
||||
char *notbefore;
|
||||
char *notafter;
|
||||
double order;
|
||||
struct ldif_str_list *cmnds;
|
||||
struct ldif_str_list *hosts;
|
||||
struct ldif_str_list *users;
|
||||
struct ldif_str_list *runasusers;
|
||||
struct ldif_str_list *runasgroups;
|
||||
struct ldif_str_list *options;
|
||||
struct cvtsudoers_str_list *cmnds;
|
||||
struct cvtsudoers_str_list *hosts;
|
||||
struct cvtsudoers_str_list *users;
|
||||
struct cvtsudoers_str_list *runasusers;
|
||||
struct cvtsudoers_str_list *runasgroups;
|
||||
struct cvtsudoers_str_list *options;
|
||||
};
|
||||
STAILQ_HEAD(sudo_role_list, sudo_role);
|
||||
|
||||
static struct ldif_string *
|
||||
ldif_string_alloc(const char *s)
|
||||
/* XXX - move to cvtsudoers.c */
|
||||
struct cvtsudoers_string *
|
||||
cvtsudoers_string_alloc(const char *s)
|
||||
{
|
||||
struct ldif_string *ls;
|
||||
debug_decl(ldif_string_alloc, SUDOERS_DEBUG_UTIL)
|
||||
struct cvtsudoers_string *ls;
|
||||
debug_decl(cvtsudoers_string_alloc, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if ((ls = malloc(sizeof(*ls))) != NULL) {
|
||||
if ((ls->str = strdup(s)) == NULL) {
|
||||
@ -554,17 +545,17 @@ ldif_string_alloc(const char *s)
|
||||
debug_return_ptr(ls);
|
||||
}
|
||||
|
||||
static void
|
||||
ldif_string_free(struct ldif_string *ls)
|
||||
void
|
||||
cvtsudoers_string_free(struct cvtsudoers_string *ls)
|
||||
{
|
||||
free(ls->str);
|
||||
free(ls);
|
||||
}
|
||||
|
||||
static struct ldif_str_list *
|
||||
struct cvtsudoers_str_list *
|
||||
str_list_alloc(void)
|
||||
{
|
||||
struct ldif_str_list *strlist;
|
||||
struct cvtsudoers_str_list *strlist;
|
||||
debug_decl(str_list_alloc, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
strlist = malloc(sizeof(*strlist));
|
||||
@ -574,17 +565,17 @@ str_list_alloc(void)
|
||||
debug_return_ptr(strlist);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
str_list_free(void *v)
|
||||
{
|
||||
struct ldif_str_list *strlist = v;
|
||||
struct ldif_string *first;
|
||||
struct cvtsudoers_str_list *strlist = v;
|
||||
struct cvtsudoers_string *first;
|
||||
debug_decl(str_list_free, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
if (--strlist->refcnt == 0) {
|
||||
while ((first = STAILQ_FIRST(strlist)) != NULL) {
|
||||
STAILQ_REMOVE_HEAD(strlist, entries);
|
||||
ldif_string_free(first);
|
||||
cvtsudoers_string_free(first);
|
||||
}
|
||||
free(strlist);
|
||||
}
|
||||
@ -644,25 +635,25 @@ sudo_role_free(struct sudo_role *role)
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a struct ldif_string, store str in it and
|
||||
* Allocate a struct cvtsudoers_string, store str in it and
|
||||
* insert into the specified strlist.
|
||||
*/
|
||||
static void
|
||||
ldif_store_string(const char *str, struct ldif_str_list *strlist, bool sorted)
|
||||
ldif_store_string(const char *str, struct cvtsudoers_str_list *strlist, bool sorted)
|
||||
{
|
||||
struct ldif_string *ls;
|
||||
struct cvtsudoers_string *ls;
|
||||
debug_decl(ldif_store_string, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
while (isblank((unsigned char)*str))
|
||||
str++;
|
||||
if ((ls = ldif_string_alloc(str)) == NULL) {
|
||||
if ((ls = cvtsudoers_string_alloc(str)) == NULL) {
|
||||
sudo_fatalx(U_("%s: %s"), __func__,
|
||||
U_("unable to allocate memory"));
|
||||
}
|
||||
if (!sorted) {
|
||||
STAILQ_INSERT_TAIL(strlist, ls, entries);
|
||||
} else {
|
||||
struct ldif_string *prev, *next;
|
||||
struct cvtsudoers_string *prev, *next;
|
||||
|
||||
/* Insertion sort, list is small. */
|
||||
prev = STAILQ_FIRST(strlist);
|
||||
@ -683,13 +674,13 @@ ldif_store_string(const char *str, struct ldif_str_list *strlist, bool sorted)
|
||||
|
||||
/*
|
||||
* Iterator for sudo_ldap_role_to_priv().
|
||||
* Takes a pointer to a struct ldif_string *.
|
||||
* Takes a pointer to a struct cvtsudoers_string *.
|
||||
* Returns the string or NULL if we've reached the end.
|
||||
*/
|
||||
static char *
|
||||
ldif_string_iter(void **vp)
|
||||
char *
|
||||
cvtsudoers_string_iter(void **vp)
|
||||
{
|
||||
struct ldif_string *ls = *vp;
|
||||
struct cvtsudoers_string *ls = *vp;
|
||||
|
||||
if (ls == NULL)
|
||||
return NULL;
|
||||
@ -714,10 +705,10 @@ role_order_cmp(const void *va, const void *vb)
|
||||
* Parse list of sudoOption and store in global defaults list.
|
||||
*/
|
||||
static void
|
||||
ldif_store_options(struct ldif_str_list *options)
|
||||
ldif_store_options(struct cvtsudoers_str_list *options)
|
||||
{
|
||||
struct defaults *d;
|
||||
struct ldif_string *ls;
|
||||
struct cvtsudoers_string *ls;
|
||||
char *var, *val;
|
||||
debug_decl(ldif_store_options, SUDOERS_DEBUG_UTIL)
|
||||
|
||||
@ -748,10 +739,10 @@ ldif_store_options(struct ldif_str_list *options)
|
||||
static int
|
||||
str_list_cmp(const void *aa, const void *bb)
|
||||
{
|
||||
const struct ldif_str_list *a = aa;
|
||||
const struct ldif_str_list *b = bb;
|
||||
const struct ldif_string *lsa = STAILQ_FIRST(a);
|
||||
const struct ldif_string *lsb = STAILQ_FIRST(b);
|
||||
const struct cvtsudoers_str_list *a = aa;
|
||||
const struct cvtsudoers_str_list *b = bb;
|
||||
const struct cvtsudoers_string *lsa = STAILQ_FIRST(a);
|
||||
const struct cvtsudoers_string *lsb = STAILQ_FIRST(b);
|
||||
int ret;
|
||||
|
||||
while (lsa != NULL && lsb != NULL) {
|
||||
@ -764,9 +755,9 @@ str_list_cmp(const void *aa, const void *bb)
|
||||
}
|
||||
|
||||
static int
|
||||
str_list_cache(struct rbtree *cache, struct ldif_str_list **strlistp)
|
||||
str_list_cache(struct rbtree *cache, struct cvtsudoers_str_list **strlistp)
|
||||
{
|
||||
struct ldif_str_list *strlist = *strlistp;
|
||||
struct cvtsudoers_str_list *strlist = *strlistp;
|
||||
struct rbnode *node;
|
||||
int ret;
|
||||
debug_decl(str_list_cache, SUDOERS_DEBUG_UTIL)
|
||||
@ -797,7 +788,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options,
|
||||
bool reuse_userspec, bool reuse_privilege, bool reuse_runas)
|
||||
{
|
||||
struct privilege *priv;
|
||||
struct ldif_string *ls;
|
||||
struct cvtsudoers_string *ls;
|
||||
struct userspec *us;
|
||||
struct member *m;
|
||||
debug_decl(role_to_sudoers, SUDOERS_DEBUG_UTIL)
|
||||
@ -882,7 +873,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options,
|
||||
STAILQ_FIRST(role->runasusers), STAILQ_FIRST(role->runasgroups),
|
||||
STAILQ_FIRST(role->cmnds), STAILQ_FIRST(role->options),
|
||||
role->notbefore, role->notafter, true, store_options,
|
||||
ldif_string_iter);
|
||||
cvtsudoers_string_iter);
|
||||
if (priv == NULL) {
|
||||
sudo_fatalx(U_("%s: %s"), __func__,
|
||||
U_("unable to allocate memory"));
|
||||
|
479
plugins/sudoers/cvtsudoers_pwutil.c
Normal file
479
plugins/sudoers/cvtsudoers_pwutil.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998-2005, 2007-2017
|
||||
* 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.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRINGS_H */
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
#include "cvtsudoers.h"
|
||||
#include "pwutil.h"
|
||||
|
||||
#ifndef LOGIN_NAME_MAX
|
||||
# ifdef _POSIX_LOGIN_NAME_MAX
|
||||
# define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
|
||||
# else
|
||||
# define LOGIN_NAME_MAX 9
|
||||
# endif
|
||||
#endif /* LOGIN_NAME_MAX */
|
||||
|
||||
#define FIELD_SIZE(src, name, size) \
|
||||
do { \
|
||||
if ((src)->name) { \
|
||||
size = strlen((src)->name) + 1; \
|
||||
total += size; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FIELD_COPY(src, dst, name, size) \
|
||||
do { \
|
||||
if ((src)->name) { \
|
||||
memcpy(cp, (src)->name, size); \
|
||||
(dst)->name = cp; \
|
||||
cp += size; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Dynamically allocate space for a struct item plus the key and data
|
||||
* elements. If name is non-NULL it is used as the key, else the
|
||||
* uid is the key. Fills in datum from struct password.
|
||||
* Returns NULL on calloc error or unknown name/id, setting errno
|
||||
* to ENOMEM or ENOENT respectively.
|
||||
*/
|
||||
struct cache_item *
|
||||
sudo_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;
|
||||
struct cache_item_pw *pwitem;
|
||||
struct passwd pw, *newpw;
|
||||
struct cvtsudoers_string *s = NULL;
|
||||
debug_decl(sudo_make_pwitem, SUDOERS_DEBUG_NSS)
|
||||
|
||||
/* Look up name or uid in filter list. */
|
||||
if (name != NULL) {
|
||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||
if (strcasecmp(name, s->str) == 0) {
|
||||
uid = (uid_t)-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||
const char *errstr;
|
||||
uid_t filter_uid;
|
||||
|
||||
if (s->str[0] != '#')
|
||||
continue;
|
||||
|
||||
filter_uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
||||
if (errstr == NULL) {
|
||||
if (uid != filter_uid)
|
||||
continue;
|
||||
snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned int)uid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s == NULL) {
|
||||
errno = ENOENT;
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/* Fake up a passwd struct. */
|
||||
memset(&pw, 0, sizeof(pw));
|
||||
pw.pw_name = name ? s->str : uidstr;
|
||||
pw.pw_passwd = "*";
|
||||
pw.pw_uid = uid;
|
||||
pw.pw_gid = (gid_t)-1;
|
||||
pw.pw_shell = _PATH_BSHELL;
|
||||
pw.pw_dir = "/";
|
||||
|
||||
/* Allocate in one big chunk for easy freeing. */
|
||||
nsize = psize = csize = gsize = dsize = ssize = 0;
|
||||
total = sizeof(*pwitem);
|
||||
FIELD_SIZE(&pw, pw_name, nsize);
|
||||
FIELD_SIZE(&pw, pw_passwd, psize);
|
||||
#ifdef HAVE_LOGIN_CAP_H
|
||||
FIELD_SIZE(&pw, pw_class, csize);
|
||||
#endif
|
||||
FIELD_SIZE(&pw, pw_gecos, gsize);
|
||||
FIELD_SIZE(&pw, pw_dir, dsize);
|
||||
FIELD_SIZE(&pw, pw_shell, ssize);
|
||||
if (name != NULL)
|
||||
total += strlen(name) + 1;
|
||||
|
||||
/* Allocate space for struct item, struct passwd and the strings. */
|
||||
if ((pwitem = calloc(1, total)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate memory");
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
newpw = &pwitem->pw;
|
||||
|
||||
/*
|
||||
* Copy in passwd contents and make strings relative to space
|
||||
* at the end of the struct.
|
||||
*/
|
||||
memcpy(newpw, &pw, sizeof(pw));
|
||||
cp = (char *)(pwitem + 1);
|
||||
FIELD_COPY(&pw, newpw, pw_name, nsize);
|
||||
FIELD_COPY(&pw, newpw, pw_passwd, psize);
|
||||
#ifdef HAVE_LOGIN_CAP_H
|
||||
FIELD_COPY(&pw, newpw, pw_class, csize);
|
||||
#endif
|
||||
FIELD_COPY(&pw, newpw, pw_gecos, gsize);
|
||||
FIELD_COPY(&pw, newpw, pw_dir, dsize);
|
||||
FIELD_COPY(&pw, newpw, pw_shell, ssize);
|
||||
|
||||
/* Set key and datum. */
|
||||
if (name != NULL) {
|
||||
memcpy(cp, name, strlen(name) + 1);
|
||||
pwitem->cache.k.name = cp;
|
||||
} else {
|
||||
pwitem->cache.k.uid = pw.pw_uid;
|
||||
}
|
||||
pwitem->cache.d.pw = newpw;
|
||||
pwitem->cache.refcnt = 1;
|
||||
|
||||
debug_return_ptr(&pwitem->cache);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dynamically allocate space for a struct item plus the key and data
|
||||
* elements. If name is non-NULL it is used as the key, else the
|
||||
* gid is the key. Fills in datum from struct group.
|
||||
* Returns NULL on calloc error or unknown name/id, setting errno
|
||||
* to ENOMEM or ENOENT respectively.
|
||||
*/
|
||||
struct cache_item *
|
||||
sudo_make_gritem(gid_t gid, const char *name)
|
||||
{
|
||||
char *cp, gidstr[MAX_UID_T_LEN + 2];
|
||||
size_t nsize, psize, nmem, total, len;
|
||||
struct cache_item_gr *gritem;
|
||||
struct group gr, *newgr;
|
||||
struct cvtsudoers_string *s = NULL;
|
||||
debug_decl(sudo_make_gritem, SUDOERS_DEBUG_NSS)
|
||||
|
||||
/* Look up name or gid in filter list. */
|
||||
if (name != NULL) {
|
||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||
if (strcasecmp(name, s->str) == 0) {
|
||||
gid = (gid_t)-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||
const char *errstr;
|
||||
gid_t filter_gid;
|
||||
|
||||
if (s->str[0] != '#')
|
||||
continue;
|
||||
|
||||
filter_gid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
||||
if (errstr == NULL) {
|
||||
if (gid != filter_gid)
|
||||
continue;
|
||||
snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned int)gid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s == NULL) {
|
||||
errno = ENOENT;
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/* Fake up a group struct with all filter users as members. */
|
||||
memset(&gr, 0, sizeof(gr));
|
||||
gr.gr_name = name ? s->str : gidstr;
|
||||
gr.gr_gid = gid;
|
||||
|
||||
/* Allocate in one big chunk for easy freeing. */
|
||||
nsize = psize = nmem = 0;
|
||||
total = sizeof(*gritem);
|
||||
FIELD_SIZE(&gr, gr_name, nsize);
|
||||
FIELD_SIZE(&gr, gr_passwd, psize);
|
||||
if (!STAILQ_EMPTY(&filters->users)) {
|
||||
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||
total += strlen(s->str) + 1;
|
||||
nmem++;
|
||||
}
|
||||
total += sizeof(char *) * nmem;
|
||||
}
|
||||
if (name != NULL)
|
||||
total += strlen(name) + 1;
|
||||
|
||||
if ((gritem = calloc(1, total)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate memory");
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in group contents and make strings relative to space
|
||||
* at the end of the buffer. Note that gr_mem must come
|
||||
* immediately after struct group to guarantee proper alignment.
|
||||
*/
|
||||
newgr = &gritem->gr;
|
||||
memcpy(newgr, &gr, sizeof(gr));
|
||||
cp = (char *)(gritem + 1);
|
||||
if (nmem != 0) {
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
total += strlen(s->str) + 1;
|
||||
}
|
||||
}
|
||||
if (nmem != 0) {
|
||||
newgr->gr_mem = (char **)cp;
|
||||
cp += sizeof(char *) * nmem;
|
||||
nmem = 0;
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
len = strlen(s->str) + 1;
|
||||
memcpy(cp, s->str, len);
|
||||
newgr->gr_mem[nmem++] = cp;
|
||||
cp += len;
|
||||
}
|
||||
newgr->gr_mem[nmem] = NULL;
|
||||
}
|
||||
FIELD_COPY(&gr, newgr, gr_passwd, psize);
|
||||
FIELD_COPY(&gr, newgr, gr_name, nsize);
|
||||
|
||||
/* Set key and datum. */
|
||||
if (name != NULL) {
|
||||
memcpy(cp, name, strlen(name) + 1);
|
||||
gritem->cache.k.name = cp;
|
||||
} else {
|
||||
gritem->cache.k.gid = gr.gr_gid;
|
||||
}
|
||||
gritem->cache.d.gr = newgr;
|
||||
gritem->cache.refcnt = 1;
|
||||
|
||||
debug_return_ptr(&gritem->cache);
|
||||
}
|
||||
|
||||
static struct cache_item_gidlist *gidlist_item;
|
||||
|
||||
/*
|
||||
* Dynamically allocate space for a struct item plus the key and data
|
||||
* 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,
|
||||
unsigned int type)
|
||||
{
|
||||
char *cp;
|
||||
size_t nsize, total;
|
||||
struct cache_item_gidlist *glitem;
|
||||
struct cvtsudoers_string *s;
|
||||
struct gid_list *gidlist;
|
||||
GETGROUPS_T *gids = NULL;
|
||||
int i, ngids = 0;
|
||||
debug_decl(sudo_make_gidlist_item, SUDOERS_DEBUG_NSS)
|
||||
|
||||
/*
|
||||
* There's only a single gid list.
|
||||
*/
|
||||
if (gidlist_item != NULL) {
|
||||
gidlist_item->cache.refcnt++;
|
||||
debug_return_ptr(&gidlist_item->cache);
|
||||
}
|
||||
|
||||
/* Count number of possible gids in the filter. */
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
if (s->str[0] == '#')
|
||||
ngids++;
|
||||
}
|
||||
|
||||
/* Allocate gids[] array and fill it with parsed gids. */
|
||||
if (ngids != 0) {
|
||||
gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T));
|
||||
if (gids == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate memory");
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
ngids = 0;
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
if (s->str[0] == '#') {
|
||||
const char *errstr;
|
||||
gid_t gid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
||||
if (errstr == NULL) {
|
||||
/* Valid gid. */
|
||||
gids[ngids++] = gid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ngids == 0) {
|
||||
free(gids);
|
||||
errno = ENOENT;
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/* Allocate in one big chunk for easy freeing. */
|
||||
nsize = strlen(pw->pw_name) + 1;
|
||||
total = sizeof(*glitem) + nsize;
|
||||
total += sizeof(gid_t *) * ngids;
|
||||
|
||||
if ((glitem = calloc(1, total)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate memory");
|
||||
free(gids);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in group list and make pointers relative to space
|
||||
* at the end of the buffer. Note that the groups array must come
|
||||
* immediately after struct group to guarantee proper alignment.
|
||||
*/
|
||||
gidlist = &glitem->gidlist;
|
||||
cp = (char *)(glitem + 1);
|
||||
gidlist->gids = (gid_t *)cp;
|
||||
cp += sizeof(gid_t) * ngids;
|
||||
|
||||
/* Set key and datum. */
|
||||
memcpy(cp, pw->pw_name, nsize);
|
||||
glitem->cache.k.name = cp;
|
||||
glitem->cache.d.gidlist = gidlist;
|
||||
glitem->cache.refcnt = 1;
|
||||
glitem->cache.type = type;
|
||||
|
||||
/*
|
||||
* Store group IDs.
|
||||
*/
|
||||
for (i = 0; i < ngids; i++)
|
||||
gidlist->gids[i] = gids[i];
|
||||
gidlist->ngids = ngids;
|
||||
free(gids);
|
||||
|
||||
debug_return_ptr(&glitem->cache);
|
||||
}
|
||||
|
||||
static struct cache_item_gidlist *grlist_item;
|
||||
|
||||
/*
|
||||
* Dynamically allocate space for a struct item plus the key and data
|
||||
* 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)
|
||||
{
|
||||
char *cp;
|
||||
size_t nsize, ngroups, total, len;
|
||||
struct cache_item_grlist *grlitem;
|
||||
struct cvtsudoers_string *s;
|
||||
struct group_list *grlist;
|
||||
int groupname_len;
|
||||
debug_decl(sudo_make_grlist_item, SUDOERS_DEBUG_NSS)
|
||||
|
||||
/*
|
||||
* There's only a single group list.
|
||||
*/
|
||||
if (grlist_item != NULL) {
|
||||
grlist_item->cache.refcnt++;
|
||||
debug_return_ptr(&grlist_item->cache);
|
||||
}
|
||||
|
||||
/* Count number of groups in the filter. */
|
||||
ngroups = 0;
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
ngroups++;
|
||||
}
|
||||
|
||||
#ifdef _SC_LOGIN_NAME_MAX
|
||||
groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32);
|
||||
#else
|
||||
groupname_len = MAX(LOGIN_NAME_MAX, 32);
|
||||
#endif
|
||||
|
||||
/* Allocate in one big chunk for easy freeing. */
|
||||
nsize = strlen(pw->pw_name) + 1;
|
||||
total = sizeof(*grlitem) + nsize;
|
||||
total += groupname_len * ngroups;
|
||||
|
||||
again:
|
||||
if ((grlitem = calloc(1, total)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate memory");
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in group list and make pointers relative to space
|
||||
* at the end of the buffer. Note that the groups array must come
|
||||
* immediately after struct group to guarantee proper alignment.
|
||||
*/
|
||||
grlist = &grlitem->grlist;
|
||||
cp = (char *)(grlitem + 1);
|
||||
grlist->groups = (char **)cp;
|
||||
cp += sizeof(char *) * ngroups;
|
||||
|
||||
/* Set key and datum. */
|
||||
memcpy(cp, pw->pw_name, nsize);
|
||||
grlitem->cache.k.name = cp;
|
||||
grlitem->cache.d.grlist = grlist;
|
||||
grlitem->cache.refcnt = 1;
|
||||
cp += nsize;
|
||||
|
||||
/*
|
||||
* Copy groups from filter.
|
||||
*/
|
||||
ngroups = 0;
|
||||
STAILQ_FOREACH(s, &filters->groups, entries) {
|
||||
if (s->str[0] == '#') {
|
||||
const char *errstr;
|
||||
sudo_strtoid(s->str + 1, NULL, NULL, &errstr);
|
||||
if (errstr == NULL) {
|
||||
/* Group ID not name, ignore it. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
len = strlen(s->str) + 1;
|
||||
if (cp - (char *)grlitem + len > total) {
|
||||
total += len + groupname_len;
|
||||
free(grlitem);
|
||||
goto again;
|
||||
}
|
||||
memcpy(cp, s->str, len);
|
||||
grlist->groups[ngroups++] = cp;
|
||||
cp += len;
|
||||
}
|
||||
grlist->ngroups = ngroups;
|
||||
|
||||
debug_return_ptr(&grlitem->cache);
|
||||
}
|
@ -252,6 +252,7 @@ extern struct defaults_list defaults;
|
||||
|
||||
/* alias.c */
|
||||
bool no_aliases(void);
|
||||
struct rbtree *replace_aliases(struct rbtree *new_aliases);
|
||||
const char *alias_add(char *name, int type, char *file, int lineno, struct member *members);
|
||||
const char *alias_type_to_string(int alias_type);
|
||||
int alias_compare(const void *a1, const void *a2);
|
||||
|
Loading…
x
Reference in New Issue
Block a user