Implement #includedir directive. Files in an includedir are not edited

by visudo unless they contain a syntax error.
This commit is contained in:
Todd C. Miller
2009-04-18 23:25:08 +00:00
parent e65ec1438a
commit 3be603aa47
13 changed files with 1483 additions and 1047 deletions

7
gram.c
View File

@@ -798,15 +798,18 @@ init_parser(path, quiet)
init_aliases();
init_lexer();
efree(sudoers);
sudoers = path ? estrdup(path) : NULL;
parse_error = FALSE;
errorlineno = -1;
errorfile = NULL;
sudolineno = 1;
verbose = !quiet;
}
#line 758 "y.tab.c"
#line 761 "y.tab.c"
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
#if defined(__cplusplus) || defined(__STDC__)
static int yygrowstack(void)
@@ -1546,7 +1549,7 @@ case 92:
yyval.member = new_member(yyvsp[0].string, WORD);
}
break;
#line 1498 "y.tab.c"
#line 1501 "y.tab.c"
}
yyssp -= yym;
yystate = *yyssp;

3
gram.y
View File

@@ -766,11 +766,14 @@ init_parser(path, quiet)
init_aliases();
init_lexer();
efree(sudoers);
sudoers = path ? estrdup(path) : NULL;
parse_error = FALSE;
errorlineno = -1;
errorfile = NULL;
sudolineno = 1;
verbose = !quiet;
}

View File

@@ -89,7 +89,7 @@ sudo_file_open(nss)
{
if (def_ignore_local_sudoers)
return(-1);
nss->handle = open_sudoers(_PATH_SUDOERS, NULL);
nss->handle = open_sudoers(_PATH_SUDOERS, FALSE, NULL);
return(nss->handle ? 0 : -1);
}

View File

@@ -185,6 +185,7 @@ struct alias *alias_remove __P((char *, int));
void alias_free __P((void *));
void alias_apply __P((int (*)(void *, void *), void *));
void init_aliases __P((void));
void init_lexer __P((void));
void init_parser __P((char *, int));
int alias_compare __P((const void *, const void *));

3
sudo.c
View File

@@ -1072,8 +1072,9 @@ parse_args(argc, argv)
* Returns a handle to the sudoers file or NULL on error.
*/
FILE *
open_sudoers(sudoers, keepopen)
open_sudoers(sudoers, doedit, keepopen)
const char *sudoers;
int doedit;
int *keepopen;
{
struct stat statbuf;

2
sudo.h
View File

@@ -298,7 +298,7 @@ char *sudo_getepw __P((const struct passwd *));
int pam_prep_user __P((struct passwd *));
void zero_bytes __P((volatile void *, size_t));
int gettime __P((struct timespec *));
FILE *open_sudoers __P((const char *, int *));
FILE *open_sudoers __P((const char *, int, int *));
void display_privs __P((struct sudo_nss_list *, struct passwd *));
int display_cmnd __P((struct sudo_nss_list *, struct passwd *));
int get_ttycols __P((void));

View File

@@ -61,7 +61,7 @@ DDEESSCCRRIIPPTTIIOONN
1.7.1 March 11, 2009 1
1.7.1 April 18, 2009 1
@@ -127,7 +127,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
1.7.1 March 11, 2009 2
1.7.1 April 18, 2009 2
@@ -193,7 +193,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
1.7.1 March 11, 2009 3
1.7.1 April 18, 2009 3
@@ -259,7 +259,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
1.7.1 March 11, 2009 4
1.7.1 April 18, 2009 4
@@ -325,7 +325,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
1.7.1 March 11, 2009 5
1.7.1 April 18, 2009 5
@@ -391,7 +391,7 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
1.7.1 March 11, 2009 6
1.7.1 April 18, 2009 6
@@ -453,11 +453,11 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
IInncclluuddiinngg ootthheerr ffiilleess ffrroomm wwiitthhiinn ssuuddooeerrss
It is possible to include other _s_u_d_o_e_r_s files from within the _s_u_d_o_e_r_s
file currently being parsed using the #include directive, similar to
file currently being parsed using the #include and #includedir
1.7.1 March 11, 2009 7
1.7.1 April 18, 2009 7
@@ -466,12 +466,13 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
the one used by the C preprocessor. This is useful, for example, for
keeping a site-wide _s_u_d_o_e_r_s file in addition to a per-machine local
one. For the sake of this example the site-wide _s_u_d_o_e_r_s will be
_/_e_t_c_/_s_u_d_o_e_r_s and the per-machine one will be _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. To
include _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l from within _/_e_t_c_/_s_u_d_o_e_r_s we would use the
following line in _/_e_t_c_/_s_u_d_o_e_r_s:
directives.
This can be used, for example, to keep a site-wide _s_u_d_o_e_r_s file in
addition to a local, per-machine file. For the sake of this example
the site-wide _s_u_d_o_e_r_s will be _/_e_t_c_/_s_u_d_o_e_r_s and the per-machine one will
be _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. To include _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l from within
_/_e_t_c_/_s_u_d_o_e_r_s we would use the following line in _/_e_t_c_/_s_u_d_o_e_r_s:
#include /etc/sudoers.local
@@ -489,6 +490,25 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
will cause ssuuddoo to include the file _/_e_t_c_/_s_u_d_o_e_r_s_._x_e_r_x_e_s.
The #includedir directive can be used to create a _s_u_d_o_._d directory that
the system package manager can drop _s_u_d_o_e_r_s rules into as part of
package installation. For example, given:
#includedir /etc/sudoers.d
ssuuddoo will read each file in _/_e_t_c_/_s_u_d_o_e_r_s_._d, skipping files that end in
".tmp" to avoid causing problems with vviissuuddoo. Files are parsed in
sorted lexical order. That is, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_0_1___f_i_r_s_t will be parsed
before _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Be aware that because the sorting is
lexical, not numeric, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1___w_h_o_o_p_s would be loaded aafftteerr
_/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Using a consistent number of leading zeroes
in the file names can be used to avoid such problems.
Note that unlike files included via #include, vviissuuddoo will not edit the
files in a #includedir directory unless one of them contains a syntax
error. It is still possible to run vviissuuddoo with the -f flag to edit the
files directly.
OOtthheerr ssppeecciiaall cchhaarraacctteerrss aanndd rreesseerrvveedd wwoorrddss
The pound sign ('#') is used to indicate a comment (unless it is part
@@ -500,6 +520,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
The reserved word AALLLL is a built-in _a_l_i_a_s that always causes a match to
succeed. It can be used wherever one might otherwise use a Cmnd_Alias,
User_Alias, Runas_Alias, or Host_Alias. You should not try to define
1.7.1 April 18, 2009 8
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
your own _a_l_i_a_s called AALLLL as the built-in alias will be used in
preference to your own. Please note that using AALLLL can be dangerous
since in a command context, it allows the user to run aannyy command on
@@ -521,17 +553,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
used as part of a word (e.g. a username or hostname): '@', '!', '=',
':', ',', '(', ')', '\'.
1.7.1 March 11, 2009 8
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
SSUUDDOOEERRSS OOPPTTIIOONNSS
ssuuddoo's behavior can be modified by Default_Entry lines, as explained
earlier. A list of all supported Defaults parameters, grouped by type,
@@ -565,6 +586,18 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
alternative is to place a colon-separated list of
editors in the editor variable. vviissuuddoo will then only
use the EDITOR or VISUAL if they match a value
1.7.1 April 18, 2009 9
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
specified in editor. This flag is _o_f_f by default.
env_reset If set, ssuuddoo will reset the environment to only contain
@@ -586,18 +619,6 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
working (for example if the machine is not plugged into
the network). Also note that you must use the host's
official name as DNS knows it. That is, you may not
1.7.1 March 11, 2009 9
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
use a host alias (CNAME entry) due to performance
issues and the fact that there is no way to get all
aliases from DNS. If your machine's hostname (as
@@ -631,6 +652,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
log_year If set, the four-digit year will be logged in the (non-
syslog) ssuuddoo log file. This flag is _o_f_f by default.
1.7.1 April 18, 2009 10
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
long_otp_prompt When validating with a One Time Password (OPT) scheme
such as SS//KKeeyy or OOPPIIEE, a two-line prompt is used to
make it easier to cut and paste the challenge to a
@@ -652,18 +685,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
mail_no_perms If set, mail will be sent to the _m_a_i_l_t_o user if the
invoking user is allowed to use ssuuddoo but the command
1.7.1 March 11, 2009 10
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
they are trying is not listed in their _s_u_d_o_e_r_s file
entry or is explicitly denied. This flag is _o_f_f by
default.
@@ -697,6 +718,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
preserve_groups By default, ssuuddoo will initialize the group vector to
the list of groups the target user is in. When
1.7.1 April 18, 2009 11
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
_p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, the user's existing group
vector is left unaltered. The real and effective group
IDs, however, are still set to match the target user.
@@ -718,18 +751,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
as _c_r_o_n(1m) or cgi-bin scripts. This flag is _o_f_f by
default.
1.7.1 March 11, 2009 11
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
root_sudo If set, root is allowed to run ssuuddoo too. Disabling
this prevents users from "chaining" ssuuddoo commands to
get a root shell by doing something like "sudo sudo
@@ -763,6 +784,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
This can be done by negating the set_logname option.
Note that if the _e_n_v___r_e_s_e_t option has not been
disabled, entries in the _e_n_v___k_e_e_p list will override
1.7.1 April 18, 2009 12
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
the value of _s_e_t___l_o_g_n_a_m_e. This flag is _o_f_f by default.
setenv Allow the user to disable the _e_n_v___r_e_s_e_t option from the
@@ -784,18 +817,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
style globbing when matching pathnames. However, since
it accesses the file system, _g_l_o_b(3) can take a long
time to complete for some patterns, especially when the
1.7.1 March 11, 2009 12
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
pattern references a network file system that is
mounted on demand (automounted). The _f_a_s_t___g_l_o_b option
causes ssuuddoo to use the _f_n_m_a_t_c_h(3) function, which does
@@ -829,6 +850,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
user is logged in on in that directory. This flag is
_o_f_f by default.
1.7.1 April 18, 2009 13
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
umask_override If set, ssuuddoo will set the umask as specified by _s_u_d_o_e_r_s
without modification. This makes it possible to
specify a more permissive umask in _s_u_d_o_e_r_s than the
@@ -850,18 +883,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
things like "rsh somehost sudo ls" since _r_s_h(1) does
not allocate a tty. This flag is _o_f_f by default.
1.7.1 March 11, 2009 13
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
IInntteeggeerrss:
closefrom Before it executes a command, ssuuddoo will close all open
@@ -896,6 +917,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
their own timestamps via sudo -v and sudo -k
respectively.
1.7.1 April 18, 2009 14
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
umask Umask to use when running the command. Negate this
option or set it to 0777 to preserve the user's umask.
The actual umask that is used will be the union of the
@@ -916,18 +948,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
matches the user's EDITOR environment variable if
possible, or the first editor in the list that exists
and is executable. The default is the path to vi on
1.7.1 March 11, 2009 14
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
your system.
mailsub Subject of the mail sent to the _m_a_i_l_t_o user. The escape
@@ -962,6 +982,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
%u expanded to the invoking user's login name
1.7.1 April 18, 2009 15
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
%% two consecutive % characters are collapsed into a
single % character
@@ -982,18 +1014,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
changing the locale may affect how sudoers is
interpreted. Defaults to "C".
1.7.1 March 11, 2009 15
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
timestampdir The directory in which ssuuddoo stores its timestamp files.
The default is _/_v_a_r_/_r_u_n_/_s_u_d_o.
@@ -1029,6 +1049,17 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
always Always lecture the user.
1.7.1 April 18, 2009 16
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
never Never lecture the user.
once Only lecture the user the first time they run ssuuddoo.
@@ -1048,18 +1079,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
all All the user's _s_u_d_o_e_r_s entries for the current host
must have the NOPASSWD flag set to avoid entering a
1.7.1 March 11, 2009 16
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
password.
always The user must always enter a password to use the --ll
@@ -1095,6 +1114,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
ssuuddoo interpreting the @ sign. Defaults to root.
secure_path Path used for every command run from ssuuddoo. If you don't
1.7.1 April 18, 2009 17
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
trust the people running ssuuddoo to have a sane PATH
environment variable you may want to use this. Another use
is if you want to have the "root path" be separate from the
@@ -1114,18 +1145,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
password.
always The user must always enter a password to use the --vv
1.7.1 March 11, 2009 17
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
option.
any At least one of the user's _s_u_d_o_e_r_s entries for the
@@ -1161,6 +1180,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
space-separated list or a single value without double-
quotes. The list can be replaced, added to, deleted
from, or disabled by using the =, +=, -=, and !
1.7.1 April 18, 2009 18
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
operators respectively. The default list of
environment variables to remove is displayed when ssuuddoo
is run by root with the _-_V option. Note that many
@@ -1180,18 +1211,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
with the _-_V option.
When logging via _s_y_s_l_o_g(3), ssuuddoo accepts the following values for the
1.7.1 March 11, 2009 18
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
syslog facility (the value of the ssyysslloogg Parameter): aauutthhpprriivv (if your
OS supports it), aauutthh, ddaaeemmoonn, uusseerr, llooccaall00, llooccaall11, llooccaall22, llooccaall33,
llooccaall44, llooccaall55, llooccaall66, and llooccaall77. The following syslog priorities
@@ -1228,6 +1247,18 @@ EEXXAAMMPPLLEESS
Host_Alias SERVERS = master, mail, www, ns
Host_Alias CDROM = orion, perseus, hercules
1.7.1 April 18, 2009 19
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
# Cmnd alias specification
Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
/usr/sbin/restore, /usr/sbin/rrestore
@@ -1246,18 +1277,6 @@ EEXXAAMMPPLLEESS
to log via _s_y_s_l_o_g(3) using the _a_u_t_h facility in all cases. We don't
want to subject the full time staff to the ssuuddoo lecture, user mmiilllleerrtt
need not give a password, and we don't want to reset the LOGNAME, USER
1.7.1 March 11, 2009 19
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
or USERNAME environment variables when running commands as root.
Additionally, on the machines in the _S_E_R_V_E_R_S Host_Alias, we keep an
additional local log file and make sure we log the year in each log
@@ -1293,6 +1312,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
any host but they must authenticate themselves first (since the entry
lacks the NOPASSWD tag).
1.7.1 April 18, 2009 20
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
jack CSNETS = ALL
The user jjaacckk may run any command on the machines in the _C_S_N_E_T_S alias
@@ -1312,18 +1343,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
The ooppeerraattoorr user may run commands limited to simple maintenance.
Here, those are commands related to backups, killing processes, the
printing system, shutting down the system, and any commands in the
1.7.1 March 11, 2009 20
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
directory _/_u_s_r_/_o_p_e_r_/_b_i_n_/.
joe ALL = /usr/bin/su operator
@@ -1359,6 +1378,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
1.7.1 April 18, 2009 21
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
On the _A_L_P_H_A machines, user jjoohhnn may su to anyone except root but he is
not allowed to specify any options to the _s_u(1) command.
@@ -1378,18 +1409,6 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
The user sstteevvee may run any command in the directory
/usr/local/op_commands/ but only as user operator.
1.7.1 March 11, 2009 21
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
matt valkyrie = KILL
On his personal workstation, valkyrie, mmaatttt needs to be able to kill
@@ -1425,6 +1444,18 @@ SSEECCUURRIITTYY NNOOTTEESS
PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS
Once ssuuddoo executes a program, that program is free to do whatever it
1.7.1 April 18, 2009 22
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
pleases, including run other programs. This can be a security issue
since it is not uncommon for a program to allow shell escapes, which
lets a user bypass ssuuddoo's access control and logging. Common programs
@@ -1444,18 +1475,6 @@ PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS
to override default library functions by pointing an
environment variable (usually LD_PRELOAD) to an alternate
shared library. On such systems, ssuuddoo's _n_o_e_x_e_c functionality
1.7.1 March 11, 2009 22
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
can be used to prevent a program run by ssuuddoo from executing
any other programs. Note, however, that this applies only to
native dynamically-linked executables. Statically-linked
@@ -1491,6 +1510,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
This allows user aaaarroonn to run _/_u_s_r_/_b_i_n_/_m_o_r_e and _/_u_s_r_/_b_i_n_/_v_i
with _n_o_e_x_e_c enabled. This will prevent those two commands
1.7.1 April 18, 2009 23
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
from executing other commands (such as a shell). If you are
unsure whether or not your system is capable of supporting
_n_o_e_x_e_c you can always just try it out and see if it works.
@@ -1510,18 +1541,6 @@ CCAAVVEEAATTSS
_s_u_d_o_e_r_s be free of syntax errors since ssuuddoo will not run with a
syntactically incorrect _s_u_d_o_e_r_s file.
1.7.1 March 11, 2009 23
SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4)
When using netgroups of machines (as opposed to users), if you store
fully qualified hostnames in the netgroup (as is usually the case), you
either need to have the machine's hostname be fully qualified as
@@ -1560,25 +1579,6 @@ DDIISSCCLLAAIIMMEERR
1.7.1 March 11, 2009 24
1.7.1 April 18, 2009 24

View File

@@ -153,7 +153,7 @@
.\" ========================================================================
.\"
.IX Title "SUDOERS @mansectform@"
.TH SUDOERS @mansectform@ "March 11, 2009" "1.7.1" "MAINTENANCE COMMANDS"
.TH SUDOERS @mansectform@ "April 18, 2009" "1.7.1" "MAINTENANCE COMMANDS"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -598,13 +598,15 @@ with \fBany\fR arguments.
.Sh "Including other files from within sudoers"
.IX Subsection "Including other files from within sudoers"
It is possible to include other \fIsudoers\fR files from within the
\&\fIsudoers\fR file currently being parsed using the \f(CW\*(C`#include\*(C'\fR
directive, similar to the one used by the C preprocessor. This is
useful, for example, for keeping a site-wide \fIsudoers\fR file in
addition to a per-machine local one. For the sake of this example
the site-wide \fIsudoers\fR will be \fI/etc/sudoers\fR and the per-machine
one will be \fI/etc/sudoers.local\fR. To include \fI/etc/sudoers.local\fR
from within \fI/etc/sudoers\fR we would use the following line in \fI/etc/sudoers\fR:
\&\fIsudoers\fR file currently being parsed using the \f(CW\*(C`#include\*(C'\fR and
\&\f(CW\*(C`#includedir\*(C'\fR directives.
.PP
This can be used, for example, to keep a site-wide \fIsudoers\fR file
in addition to a local, per-machine file. For the sake of this
example the site-wide \fIsudoers\fR will be \fI/etc/sudoers\fR and the
per-machine one will be \fI/etc/sudoers.local\fR. To include
\&\fI/etc/sudoers.local\fR from within \fI/etc/sudoers\fR we would use the
following line in \fI/etc/sudoers\fR:
.Sp
.RS 4
\&\f(CW\*(C`#include /etc/sudoers.local\*(C'\fR
@@ -625,6 +627,28 @@ of the hostname. I.e., if the machine's hostname is \*(L"xerxes\*(R", then
.Ve
.PP
will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR.
.PP
The \f(CW\*(C`#includedir\*(C'\fR directive can be used to create a \fIsudo.d\fR
directory that the system package manager can drop \fIsudoers\fR rules
into as part of package installation. For example, given:
.PP
.Vb 1
\& #includedir /etc/sudoers.d
.Ve
.PP
\&\fBsudo\fR will read each file in \fI/etc/sudoers.d\fR, skipping files
that end in \*(L".tmp\*(R" to avoid causing problems with \fBvisudo\fR. Files
are parsed in sorted lexical order. That is, \fI/etc/sudoers.d/01_first\fR
will be parsed before \fI/etc/sudoers.d/10_second\fR. Be aware that
because the sorting is lexical, not numeric, \fI/etc/sudoers.d/1_whoops\fR
would be loaded \fBafter\fR \fI/etc/sudoers.d/10_second\fR. Using a
consistent number of leading zeroes in the file names can be used
to avoid such problems.
.PP
Note that unlike files included via \f(CW\*(C`#include\*(C'\fR, \fBvisudo\fR will not
edit the files in a \f(CW\*(C`#includedir\*(C'\fR directory unless one of them
contains a syntax error. It is still possible to run \fBvisudo\fR
with the \f(CW\*(C`\-f\*(C'\fR flag to edit the files directly.
.Sh "Other special characters and reserved words"
.IX Subsection "Other special characters and reserved words"
The pound sign ('#') is used to indicate a comment (unless it is

View File

@@ -441,13 +441,15 @@ with B<any> arguments.
=head2 Including other files from within sudoers
It is possible to include other I<sudoers> files from within the
I<sudoers> file currently being parsed using the C<#include>
directive, similar to the one used by the C preprocessor. This is
useful, for example, for keeping a site-wide I<sudoers> file in
addition to a per-machine local one. For the sake of this example
the site-wide I<sudoers> will be F</etc/sudoers> and the per-machine
one will be F</etc/sudoers.local>. To include F</etc/sudoers.local>
from within F</etc/sudoers> we would use the following line in F</etc/sudoers>:
I<sudoers> file currently being parsed using the C<#include> and
C<#includedir> directives.
This can be used, for example, to keep a site-wide I<sudoers> file
in addition to a local, per-machine file. For the sake of this
example the site-wide I<sudoers> will be F</etc/sudoers> and the
per-machine one will be F</etc/sudoers.local>. To include
F</etc/sudoers.local> from within F</etc/sudoers> we would use the
following line in F</etc/sudoers>:
=over 4
@@ -469,6 +471,26 @@ of the hostname. I.e., if the machine's hostname is "xerxes", then
will cause B<sudo> to include the file F</etc/sudoers.xerxes>.
The C<#includedir> directive can be used to create a F<sudo.d>
directory that the system package manager can drop I<sudoers> rules
into as part of package installation. For example, given:
#includedir /etc/sudoers.d
B<sudo> will read each file in F</etc/sudoers.d>, skipping files
that end in ".tmp" to avoid causing problems with B<visudo>. Files
are parsed in sorted lexical order. That is, F</etc/sudoers.d/01_first>
will be parsed before F</etc/sudoers.d/10_second>. Be aware that
because the sorting is lexical, not numeric, F</etc/sudoers.d/1_whoops>
would be loaded B<after> F</etc/sudoers.d/10_second>. Using a
consistent number of leading zeroes in the file names can be used
to avoid such problems.
Note that unlike files included via C<#include>, B<visudo> will not
edit the files in a C<#includedir> directory unless one of them
contains a syntax error. It is still possible to run B<visudo>
with the C<-f> flag to edit the files directly.
=head2 Other special characters and reserved words
The pound sign ('#') is used to indicate a comment (unless it is

View File

@@ -373,8 +373,9 @@ set_fqdn()
}
FILE *
open_sudoers(path, keepopen)
open_sudoers(path, isdir, keepopen)
const char *path;
int isdir;
int *keepopen;
{
return(fopen(path, "r"));

1681
toke.c

File diff suppressed because it is too large Load Diff

245
toke.l
View File

@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
@@ -50,6 +51,7 @@
# include <malloc.h>
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
#include <ctype.h>
#include <dirent.h>
#include "sudo.h"
#include "parse.h"
#include <gram.h>
@@ -69,15 +71,16 @@ static int append __P((char *, int));
static int _fill __P((char *, int, int));
static int fill_cmnd __P((char *, int));
static int fill_args __P((char *, int, int));
static int switch_buffer __P((char *));
static int _push_include __P((char *, int));
static int pop_include __P((void));
static int ipv6_valid __P((const char *s));
static char *parse_include __P((char *));
extern void yyerror __P((const char *));
#define fill(a, b) _fill(a, b, 0)
#define push_include(_p) (switch_buffer((_p)))
#define pop_include() (switch_buffer(NULL))
#define push_include(_p) (_push_include((_p), FALSE))
#define push_includedir(_p) (_push_include((_p), TRUE))
/* realloc() to size + COMMANDARGINC to make room for command args */
#define COMMANDARGINC 64
@@ -227,6 +230,19 @@ DEFVAR [a-z_]+
yyterminate();
}
<INITIAL>^#includedir[[:blank:]]+\/.*\n {
char *path;
if ((path = parse_include(yytext)) == NULL)
yyterminate();
LEXTRACE("INCLUDEDIR\n");
/* Push current buffer and switch to include file */
if (!push_includedir(path))
yyterminate();
}
<INITIAL>^[[:blank:]]*Defaults([:@>\!]{WORD})? {
int n;
for (n = 0; isblank((unsigned char)yytext[n]); n++)
@@ -605,63 +621,228 @@ fill_args(s, len, addspace)
return(TRUE);
}
struct sudoers_state {
struct path_list {
char *path;
struct path_list *next;
};
struct include_stack {
YY_BUFFER_STATE bs;
char *path;
struct path_list *more; /* more files in case of includedir */
int lineno;
int keepopen;
};
static int
pl_compare(v1, v2)
const void *v1;
const void *v2;
{
const struct path_list * const *p1 = v1;
const struct path_list * const *p2 = v2;
return(strcmp((*p1)->path, (*p2)->path));
}
static char *
switch_dir(stack, dirpath)
struct include_stack *stack;
char *dirpath;
{
DIR *dir;
int i, count = 0;
char *path = NULL;
struct dirent *dent;
struct stat sb;
struct path_list *pl, *first = NULL;
struct path_list **sorted = NULL;
if (!(dir = opendir(dirpath))) {
yyerror(dirpath);
return(FALSE);
}
while ((dent = readdir(dir))) {
/* Ignore visudo .tmp files. */
if (dent->d_namlen > 4 &&
strcmp(dent->d_name + dent->d_namlen - 4, ".tmp") == 0) {
continue;
}
if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
closedir(dir);
goto bad;
}
if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
efree(path);
continue;
}
pl = malloc(sizeof(*pl));
if (pl == NULL)
goto bad;
pl->path = path;
pl->next = first;
first = pl;
count++;
}
closedir(dir);
if (count == 0)
goto done;
/* Sort the list as an array. */
sorted = malloc(sizeof(*sorted) * count);
if (sorted == NULL)
goto bad;
pl = first;
for (i = 0; i < count; i++) {
sorted[i] = pl;
pl = pl->next;
}
qsort(sorted, count, sizeof(*sorted), pl_compare);
/* Apply sorting to the list. */
first = sorted[0];
sorted[count - 1]->next = NULL;
for (i = 1; i < count; i++)
sorted[i - 1]->next = sorted[i];
efree(sorted);
/* Pull out the first element for parsing, leave the rest for later. */
if (count) {
path = first->path;
pl = first->next;
efree(first);
stack->more = pl;
} else {
path = NULL;
}
done:
efree(dirpath);
return(path);
bad:
while (first != NULL) {
pl = first;
first = pl->next;
free(pl->path);
free(pl);
}
efree(sorted);
efree(dirpath);
efree(path);
return(NULL);
}
#define MAX_SUDOERS_DEPTH 128
#define SUDOERS_STACK_INCREMENT 16
static int
switch_buffer(path)
char *path;
static size_t istacksize, idepth;
static struct include_stack *istack;
static int keepopen;
void
init_lexer()
{
struct path_list *pl;
while (idepth) {
idepth--;
while ((pl = istack[idepth].more) != NULL) {
istack[idepth].more = pl->next;
efree(pl->path);
efree(pl);
}
efree(istack[idepth].path);
if (!istack[idepth].keepopen)
fclose(istack[idepth].bs->yy_input_file);
yy_delete_buffer(istack[idepth].bs);
}
efree(istack);
istack = NULL;
istacksize = idepth = 0;
keepopen = FALSE;
}
static int
_push_include(path, isdir)
char *path;
int isdir;
{
static size_t stacksize, depth;
static struct sudoers_state *state;
static int keepopen;
FILE *fp;
if (path != NULL) {
/* push current state */
if (depth >= stacksize) {
if (depth > MAX_SUDOERS_DEPTH) {
/* push current state onto stack */
if (idepth >= istacksize) {
if (idepth > MAX_SUDOERS_DEPTH) {
yyerror("too many levels of includes");
return(FALSE);
}
stacksize += SUDOERS_STACK_INCREMENT;
state = (struct sudoers_state *) realloc(state,
sizeof(state) * stacksize);
if (state == NULL) {
istacksize += SUDOERS_STACK_INCREMENT;
istack = (struct include_stack *) realloc(istack,
sizeof(istack) * istacksize);
if (istack == NULL) {
yyerror("unable to allocate memory");
return(FALSE);
}
}
if ((fp = open_sudoers(path, &keepopen)) == NULL) {
if (isdir) {
if (!(path = switch_dir(&istack[idepth], path))) {
yyerror(path);
return(FALSE);
}
state[depth].bs = YY_CURRENT_BUFFER;
state[depth].path = sudoers;
state[depth].lineno = sudolineno;
depth++;
if ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
yyerror(path);
return(FALSE); /* XXX - just to go next one? */
}
} else {
if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
yyerror(path);
return(FALSE);
}
istack[idepth].more = NULL;
}
/* Push the old (current) file and open the new one. */
istack[idepth].path = sudoers; /* push old path */
istack[idepth].bs = YY_CURRENT_BUFFER;
istack[idepth].lineno = sudolineno;
istack[idepth].keepopen = keepopen;
idepth++;
sudolineno = 1;
sudoers = path;
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
} else {
/* pop */
if (depth == 0)
return(TRUE);
}
static int
pop_include()
{
struct path_list *pl;
FILE *fp;
if (idepth == 0)
return(FALSE);
depth--;
if (!keepopen)
fclose(YY_CURRENT_BUFFER->yy_input_file);
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(state[depth].bs);
efree(sudoers);
sudoers = state[depth].path;
sudolineno = state[depth].lineno;
keepopen = FALSE;
if ((pl = istack[idepth - 1].more) != NULL) {
/* Move to next file in the dir. */
istack[idepth - 1].more = pl->next;
if ((fp = open_sudoers(pl->path, FALSE, &keepopen)) == NULL) {
yyerror(pl->path);
return(FALSE); /* XXX - just to go next one? */
}
efree(sudoers);
sudoers = pl->path;
sudolineno = 1;
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
efree(pl);
} else {
idepth--;
yy_switch_to_buffer(istack[idepth].bs);
efree(sudoers);
sudoers = istack[idepth].path;
sudolineno = istack[idepth].lineno;
}
return(TRUE);
}
@@ -676,6 +857,8 @@ parse_include(base)
/* Pull out path from #include line. */
cp = base + sizeof("#include");
if (*cp == 'i')
cp += 3; /* includedir */
while (isblank((unsigned char) *cp))
cp++;
ep = cp;

View File

@@ -93,10 +93,11 @@ __unused static const char rcsid[] = "$Sudo$";
struct sudoersfile {
char *path;
int fd;
char *tpath;
int fd;
int tfd;
int modified;
int doedit;
struct sudoersfile *next;
};
@@ -215,8 +216,9 @@ main(argc, argv)
* Parse the existing sudoers file(s) in quiet mode to highlight any
* existing errors and to pull in editor and env_editor conf values.
*/
if ((yyin = open_sudoers(sudoers_path, NULL)) == NULL)
if ((yyin = open_sudoers(sudoers_path, TRUE, NULL)) == NULL) {
error(1, "%s", sudoers_path);
}
init_parser(sudoers_path, 0);
yyparse();
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER);
@@ -228,6 +230,8 @@ main(argc, argv)
/* Edit the sudoers file(s) */
tq_foreach_fwd(&sudoerslist, sp) {
if (!sp->doedit)
continue;
if (sp != tq_first(&sudoerslist)) {
printf("press return to edit %s: ", sp->path);
while ((ch = getchar()) != EOF && ch != '\n')
@@ -747,8 +751,9 @@ check_syntax(sudoers_path, quiet, strict)
* any subsequent files #included via a callback from the parser.
*/
FILE *
open_sudoers(path, keepopen)
open_sudoers(path, doedit, keepopen)
const char *path;
int doedit;
int *keepopen;
{
struct sudoersfile *entry;
@@ -766,6 +771,8 @@ open_sudoers(path, keepopen)
entry->next = NULL;
entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE);
entry->tpath = NULL;
entry->tfd = -1;
entry->doedit = doedit;
if (entry->fd == -1) {
warning("%s", entry->path);
efree(entry);