2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-30 05:48:18 +00:00

Do not follow symbolic links in sudoedit by default. This behavior

can be controlled by the sudoedit_follow Defaults flag as well as
the FOLLOW/NOFOLLOW tags.
This commit is contained in:
Todd C. Miller 2015-08-06 13:20:01 -06:00
parent 079167d2c4
commit 3354d27a17
35 changed files with 2447 additions and 2082 deletions

View File

@ -1,6 +1,13 @@
Notes on upgrading from an older release Notes on upgrading from an older release
======================================== ========================================
o Upgrading from a version prior to 1.8.15:
When editing files with sudoedit, symbolic links will no longer
be followed by default. The old behavior can be restored by
enabling the sudoedit_follow option in sudoers or on a per-command
basis with the FOLLOW and NOFOLLOW tags.
o Upgrading from a version prior to 1.8.14: o Upgrading from a version prior to 1.8.14:
On HP-UX, sudo will no longer check for "plugin.sl" if "plugin.so" On HP-UX, sudo will no longer check for "plugin.sl" if "plugin.so"

View File

@ -124,6 +124,13 @@ DDEESSCCRRIIPPTTIIOONN
copied back to their original location and the copied back to their original location and the
temporary versions are removed. temporary versions are removed.
Unless explicitly allowed by the security policy, symbolic
links will not be opened. This helps prevent the editing of
unauthorized files when the file is located in a user-
writable directory. Versions of ssuuddoo prior to 1.8.15 do not
have this restriction. Users are never allowed to edit
device special files.
If the specified file does not exist, it will be created. If the specified file does not exist, it will be created.
Note that unlike most commands run by _s_u_d_o, the editor is run Note that unlike most commands run by _s_u_d_o, the editor is run
with the invoking user's environment unmodified. If, for with the invoking user's environment unmodified. If, for
@ -585,4 +592,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or http://www.sudo.ws/license.html for file distributed with ssuuddoo or http://www.sudo.ws/license.html for
complete details. complete details.
Sudo 1.8.14 July 10, 2015 Sudo 1.8.14 Sudo 1.8.15 August 6, 2015 Sudo 1.8.15

View File

@ -21,7 +21,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.TH "SUDO" "8" "July 10, 2015" "Sudo @PACKAGE_VERSION@" "System Manager's Manual" .TH "SUDO" "8" "August 6, 2015" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -292,6 +292,15 @@ their original location and the temporary versions are removed.
.RE .RE
.RS 12n .RS 12n
.sp .sp
Unless explicitly allowed by the security policy, symbolic links
will not be opened.
This helps prevent the editing of unauthorized files when the file
is located in a user-writable directory.
Versions of
\fBsudo\fR
prior to 1.8.15 do not have this restriction.
Users are never allowed to edit device special files.
.sp
If the specified file does not exist, it will be created. If the specified file does not exist, it will be created.
Note that unlike most commands run by Note that unlike most commands run by
\fIsudo\fR, \fIsudo\fR,

View File

@ -19,7 +19,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.Dd July 10, 2015 .Dd August 6, 2015
.Dt SUDO @mansectsu@ .Dt SUDO @mansectsu@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -265,6 +265,15 @@ If they have been modified, the temporary files are copied back to
their original location and the temporary versions are removed. their original location and the temporary versions are removed.
.El .El
.Pp .Pp
Unless explicitly allowed by the security policy, symbolic links
will not be opened.
This helps prevent the editing of unauthorized files when the file
is located in a user-writable directory.
Versions of
.Nm
prior to 1.8.15 do not have this restriction.
Users are never allowed to edit device special files.
.Pp
If the specified file does not exist, it will be created. If the specified file does not exist, it will be created.
Note that unlike most commands run by Note that unlike most commands run by
.Em sudo , .Em sudo ,

View File

@ -606,6 +606,14 @@ DDEESSCCRRIIPPTTIIOONN
substitution and transparently enable _s_u_d_o_e_d_i_t when the substitution and transparently enable _s_u_d_o_e_d_i_t when the
user attempts to run an editor. user attempts to run an editor.
sudoedit_follow=bool
Set to true to allow ssuuddooeeddiitt to edit files that are
symbolic links. By default, ssuuddooeeddiitt 1.8.15 and higher
will refuse to open a symbolic link. The
_s_u_d_o_e_d_i_t___f_o_l_l_o_w option can be used to restore the older
behavior and allow ssuuddooeeddiitt to open symbolic links.
Only available starting with API version 1.8.
timeout=int timeout=int
Command timeout. If non-zero then when the timeout Command timeout. If non-zero then when the timeout
expires the command will be killed. expires the command will be killed.
@ -1479,6 +1487,9 @@ PPLLUUGGIINN AAPPII CCHHAANNGGEELLOOGG
may occur multiple times if there are multiple plugin-specific may occur multiple times if there are multiple plugin-specific
Debug lines in the sudo.conf(4) file. Debug lines in the sudo.conf(4) file.
Version 1.8 (sudo 1.8.15)
The _s_u_d_o_e_d_i_t___f_o_l_l_o_w entry was added to the command_info list.
SSEEEE AALLSSOO SSEEEE AALLSSOO
sudo.conf(4), sudoers(4), sudo(1m) sudo.conf(4), sudoers(4), sudo(1m)
@ -1508,4 +1519,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or http://www.sudo.ws/license.html for file distributed with ssuuddoo or http://www.sudo.ws/license.html for
complete details. complete details.
Sudo 1.8.14 December 4, 2014 Sudo 1.8.14 Sudo 1.8.15 August 6, 2015 Sudo 1.8.15

View File

@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.TH "SUDO_PLUGIN" "5" "December 4, 2014" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDO_PLUGIN" "5" "August 6, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -999,6 +999,20 @@ enable
\fIsudoedit\fR \fIsudoedit\fR
when the user attempts to run an editor. when the user attempts to run an editor.
.TP 6n .TP 6n
sudoedit_follow=bool
Set to true to allow
\fBsudoedit\fR
to edit files that are symbolic links.
By default,
\fBsudoedit\fR
1.8.15 and higher will refuse to open a symbolic link.
The
\fIsudoedit_follow\fR
option can be used to restore the older behavior and allow
\fBsudoedit\fR
to open symbolic links.
Only available starting with API version 1.8.
.TP 6n
timeout=int timeout=int
Command timeout. Command timeout.
If non-zero then when the timeout expires the command will be killed. If non-zero then when the timeout expires the command will be killed.
@ -2641,6 +2655,13 @@ The
entry now starts with a debug file path name and may occur multiple entry now starts with a debug file path name and may occur multiple
times if there are multiple plugin-specific Debug lines in the times if there are multiple plugin-specific Debug lines in the
sudo.conf(@mansectform@) file. sudo.conf(@mansectform@) file.
.TP 6n
Version 1.8 (sudo 1.8.15)
The
\fIsudoedit_follow\fR
entry was added to the
\fRcommand_info\fR
list.
.SH "SEE ALSO" .SH "SEE ALSO"
sudo.conf(@mansectform@), sudo.conf(@mansectform@),
sudoers(@mansectform@), sudoers(@mansectform@),

View File

@ -14,7 +14,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd December 4, 2014 .Dd August 6, 2015
.Dt SUDO_PLUGIN @mansectform@ .Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -881,6 +881,19 @@ This allows the plugin to perform command substitution and transparently
enable enable
.Em sudoedit .Em sudoedit
when the user attempts to run an editor. when the user attempts to run an editor.
.It sudoedit_follow=bool
Set to true to allow
.Nm sudoedit
to edit files that are symbolic links.
By default,
.Nm sudoedit
1.8.15 and higher will refuse to open a symbolic link.
The
.Em sudoedit_follow
option can be used to restore the older behavior and allow
.Nm sudoedit
to open symbolic links.
Only available starting with API version 1.8.
.It timeout=int .It timeout=int
Command timeout. Command timeout.
If non-zero then when the timeout expires the command will be killed. If non-zero then when the timeout expires the command will be killed.
@ -2310,6 +2323,12 @@ The
entry now starts with a debug file path name and may occur multiple entry now starts with a debug file path name and may occur multiple
times if there are multiple plugin-specific Debug lines in the times if there are multiple plugin-specific Debug lines in the
.Xr sudo.conf @mansectform@ file. .Xr sudo.conf @mansectform@ file.
.It Version 1.8 (sudo 1.8.15)
The
.Em sudoedit_follow
entry was added to the
.Li command_info
list.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sudo.conf @mansectform@ , .Xr sudo.conf @mansectform@ ,

View File

@ -465,9 +465,10 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset') Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
Tag_Spec ::= ('NOEXEC:' | 'EXEC:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
'LOG_OUTPUT:' | 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
'NOPASSWD:' | 'PASSWD:' | 'SETENV:' | 'NOSETENV:') 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
'NOPASSWD:' | 'SETENV:' | 'NOSETENV:')
A uusseerr ssppeecciiffiiccaattiioonn determines which commands a user may run (and as A uusseerr ssppeecciiffiiccaattiioonn determines which commands a user may run (and as
what user) on specified hosts. By default, commands are run as rroooott, but what user) on specified hosts. By default, commands are run as rroooott, but
@ -581,13 +582,14 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
TTaagg__SSppeecc TTaagg__SSppeecc
A command may have zero or more tags associated with it. There are ten A command may have zero or more tags associated with it. There are ten
possible tag values: NOEXEC, EXEC, LOG_INPUT, NOLOG_INPUT, LOG_OUTPUT, possible tag values: EXEC, NOEXEC, FOLLOW, NOFOLLOW, LOG_INPUT,
NOLOG_OUTPUT, MAIL, NOMAIL, NOPASSWD, PASSWD, SETENV, and NOSETENV. Once NOLOG_INPUT, LOG_OUTPUT, NOLOG_OUTPUT, MAIL, NOMAIL, PASSWD, NOPASSWD,
a tag is set on a Cmnd, subsequent Cmnds in the Cmnd_Spec_List, inherit SETENV, and NOSETENV. Once a tag is set on a Cmnd, subsequent Cmnds in
the tag unless it is overridden by the opposite tag (in other words, the Cmnd_Spec_List, inherit the tag unless it is overridden by the
PASSWD overrides NOPASSWD and NOEXEC overrides EXEC). opposite tag (in other words, PASSWD overrides NOPASSWD and NOEXEC
overrides EXEC).
_N_O_E_X_E_C and _E_X_E_C _E_X_E_C and _N_O_E_X_E_C
If ssuuddoo has been compiled with _n_o_e_x_e_c support and the underlying If ssuuddoo has been compiled with _n_o_e_x_e_c support and the underlying
operating system supports it, the NOEXEC tag can be used to prevent a operating system supports it, the NOEXEC tag can be used to prevent a
@ -601,6 +603,13 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
See the _P_r_e_v_e_n_t_i_n_g _s_h_e_l_l _e_s_c_a_p_e_s section below for more details on how See the _P_r_e_v_e_n_t_i_n_g _s_h_e_l_l _e_s_c_a_p_e_s section below for more details on how
NOEXEC works and whether or not it will work on your system. NOEXEC works and whether or not it will work on your system.
_F_O_L_L_O_W and _N_O_F_O_L_L_O_W Starting with version 1.8.15, ssuuddooeeddiitt will not
follow symbolic links when opening files unless the _s_u_d_o_e_d_i_t___f_o_l_l_o_w
option is enabled. The _F_O_L_L_O_W and _N_O_F_O_L_L_O_W tags override the value of
_s_u_d_o_e_d_i_t___f_o_l_l_o_w and can be used to permit (or deny) the editing of
symbolic links on a per-command basis. These tags are only effective
for the _s_u_d_o_e_d_i_t command and are ignored for all other commands.
_L_O_G___I_N_P_U_T and _N_O_L_O_G___I_N_P_U_T _L_O_G___I_N_P_U_T and _N_O_L_O_G___I_N_P_U_T
These tags override the value of the _l_o_g___i_n_p_u_t option on a per-command These tags override the value of the _l_o_g___i_n_p_u_t option on a per-command
@ -623,7 +632,7 @@ SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT
the descriptions of _m_a_i_l___a_l_l___c_m_n_d_s, _m_a_i_l___a_l_w_a_y_s, and _m_a_i_l___n_o___p_e_r_m_s in the descriptions of _m_a_i_l___a_l_l___c_m_n_d_s, _m_a_i_l___a_l_w_a_y_s, and _m_a_i_l___n_o___p_e_r_m_s in
the _S_U_D_O_E_R_S _O_P_T_I_O_N_S section below. the _S_U_D_O_E_R_S _O_P_T_I_O_N_S section below.
_N_O_P_A_S_S_W_D and _P_A_S_S_W_D _P_A_S_S_W_D and _N_O_P_A_S_S_W_D
By default, ssuuddoo requires that a user authenticate him or herself By default, ssuuddoo requires that a user authenticate him or herself
before running a command. This behavior can be modified via the before running a command. This behavior can be modified via the
@ -1248,6 +1257,15 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
that support either the setreuid(2) or setresuid(2) that support either the setreuid(2) or setresuid(2)
system call. This flag is _o_f_f by default. system call. This flag is _o_f_f by default.
sudoedit_follow By default, ssuuddooeeddiitt will not follow symbolic links
when opening files. The _s_u_d_o_e_d_i_t___f_o_l_l_o_w option can be
enabled to allow ssuuddooeeddiitt to open symbolic links. It
may be overridden on a per-command basis by the _F_O_L_L_O_W
and _N_O_F_O_L_L_O_W tags. This flag is _o_f_f by default.
This setting is only supported by version 1.8.15 or
higher.
targetpw If set, ssuuddoo will prompt for the password of the user targetpw If set, ssuuddoo will prompt for the password of the user
specified by the --uu option (defaults to root) instead specified by the --uu option (defaults to root) instead
of the password of the invoking user when running a of the password of the invoking user when running a
@ -2417,4 +2435,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or http://www.sudo.ws/license.html for file distributed with ssuuddoo or http://www.sudo.ws/license.html for
complete details. complete details.
Sudo 1.8.14 August 4, 2015 Sudo 1.8.14 Sudo 1.8.15 August 6, 2015 Sudo 1.8.15

View File

@ -21,7 +21,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.TH "SUDOERS" "5" "August 4, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .TH "SUDOERS" "5" "August 6, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -961,9 +961,10 @@ SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset') Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
Tag_Spec ::= ('NOEXEC:' | 'EXEC:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
'LOG_OUTPUT:' | 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
'NOPASSWD:' | 'PASSWD:' | 'SETENV:' | 'NOSETENV:') 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
'NOPASSWD:' | 'SETENV:' | 'NOSETENV:')
.RE .RE
.fi .fi
.PP .PP
@ -1214,16 +1215,18 @@ character.
A command may have zero or more tags associated with it. A command may have zero or more tags associated with it.
There are There are
ten possible tag values: ten possible tag values:
\fRNOEXEC\fR,
\fREXEC\fR, \fREXEC\fR,
\fRNOEXEC\fR,
\fRFOLLOW\fR,
\fRNOFOLLOW\fR,
\fRLOG_INPUT\fR, \fRLOG_INPUT\fR,
\fRNOLOG_INPUT\fR, \fRNOLOG_INPUT\fR,
\fRLOG_OUTPUT\fR, \fRLOG_OUTPUT\fR,
\fRNOLOG_OUTPUT\fR, \fRNOLOG_OUTPUT\fR,
\fRMAIL\fR, \fRMAIL\fR,
\fRNOMAIL\fR, \fRNOMAIL\fR,
\fRNOPASSWD\fR,
\fRPASSWD\fR, \fRPASSWD\fR,
\fRNOPASSWD\fR,
\fRSETENV\fR, \fRSETENV\fR,
and and
\fRNOSETENV\fR. \fRNOSETENV\fR.
@ -1242,7 +1245,7 @@ and
overrides overrides
\fREXEC\fR). \fREXEC\fR).
.TP 2n .TP 2n
\fINOEXEC\fR and \fIEXEC\fR \fIEXEC\fR and \fINOEXEC\fR
.sp .sp
If If
\fBsudo\fR \fBsudo\fR
@ -1275,6 +1278,24 @@ section below for more details on how
works and whether or not it will work on your system. works and whether or not it will work on your system.
.RE .RE
.TP 2n .TP 2n
\fIFOLLOW\fR and \fINOFOLLOW\fR
Starting with version 1.8.15,
\fBsudoedit\fR
will not follow symbolic links when opening files unless the
\fIsudoedit_follow\fR
option is enabled.
The
\fIFOLLOW\fR
and
\fINOFOLLOW\fR
tags override the value of
\fIsudoedit_follow\fR
and can be used to permit (or deny) the editing of symbolic links
on a per-command basis.
These tags are only effective for the
\fIsudoedit\fR
command and are ignored for all other commands.
.TP 2n
\fILOG_INPUT\fR and \fINOLOG_INPUT\fR \fILOG_INPUT\fR and \fINOLOG_INPUT\fR
.sp .sp
These tags override the value of the These tags override the value of the
@ -1327,7 +1348,7 @@ in the
\fISUDOERS OPTIONS\fR \fISUDOERS OPTIONS\fR
section below. section below.
.TP 2n .TP 2n
\fINOPASSWD\fR and \fIPASSWD\fR \fIPASSWD\fR and \fINOPASSWD\fR
.sp .sp
By default, By default,
\fBsudo\fR \fBsudo\fR
@ -2660,6 +2681,26 @@ This flag is
\fIoff\fR \fIoff\fR
by default. by default.
.TP 18n .TP 18n
sudoedit_follow
By default,
\fBsudoedit\fR
will not follow symbolic links when opening files.
The
\fIsudoedit_follow\fR
option can be enabled to allow
\fBsudoedit\fR
to open symbolic links.
It may be overridden on a per-command basis by the
\fIFOLLOW\fR
and
\fINOFOLLOW\fR
tags.
This flag is
\fIoff\fR
by default.
.sp
This setting is only supported by version 1.8.15 or higher.
.TP 18n
targetpw targetpw
If set, If set,
\fBsudo\fR \fBsudo\fR

View File

@ -19,7 +19,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.Dd August 4, 2015 .Dd August 6, 2015
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -914,9 +914,10 @@ SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset') Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
Tag_Spec ::= ('NOEXEC:' | 'EXEC:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | Tag_Spec ::= ('EXEC:' | 'NOEXEC:' | 'FOLLOW:' | 'NOFOLLOW' |
'LOG_OUTPUT:' | 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | 'LOG_OUTPUT:' |
'NOPASSWD:' | 'PASSWD:' | 'SETENV:' | 'NOSETENV:') 'NOLOG_OUTPUT:' | 'MAIL:' | 'NOMAIL:' | 'PASSWD:' |
'NOPASSWD:' | 'SETENV:' | 'NOSETENV:')
.Ed .Ed
.Pp .Pp
A A
@ -1137,16 +1138,18 @@ character.
A command may have zero or more tags associated with it. A command may have zero or more tags associated with it.
There are There are
ten possible tag values: ten possible tag values:
.Li NOEXEC ,
.Li EXEC , .Li EXEC ,
.Li NOEXEC ,
.Li FOLLOW ,
.Li NOFOLLOW ,
.Li LOG_INPUT , .Li LOG_INPUT ,
.Li NOLOG_INPUT , .Li NOLOG_INPUT ,
.Li LOG_OUTPUT , .Li LOG_OUTPUT ,
.Li NOLOG_OUTPUT , .Li NOLOG_OUTPUT ,
.Li MAIL , .Li MAIL ,
.Li NOMAIL , .Li NOMAIL ,
.Li NOPASSWD ,
.Li PASSWD , .Li PASSWD ,
.Li NOPASSWD ,
.Li SETENV , .Li SETENV ,
and and
.Li NOSETENV . .Li NOSETENV .
@ -1165,7 +1168,7 @@ and
overrides overrides
.Li EXEC ) . .Li EXEC ) .
.Bl -hang -width 0n .Bl -hang -width 0n
.It Em NOEXEC No and Em EXEC .It Em EXEC No and Em NOEXEC
.sp .sp
If If
.Nm sudo .Nm sudo
@ -1192,6 +1195,23 @@ See the
section below for more details on how section below for more details on how
.Li NOEXEC .Li NOEXEC
works and whether or not it will work on your system. works and whether or not it will work on your system.
.It Em FOLLOW No and Em NOFOLLOW
Starting with version 1.8.15,
.Nm sudoedit
will not follow symbolic links when opening files unless the
.Em sudoedit_follow
option is enabled.
The
.Em FOLLOW
and
.Em NOFOLLOW
tags override the value of
.Em sudoedit_follow
and can be used to permit (or deny) the editing of symbolic links
on a per-command basis.
These tags are only effective for the
.Em sudoedit
command and are ignored for all other commands.
.It Em LOG_INPUT No and Em NOLOG_INPUT .It Em LOG_INPUT No and Em NOLOG_INPUT
.sp .sp
These tags override the value of the These tags override the value of the
@ -1241,7 +1261,7 @@ and
in the in the
.Sx SUDOERS OPTIONS .Sx SUDOERS OPTIONS
section below. section below.
.It Em NOPASSWD No and Em PASSWD .It Em PASSWD No and Em NOPASSWD
.sp .sp
By default, By default,
.Nm sudo .Nm sudo
@ -2493,6 +2513,25 @@ system call.
This flag is This flag is
.Em off .Em off
by default. by default.
.It sudoedit_follow
By default,
.Nm sudoedit
will not follow symbolic links when opening files.
The
.Em sudoedit_follow
option can be enabled to allow
.Nm sudoedit
to open symbolic links.
It may be overridden on a per-command basis by the
.Em FOLLOW
and
.Em NOFOLLOW
tags.
This flag is
.Em off
by default.
.Pp
This setting is only supported by version 1.8.15 or higher.
.It targetpw .It targetpw
If set, If set,
.Nm sudo .Nm sudo

View File

@ -170,6 +170,9 @@
#ifndef S_ISDIR #ifndef S_ISDIR
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) # define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
#endif /* S_ISDIR */ #endif /* S_ISDIR */
#ifndef S_ISLNK
# define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK)
#endif /* S_ISLNK */
/* For futimens() and utimensat() emulation. */ /* For futimens() and utimensat() emulation. */
#if !defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT) #if !defined(HAVE_FUTIMENS) && !defined(HAVE_UTIMENSAT)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2014 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -19,7 +19,7 @@
/* API version major/minor */ /* API version major/minor */
#define SUDO_API_VERSION_MAJOR 1 #define SUDO_API_VERSION_MAJOR 1
#define SUDO_API_VERSION_MINOR 7 #define SUDO_API_VERSION_MINOR 8
#define SUDO_API_MKVERSION(x, y) ((x << 16) | y) #define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)

View File

@ -386,6 +386,10 @@ struct sudo_defs_types sudo_defs_table[] = {
"use_netgroups", T_FLAG, "use_netgroups", T_FLAG,
N_("Enable sudoers netgroup support"), N_("Enable sudoers netgroup support"),
NULL, NULL,
}, {
"sudoedit_follow", T_FLAG,
N_("Follow symbolic links when editing files with sudoedit"),
NULL,
}, { }, {
NULL, 0, NULL NULL, 0, NULL
} }

View File

@ -180,6 +180,8 @@
#define I_MAXSEQ 89 #define I_MAXSEQ 89
#define def_use_netgroups (sudo_defs_table[90].sd_un.flag) #define def_use_netgroups (sudo_defs_table[90].sd_un.flag)
#define I_USE_NETGROUPS 90 #define I_USE_NETGROUPS 90
#define def_sudoedit_follow (sudo_defs_table[91].sd_un.flag)
#define I_SUDOEDIT_FOLLOW 91
enum def_tuple { enum def_tuple {
never, never,

View File

@ -286,3 +286,6 @@ maxseq
use_netgroups use_netgroups
T_FLAG T_FLAG
"Enable sudoers netgroup support" "Enable sudoers netgroup support"
sudoedit_follow
T_FLAG
"Follow symbolic links when editing files with sudoedit"

File diff suppressed because it is too large Load Diff

View File

@ -23,22 +23,24 @@
#define NOLOG_OUTPUT 279 #define NOLOG_OUTPUT 279
#define MAIL 280 #define MAIL 280
#define NOMAIL 281 #define NOMAIL 281
#define ALL 282 #define FOLLOW 282
#define COMMENT 283 #define NOFOLLOW 283
#define HOSTALIAS 284 #define ALL 284
#define CMNDALIAS 285 #define COMMENT 285
#define USERALIAS 286 #define HOSTALIAS 286
#define RUNASALIAS 287 #define CMNDALIAS 287
#define ERROR 288 #define USERALIAS 288
#define TYPE 289 #define RUNASALIAS 289
#define ROLE 290 #define ERROR 290
#define PRIVS 291 #define TYPE 291
#define LIMITPRIVS 292 #define ROLE 292
#define MYSELF 293 #define PRIVS 293
#define SHA224_TOK 294 #define LIMITPRIVS 294
#define SHA256_TOK 295 #define MYSELF 295
#define SHA384_TOK 296 #define SHA224_TOK 296
#define SHA512_TOK 297 #define SHA256_TOK 297
#define SHA384_TOK 298
#define SHA512_TOK 299
#ifndef YYSTYPE_DEFINED #ifndef YYSTYPE_DEFINED
#define YYSTYPE_DEFINED #define YYSTYPE_DEFINED
typedef union { typedef union {

View File

@ -111,6 +111,8 @@ static struct sudo_digest *new_digest(int, const char *);
%token <tok> NOLOG_OUTPUT /* don't log cmnd output */ %token <tok> NOLOG_OUTPUT /* don't log cmnd output */
%token <tok> MAIL /* mail log message */ %token <tok> MAIL /* mail log message */
%token <tok> NOMAIL /* don't mail log message */ %token <tok> NOMAIL /* don't mail log message */
%token <tok> FOLLOW /* follow symbolic links */
%token <tok> NOFOLLOW /* don't follow symbolic links */
%token <tok> ALL /* ALL keyword */ %token <tok> ALL /* ALL keyword */
%token <tok> COMMENT /* comment and/or carriage return */ %token <tok> COMMENT /* comment and/or carriage return */
%token <tok> HOSTALIAS /* Host_Alias keyword */ %token <tok> HOSTALIAS /* Host_Alias keyword */
@ -370,6 +372,8 @@ cmndspeclist : cmndspec
$3->tags.log_output = prev->tags.log_output; $3->tags.log_output = prev->tags.log_output;
if ($3->tags.send_mail == UNSPEC) if ($3->tags.send_mail == UNSPEC)
$3->tags.send_mail = prev->tags.send_mail; $3->tags.send_mail = prev->tags.send_mail;
if ($3->tags.follow == UNSPEC)
$3->tags.follow = prev->tags.follow;
if (($3->runasuserlist == NULL && if (($3->runasuserlist == NULL &&
$3->runasgrouplist == NULL) && $3->runasgrouplist == NULL) &&
(prev->runasuserlist != NULL || (prev->runasuserlist != NULL ||
@ -614,8 +618,7 @@ runaslist : /* empty */ {
; ;
cmndtag : /* empty */ { cmndtag : /* empty */ {
$$.log_input = $$.log_output = $$.noexec = TAGS_INIT($$);
$$.nopasswd = $$.send_mail = $$.setenv = UNSPEC;
} }
| cmndtag NOPASSWD { | cmndtag NOPASSWD {
$$.nopasswd = true; $$.nopasswd = true;
@ -647,6 +650,12 @@ cmndtag : /* empty */ {
| cmndtag NOLOG_OUTPUT { | cmndtag NOLOG_OUTPUT {
$$.log_output = false; $$.log_output = false;
} }
| cmndtag FOLLOW {
$$.follow = true;
}
| cmndtag NOFOLLOW {
$$.follow = false;
}
| cmndtag MAIL { | cmndtag MAIL {
$$.send_mail = true; $$.send_mail = true;
} }

View File

@ -2325,6 +2325,9 @@ sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct sudo_lbuf *lb
if (strcmp(cp, "authenticate") == 0) if (strcmp(cp, "authenticate") == 0)
sudo_lbuf_append(lbuf, (*p)->bv_val[0] == '!' ? sudo_lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
"NOPASSWD: " : "PASSWD: "); "NOPASSWD: " : "PASSWD: ");
else if (strcmp(cp, "sudoedit_follow") == 0)
sudo_lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
"FOLLOW: " : "NOFOLLOW: ");
else if (strcmp(cp, "noexec") == 0) else if (strcmp(cp, "noexec") == 0)
sudo_lbuf_append(lbuf, (*p)->bv_val[0] == '!' ? sudo_lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
"EXEC: " : "NOEXEC: "); "EXEC: " : "NOEXEC: ");

View File

@ -320,6 +320,8 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
def_mail_no_perms = false; def_mail_no_perms = false;
} }
} }
if (tags->follow != UNSPEC)
def_sudoedit_follow = tags->follow;
} }
} else if (match == DENY) { } else if (match == DENY) {
SET(validated, VALIDATE_FAILURE); SET(validated, VALIDATE_FAILURE);
@ -346,9 +348,6 @@ done:
debug_return_int(validated); debug_return_int(validated);
} }
#define TAG_SET(tt) \
((tt) != UNSPEC && (tt) != IMPLIED)
#define TAG_CHANGED(t) \ #define TAG_CHANGED(t) \
(TAG_SET(cs->tags.t) && cs->tags.t != tags->t) (TAG_SET(cs->tags.t) && cs->tags.t != tags->t)
@ -394,14 +393,14 @@ sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
tags->send_mail = cs->tags.send_mail; tags->send_mail = cs->tags.send_mail;
sudo_lbuf_append(lbuf, tags->send_mail ? "MAIL: " : "NOMAIL: "); sudo_lbuf_append(lbuf, tags->send_mail ? "MAIL: " : "NOMAIL: ");
} }
if (TAG_CHANGED(follow)) {
tags->follow = cs->tags.follow;
sudo_lbuf_append(lbuf, tags->follow ? "FOLLOW: " : "NOFOLLOW: ");
}
print_member(lbuf, cs->cmnd, CMNDALIAS); print_member(lbuf, cs->cmnd, CMNDALIAS);
debug_return_bool(!sudo_lbuf_error(lbuf)); debug_return_bool(!sudo_lbuf_error(lbuf));
} }
#define RUNAS_CHANGED(cs1, cs2) \
(cs1->runasuserlist != cs2->runasuserlist || \
cs1->runasgrouplist != cs2->runasgrouplist)
static int static int
sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
struct sudo_lbuf *lbuf) struct sudo_lbuf *lbuf)
@ -414,12 +413,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
debug_decl(sudo_file_display_priv_short, SUDOERS_DEBUG_NSS) debug_decl(sudo_file_display_priv_short, SUDOERS_DEBUG_NSS)
/* gcc -Wuninitialized false positive */ /* gcc -Wuninitialized false positive */
tags.log_input = UNSPEC; TAGS_INIT(tags);
tags.log_output = UNSPEC;
tags.noexec = UNSPEC;
tags.nopasswd = UNSPEC;
tags.send_mail = UNSPEC;
tags.setenv = UNSPEC;
TAILQ_FOREACH(priv, &us->privileges, entries) { TAILQ_FOREACH(priv, &us->privileges, entries) {
if (hostlist_matches(&priv->hostlist) != ALLOW) if (hostlist_matches(&priv->hostlist) != ALLOW)
continue; continue;
@ -449,12 +443,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
} }
} }
sudo_lbuf_append(lbuf, ") "); sudo_lbuf_append(lbuf, ") ");
tags.log_input = UNSPEC; TAGS_INIT(tags);
tags.log_output = UNSPEC;
tags.noexec = UNSPEC;
tags.nopasswd = UNSPEC;
tags.send_mail = UNSPEC;
tags.setenv = UNSPEC;
} else if (cs != TAILQ_FIRST(&priv->cmndlist)) { } else if (cs != TAILQ_FIRST(&priv->cmndlist)) {
sudo_lbuf_append(lbuf, ", "); sudo_lbuf_append(lbuf, ", ");
} }
@ -467,13 +456,6 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
debug_return_int(nfound); debug_return_int(nfound);
} }
#define TAGS_CHANGED(ot, nt) \
((TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \
(TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \
(TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \
(TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \
(TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output))
/* /*
* Compare the current cmndspec with the previous one to determine * Compare the current cmndspec with the previous one to determine
* whether we need to start a new long entry for "sudo -ll". * whether we need to start a new long entry for "sudo -ll".

View File

@ -27,6 +27,54 @@
#undef IMPLIED #undef IMPLIED
#define IMPLIED 2 #define IMPLIED 2
/*
* Initialize all tags to UNSPEC.
*/
#define TAGS_INIT(t) do { \
(t).follow = UNSPEC; \
(t).log_input = UNSPEC; \
(t).log_output = UNSPEC; \
(t).noexec = UNSPEC; \
(t).nopasswd = UNSPEC; \
(t).send_mail = UNSPEC; \
(t).setenv = UNSPEC; \
} while (0)
/*
* Returns true if any tag are not UNSPEC, else false.
*/
#define TAGS_SET(t) \
((t).follow != UNSPEC || (t).log_input != UNSPEC || \
(t).log_output != UNSPEC || (t).noexec != UNSPEC || \
(t).nopasswd != UNSPEC || (t).send_mail != UNSPEC || \
(t).setenv != UNSPEC)
/*
* Returns true if the specified tag is not UNSPEC or IMPLIED, else false.
*/
#define TAG_SET(tt) \
((tt) != UNSPEC && (tt) != IMPLIED)
/*
* Returns true if any tags set in nt differ between ot and nt, else false.
*/
#define TAGS_CHANGED(ot, nt) \
((TAG_SET((nt).follow) && (nt).follow != (ot).follow) || \
(TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \
(TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output) || \
(TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \
(TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \
(TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \
(TAG_SET((nt).send_mail) && (nt).send_mail != (ot).send_mail))
/*
* Returns true if the runas user and group lists match, else false.
*/
#define RUNAS_CHANGED(cs1, cs2) \
((cs1) == NULL || (cs2) == NULL || \
(cs1)->runasuserlist != (cs2)->runasuserlist || \
(cs1)->runasgrouplist != (cs2)->runasgrouplist)
#define SUDO_DIGEST_SHA224 0 #define SUDO_DIGEST_SHA224 0
#define SUDO_DIGEST_SHA256 1 #define SUDO_DIGEST_SHA256 1
#define SUDO_DIGEST_SHA384 2 #define SUDO_DIGEST_SHA384 2
@ -59,6 +107,7 @@ struct cmndtag {
signed int log_input: 3; signed int log_input: 3;
signed int log_output: 3; signed int log_output: 3;
signed int send_mail: 3; signed int send_mail: 3;
signed int follow: 3;
}; };
/* /*

View File

@ -438,6 +438,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
if (ISSET(sudo_mode, MODE_EDIT)) { if (ISSET(sudo_mode, MODE_EDIT)) {
if ((command_info[info_len++] = strdup("sudoedit=true")) == NULL) if ((command_info[info_len++] = strdup("sudoedit=true")) == NULL)
goto oom; goto oom;
if (def_sudoedit_follow) {
if ((command_info[info_len++] = strdup("sudoedit_follow=true")) == NULL)
goto oom;
}
} }
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
/* Set cwd to run user's homedir. */ /* Set cwd to run user's homedir. */

View File

@ -8,3 +8,5 @@ user2 ALL = NOPASSWD: NOEXEC: SETENV: /usr/bin/vi:\
ALL = PASSWD: EXEC: NOSETENV: /usr/bin/echo ALL = PASSWD: EXEC: NOSETENV: /usr/bin/echo
user3 ALL = MAIL: /bin/sh:\ user3 ALL = MAIL: /bin/sh:\
ALL = NOMAIL: /usr/bin/id ALL = NOMAIL: /usr/bin/id
user4 ALL = FOLLOW: sudoedit /etc/motd:\
ALL = NOFOLLOW: sudoedit /home/*/*

View File

@ -113,6 +113,42 @@
] ]
} }
] ]
},
{
"User_List": [
{ "username": "user4" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Options": [
{ "sudoedit_follow": true }
],
"Commands": [
{ "command": "sudoedit \/etc\/motd" }
]
}
]
},
{
"User_List": [
{ "username": "user4" }
],
"Host_List": [
{ "hostalias": "ALL" }
],
"Cmnd_Specs": [
{
"Options": [
{ "sudoedit_follow": false }
],
"Commands": [
{ "command": "sudoedit \/home\/*\/*" }
]
}
]
} }
] ]
} }

View File

@ -5,3 +5,4 @@ Parses OK.
user1 ALL = LOG_INPUT: LOG_OUTPUT: /usr/bin/su - : ALL = NOLOG_INPUT: NOLOG_OUTPUT: /usr/bin/id user1 ALL = LOG_INPUT: LOG_OUTPUT: /usr/bin/su - : ALL = NOLOG_INPUT: NOLOG_OUTPUT: /usr/bin/id
user2 ALL = NOEXEC: NOPASSWD: SETENV: /usr/bin/vi : ALL = EXEC: PASSWD: NOSETENV: /usr/bin/echo user2 ALL = NOEXEC: NOPASSWD: SETENV: /usr/bin/vi : ALL = EXEC: PASSWD: NOSETENV: /usr/bin/echo
user3 ALL = MAIL: /bin/sh : ALL = NOMAIL: /usr/bin/id user3 ALL = MAIL: /bin/sh : ALL = NOMAIL: /usr/bin/id
user4 ALL = FOLLOW: sudoedit /etc/motd : ALL = NOFOLLOW: sudoedit /home/*/*

View File

@ -5,3 +5,4 @@
WORD(5) ALL = LOG_INPUT LOG_OUTPUT COMMAND ARG : ALL = NOLOG_INPUT NOLOG_OUTPUT COMMAND WORD(5) ALL = LOG_INPUT LOG_OUTPUT COMMAND ARG : ALL = NOLOG_INPUT NOLOG_OUTPUT COMMAND
WORD(5) ALL = NOPASSWD NOEXEC SETENV COMMAND : ALL = PASSWD EXEC NOSETENV COMMAND WORD(5) ALL = NOPASSWD NOEXEC SETENV COMMAND : ALL = PASSWD EXEC NOSETENV COMMAND
WORD(5) ALL = MAIL COMMAND : ALL = NOMAIL COMMAND WORD(5) ALL = MAIL COMMAND : ALL = NOMAIL COMMAND
WORD(5) ALL = FOLLOW COMMAND ARG : ALL = NOFOLLOW COMMAND ARG

View File

@ -63,11 +63,12 @@
* 42 sudo 1.8.6, Support for empty Runas_List (with or without a colon) to mean the invoking user. Support for Solaris Privilege Sets (PRIVS= and LIMITPRIVS=). * 42 sudo 1.8.6, Support for empty Runas_List (with or without a colon) to mean the invoking user. Support for Solaris Privilege Sets (PRIVS= and LIMITPRIVS=).
* 43 sudo 1.8.7, Support for specifying a digest along with the command. * 43 sudo 1.8.7, Support for specifying a digest along with the command.
* 44 sudo 1.8.13, added MAIL/NOMAIL tags. * 44 sudo 1.8.13, added MAIL/NOMAIL tags.
* 45 sudo 1.8.15, added FOLLOW/NOFOLLOW tags and sudoedit_follow Default.
*/ */
#ifndef SUDOERS_VERSION_H #ifndef SUDOERS_VERSION_H
#define SUDOERS_VERSION_H #define SUDOERS_VERSION_H
#define SUDOERS_GRAMMAR_VERSION 44 #define SUDOERS_GRAMMAR_VERSION 45
#endif /* SUDOERS_VERSION_H */ #endif /* SUDOERS_VERSION_H */

View File

@ -591,12 +591,7 @@ print_privilege(struct privilege *priv)
print_member(m); print_member(m);
} }
fputs(" = ", stdout); fputs(" = ", stdout);
tags.log_input = UNSPEC; TAGS_INIT(tags);
tags.log_output = UNSPEC;
tags.noexec = UNSPEC;
tags.nopasswd = UNSPEC;
tags.send_mail = UNSPEC;
tags.setenv = UNSPEC;
TAILQ_FOREACH(cs, &priv->cmndlist, entries) { TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
if (cs != TAILQ_FIRST(&priv->cmndlist)) if (cs != TAILQ_FIRST(&priv->cmndlist))
fputs(", ", stdout); fputs(", ", stdout);
@ -635,6 +630,8 @@ print_privilege(struct privilege *priv)
if (cs->limitprivs) if (cs->limitprivs)
printf("LIMITPRIVS=%s ", cs->limitprivs); printf("LIMITPRIVS=%s ", cs->limitprivs);
#endif /* HAVE_PRIV_SET */ #endif /* HAVE_PRIV_SET */
if (TAG_CHANGED(follow))
printf("%sFOLLOW: ", cs->tags.follow ? "" : "NO");
if (TAG_CHANGED(log_input)) if (TAG_CHANGED(log_input))
printf("%sLOG_INPUT: ", cs->tags.log_input ? "" : "NO"); printf("%sLOG_INPUT: ", cs->tags.log_input ? "" : "NO");
if (TAG_CHANGED(log_output)) if (TAG_CHANGED(log_output))

File diff suppressed because it is too large Load Diff

View File

@ -454,6 +454,16 @@ NOMAIL[[:blank:]]*: {
LEXRETURN(NOMAIL); LEXRETURN(NOMAIL);
} }
FOLLOW[[:blank:]]*: {
LEXTRACE("FOLLOW ");
LEXRETURN(FOLLOW);
}
NOFOLLOW[[:blank:]]*: {
LEXTRACE("NOFOLLOW ");
LEXRETURN(NOFOLLOW);
}
<INITIAL,GOTDEFS>(\+|\%|\%:) { <INITIAL,GOTDEFS>(\+|\%|\%:) {
/* empty group or netgroup */ /* empty group or netgroup */
LEXTRACE("ERROR "); LEXTRACE("ERROR ");

View File

@ -667,7 +667,7 @@ print_defaults_json(FILE *fp, int indent, bool need_comma)
if (type == -1) { if (type == -1) {
sudo_warnx(U_("unknown defaults entry `%s'"), def->var); sudo_warnx(U_("unknown defaults entry `%s'"), def->var);
/* XXX - just pass it through as a string anyway? */ /* XXX - just pass it through as a string anyway? */
break;; break;
} }
fputs(",\n", fp); fputs(",\n", fp);
} }
@ -738,23 +738,6 @@ print_aliases_json(FILE *fp, int indent, bool need_comma)
debug_return_bool(need_comma); debug_return_bool(need_comma);
} }
/* XXX these are all duplicated w/ parse.c */
#define RUNAS_CHANGED(cs1, cs2) \
(cs1 == NULL || cs2 == NULL || \
cs1->runasuserlist != cs2->runasuserlist || \
cs1->runasgrouplist != cs2->runasgrouplist)
#define TAG_SET(tt) \
((tt) != UNSPEC && (tt) != IMPLIED)
#define TAGS_CHANGED(ot, nt) \
((TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \
(TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output) || \
(TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \
(TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \
(TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \
(TAG_SET((nt).send_mail) && (nt).send_mail != (ot).send_mail))
/* /*
* Print a Cmnd_Spec in JSON format at the specified indent level. * Print a Cmnd_Spec in JSON format at the specified indent level.
* A pointer to the next Cmnd_Spec is passed in to make it possible to * A pointer to the next Cmnd_Spec is passed in to make it possible to
@ -799,56 +782,59 @@ print_cmndspec_json(FILE *fp, struct cmndspec *cs, struct cmndspec **nextp,
} }
/* Print tags */ /* Print tags */
if (cs->tags.log_input != UNSPEC || cs->tags.log_output != UNSPEC || if (TAGS_SET(cs->tags)) {
cs->tags.noexec != UNSPEC || cs->tags.nopasswd != UNSPEC || struct cmndtag tag = cs->tags;
cs->tags.send_mail != UNSPEC || cs->tags.setenv != UNSPEC) {
fprintf(fp, "%*s\"Options\": [\n", indent, ""); fprintf(fp, "%*s\"Options\": [\n", indent, "");
indent += 4; indent += 4;
if (cs->tags.nopasswd != UNSPEC) { if (tag.nopasswd != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = !cs->tags.nopasswd; value.u.boolean = !tag.nopasswd;
last_one = cs->tags.noexec == UNSPEC && tag.nopasswd = UNSPEC;
cs->tags.send_mail == UNSPEC && cs->tags.setenv == UNSPEC &&
cs->tags.log_input == UNSPEC && cs->tags.log_output == UNSPEC;
print_pair_json(fp, "{ ", "authenticate", &value, print_pair_json(fp, "{ ", "authenticate", &value,
last_one ? " }\n" : " },\n", indent); TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
if (cs->tags.noexec != UNSPEC) { if (tag.noexec != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = cs->tags.noexec; value.u.boolean = tag.noexec;
last_one = cs->tags.send_mail == UNSPEC && tag.noexec = UNSPEC;
cs->tags.setenv == UNSPEC && cs->tags.log_input == UNSPEC &&
cs->tags.log_output == UNSPEC;
print_pair_json(fp, "{ ", "noexec", &value, print_pair_json(fp, "{ ", "noexec", &value,
last_one ? " }\n" : " },\n", indent); TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
if (cs->tags.send_mail != UNSPEC) { if (tag.send_mail != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = cs->tags.send_mail; value.u.boolean = tag.send_mail;
last_one = cs->tags.setenv == UNSPEC && tag.send_mail = UNSPEC;
cs->tags.log_input == UNSPEC && cs->tags.log_output == UNSPEC;
print_pair_json(fp, "{ ", "send_mail", &value, print_pair_json(fp, "{ ", "send_mail", &value,
last_one ? " }\n" : " },\n", indent); TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
if (cs->tags.setenv != UNSPEC) { if (tag.setenv != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = cs->tags.setenv; value.u.boolean = tag.setenv;
last_one = cs->tags.log_input == UNSPEC && tag.setenv = UNSPEC;
cs->tags.log_output == UNSPEC;
print_pair_json(fp, "{ ", "setenv", &value, print_pair_json(fp, "{ ", "setenv", &value,
last_one ? " }\n" : " },\n", indent); TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
if (cs->tags.log_input != UNSPEC) { if (tag.follow != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = cs->tags.log_input; value.u.boolean = tag.follow;
last_one = cs->tags.log_output == UNSPEC; tag.follow = UNSPEC;
print_pair_json(fp, "{ ", "sudoedit_follow", &value,
TAGS_SET(tag) ? " },\n" : " }\n", indent);
}
if (tag.log_input != UNSPEC) {
value.type = JSON_BOOL;
value.u.boolean = tag.log_input;
tag.log_input = UNSPEC;
print_pair_json(fp, "{ ", "log_input", &value, print_pair_json(fp, "{ ", "log_input", &value,
last_one ? " }\n" : " },\n", indent); TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
if (cs->tags.log_output != UNSPEC) { if (tag.log_output != UNSPEC) {
value.type = JSON_BOOL; value.type = JSON_BOOL;
value.u.boolean = cs->tags.log_output; value.u.boolean = tag.log_output;
print_pair_json(fp, "{ ", "log_output", &value, " }\n", indent); tag.log_output = UNSPEC;
print_pair_json(fp, "{ ", "log_output", &value,
TAGS_SET(tag) ? " },\n" : " }\n", indent);
} }
indent -= 4; indent -= 4;
fprintf(fp, "%*s],\n", indent, ""); fprintf(fp, "%*s],\n", indent, "");

View File

@ -120,13 +120,20 @@ static int
sesh_sudoedit(int argc, char *argv[]) sesh_sudoedit(int argc, char *argv[])
{ {
int i, oflags_dst, post, ret = SESH_ERR_FAILURE; int i, oflags_dst, post, ret = SESH_ERR_FAILURE;
int fd_src = -1, fd_dst = -1; int fd_src = -1, fd_dst = -1, follow = 0;
ssize_t nread, nwritten; ssize_t nread, nwritten;
struct stat sb; struct stat sb;
struct timespec times[2]; struct timespec times[2];
char buf[BUFSIZ]; char buf[BUFSIZ];
debug_decl(sesh_sudoedit, SUDO_DEBUG_EDIT) debug_decl(sesh_sudoedit, SUDO_DEBUG_EDIT)
/* Check for -h flag (don't follow links). */
if (strcmp(argv[2], "-h") == 0) {
argv++;
argc--;
follow = O_NOFOLLOW;
}
if (argc < 3) if (argc < 3)
debug_return_int(SESH_ERR_FAILURE); debug_return_int(SESH_ERR_FAILURE);
@ -160,7 +167,7 @@ sesh_sudoedit(int argc, char *argv[])
* so that it's ensured that the temporary files are * so that it's ensured that the temporary files are
* created by us and that we are not opening any symlinks. * created by us and that we are not opening any symlinks.
*/ */
oflags_dst = O_WRONLY|O_TRUNC|O_CREAT|(post ? 0 : O_EXCL); oflags_dst = O_WRONLY|O_TRUNC|O_CREAT|(post ? follow : O_EXCL);
for (i = 0; i < argc - 1; i += 2) { for (i = 0; i < argc - 1; i += 2) {
const char *path_src = argv[i]; const char *path_src = argv[i];
const char *path_dst = argv[i + 1]; const char *path_dst = argv[i + 1];
@ -169,7 +176,7 @@ sesh_sudoedit(int argc, char *argv[])
* doesn't exist, that's OK, we'll create an empty * doesn't exist, that's OK, we'll create an empty
* destination file. * destination file.
*/ */
if ((fd_src = open(path_src, O_RDONLY, 0600)) < 0) { if ((fd_src = open(path_src, O_RDONLY|follow, 0600)) < 0) {
if (errno != ENOENT) { if (errno != ENOENT) {
sudo_warn("%s", path_src); sudo_warn("%s", path_src);
if (post) { if (post) {

View File

@ -715,6 +715,11 @@ command_info_to_details(char * const info[], struct command_details *details)
SET(details->flags, CD_SUDOEDIT); SET(details->flags, CD_SUDOEDIT);
break; break;
} }
if (strncmp("sudoedit_follow=", info[i], sizeof("sudoedit_follow=") - 1) == 0) {
if (sudo_strtobool(info[i] + sizeof("sudoedit_follow=") - 1) == true)
SET(details->flags, CD_SUDOEDIT_FOLLOW);
break;
}
break; break;
case 't': case 't':
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {

View File

@ -111,22 +111,23 @@ struct user_details {
int ts_lines; int ts_lines;
}; };
#define CD_SET_UID 0x0001 #define CD_SET_UID 0x00001
#define CD_SET_EUID 0x0002 #define CD_SET_EUID 0x00002
#define CD_SET_GID 0x0004 #define CD_SET_GID 0x00004
#define CD_SET_EGID 0x0008 #define CD_SET_EGID 0x00008
#define CD_PRESERVE_GROUPS 0x0010 #define CD_PRESERVE_GROUPS 0x00010
#define CD_NOEXEC 0x0020 #define CD_NOEXEC 0x00020
#define CD_SET_PRIORITY 0x0040 #define CD_SET_PRIORITY 0x00040
#define CD_SET_UMASK 0x0080 #define CD_SET_UMASK 0x00080
#define CD_SET_TIMEOUT 0x0100 #define CD_SET_TIMEOUT 0x00100
#define CD_SUDOEDIT 0x0200 #define CD_SUDOEDIT 0x00200
#define CD_BACKGROUND 0x0400 #define CD_BACKGROUND 0x00400
#define CD_RBAC_ENABLED 0x0800 #define CD_RBAC_ENABLED 0x00800
#define CD_USE_PTY 0x1000 #define CD_USE_PTY 0x01000
#define CD_SET_UTMP 0x2000 #define CD_SET_UTMP 0x02000
#define CD_EXEC_BG 0x4000 #define CD_EXEC_BG 0x04000
#define CD_SUDOEDIT_COPY 0x8000 #define CD_SUDOEDIT_COPY 0x08000
#define CD_SUDOEDIT_FOLLOW 0x10000
struct preserved_fd { struct preserved_fd {
TAILQ_ENTRY(preserved_fd) entries; TAILQ_ENTRY(preserved_fd) entries;

View File

@ -57,8 +57,8 @@
struct tempfile { struct tempfile {
char *tfile; char *tfile;
char *ofile; char *ofile;
struct timespec omtim;
off_t osize; off_t osize;
struct timespec omtim;
}; };
static char edit_tmpdir[MAX(sizeof(_PATH_VARTMP), sizeof(_PATH_TMP))]; static char edit_tmpdir[MAX(sizeof(_PATH_VARTMP), sizeof(_PATH_TMP))];
@ -157,6 +157,50 @@ sudo_edit_mktemp(const char *ofile, char **tfile)
debug_return_int(tfd); debug_return_int(tfd);
} }
#ifdef O_NOFOLLOW
static int
sudo_edit_open(const char *path, int oflags, mode_t mode, int sflags)
{
if (!ISSET(sflags, CD_SUDOEDIT_FOLLOW))
oflags |= O_NOFOLLOW;
return open(path, oflags, mode);
}
#else
static int
sudo_edit_open(const char *path, int oflags, mode_t mode, int sflags)
{
struct stat sb1, sb2;
int fd;
fd = open(path, oflags, mode);
if (fd == -1 || ISSET(sflags, CD_SUDOEDIT_FOLLOW))
return fd;
/*
* Treat [fl]stat() failure like an open() failure.
*/
if (fstat(fd, &sb1) == -1 || lstat(path, &sb2) == -1) {
const int serrno = errno;
close(fd);
errno = serrno;
return -1;
}
/*
* Make sure we did not open a link and that what we opened
* matches what is currently on the file system.
*/
if (S_ISLNK(sb2.st_mode) ||
sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
close(fd);
errno = ELOOP;
return -1;
}
return fd;
}
#endif /* O_NOFOLLOW */
/* /*
* Create temporary copies of files[] and store the temporary path name * Create temporary copies of files[] and store the temporary path name
* along with the original name, size and mtime in tf. * along with the original name, size and mtime in tf.
@ -182,7 +226,8 @@ sudo_edit_create_tfiles(struct command_details *command_details,
rc = -1; rc = -1;
switch_user(command_details->euid, command_details->egid, switch_user(command_details->euid, command_details->egid,
command_details->ngroups, command_details->groups); command_details->ngroups, command_details->groups);
if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { ofd = sudo_edit_open(files[i], O_RDONLY, 0644, command_details->flags);
if (ofd != -1 || errno == ENOENT) {
if (ofd == -1) { if (ofd == -1) {
memset(&sb, 0, sizeof(sb)); /* new file */ memset(&sb, 0, sizeof(sb)); /* new file */
rc = 0; rc = 0;
@ -192,11 +237,17 @@ sudo_edit_create_tfiles(struct command_details *command_details,
} }
switch_user(ROOT_UID, user_details.egid, switch_user(ROOT_UID, user_details.egid,
user_details.ngroups, user_details.groups); user_details.ngroups, user_details.groups);
if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) { if (ofd != -1 && !S_ISREG(sb.st_mode)) {
if (rc) sudo_warnx(U_("%s: not a regular file"), files[i]);
sudo_warn("%s", files[i]); close(ofd);
continue;
}
if (rc == -1) {
/* open() or fstat() error. */
if (ofd == -1 && errno == ELOOP)
sudo_warnx(U_("%s: is a symbolic link"), files[i]);
else else
sudo_warnx(U_("%s: not a regular file"), files[i]); sudo_warn("%s", files[i]);
if (ofd != -1) if (ofd != -1)
close(ofd); close(ofd);
continue; continue;
@ -275,9 +326,9 @@ sudo_edit_copy_tfiles(struct command_details *command_details,
"seteuid(%u)", user_details.uid); "seteuid(%u)", user_details.uid);
if (seteuid(user_details.uid) != 0) if (seteuid(user_details.uid) != 0)
sudo_fatal("seteuid(%d)", (int)user_details.uid); sudo_fatal("seteuid(%d)", (int)user_details.uid);
if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) { tfd = sudo_edit_open(tf[i].tfile, O_RDONLY, 0644, 0);
if (tfd != -1)
rc = fstat(tfd, &sb); rc = fstat(tfd, &sb);
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"seteuid(%u)", ROOT_UID); "seteuid(%u)", ROOT_UID);
if (seteuid(ROOT_UID) != 0) if (seteuid(ROOT_UID) != 0)
@ -309,7 +360,8 @@ sudo_edit_copy_tfiles(struct command_details *command_details,
} }
switch_user(command_details->euid, command_details->egid, switch_user(command_details->euid, command_details->egid,
command_details->ngroups, command_details->groups); command_details->ngroups, command_details->groups);
ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644); ofd = sudo_edit_open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644,
command_details->flags);
switch_user(ROOT_UID, user_details.egid, switch_user(ROOT_UID, user_details.egid,
user_details.ngroups, user_details.groups); user_details.ngroups, user_details.groups);
if (ofd == -1) { if (ofd == -1) {
@ -368,7 +420,7 @@ selinux_edit_create_tfiles(struct command_details *command_details,
command_details->command = _PATH_SUDO_SESH; command_details->command = _PATH_SUDO_SESH;
command_details->flags |= CD_SUDOEDIT_COPY; command_details->flags |= CD_SUDOEDIT_COPY;
sesh_nargs = 3 + (nfiles * 2) + 1; sesh_nargs = 4 + (nfiles * 2) + 1;
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *)); sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
if (sesh_args == NULL) { if (sesh_args == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
@ -376,6 +428,8 @@ selinux_edit_create_tfiles(struct command_details *command_details,
} }
*sesh_ap++ = "sesh"; *sesh_ap++ = "sesh";
*sesh_ap++ = "-e"; *sesh_ap++ = "-e";
if (!ISSET(command_details->flags, CD_SUDOEDIT_FOLLOW))
*sesh_ap++ = "-h";
*sesh_ap++ = "0"; *sesh_ap++ = "0";
for (i = 0; i < nfiles; i++) { for (i = 0; i < nfiles; i++) {
@ -406,7 +460,7 @@ selinux_edit_create_tfiles(struct command_details *command_details,
} }
*sesh_ap = NULL; *sesh_ap = NULL;
/* Run sesh -e 0 <o1> <t1> ... <on> <tn> */ /* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
command_details->argv = sesh_args; command_details->argv = sesh_args;
rc = run_command(command_details); rc = run_command(command_details);
switch (rc) { switch (rc) {