Checking for setid commands in intercept mode after command matching
allows us to log a proper error message. Previously, we simply
ignored setid commands when matching and the only indication of why
was in the debug logs.
We rely on the include path to find many of these headers. It
especially doesn't make sense to use #include "foo.h" for headers
in the top-level include directory.
We now use ROWHAMMER-resistent values for ALLOW, DENY, AUTH_SUCCESS,
AUTH_FAILURE, AUTH_ERROR and AUTH_NONINTERACTIVE. In addition, we
explicitly test for expected values instead of using a negated test
against an error value. In the parser match functions this means
explicitly checking for ALLOW or DENY instead of accepting anything
that is not set to UNSPEC.
Thanks to Andrew J. Adiletta, M. Caner Tol, Yarkin Doroz, and Berk
Sunar, all affiliated with the Vernam Applied Cryptography and
Cybersecurity Lab at Worcester Polytechnic Institute, for the report.
Paper preprint: https://arxiv.org/abs/2309.02545
We now pass a pointer to the context where necessary. There are a
few cases where we need to request the context from sudoers via
sudoers_get_context() for the plugin API functions. If the plugin
API was able to pass around a closure pointer this would not be
necessary.
The output of "sudo -ll command" consists of the matching sudoers
rule (in long form) with the addition of a "Matched" entry that
shows the fully-qualfied path along with any arguments.
The single callback now receives all the match info (or UNSPEC if
no match was attempted). This makes it possible to use the callback
for more than just printing testsudoers output.
The format value has to be a string literal, every time.
Otherwise, you are not using these functions correctly. To reinforce this fact, I putrestrict over every non-contrib example of this I could find.
This allows us to use the LDAP-specific version of innetgr() when
possible. Also enable "use_netgroups" by default even on systems
without innetgr() since we can now query netgroups directly via
LDAP.
sudoers now supports an APPARMOR_PROFILE option, which can be specified
as e.g.
alice ALL=(ALL:ALL) APPARMOR_PROFILE=foo ALL
The line above says "user alice can run any command as any user/group,
under confinement by the AppArmor profile 'foo'." Profiles can be
specified in any way that complies with the rules of
aa_change_profile(2). For instance, the sudoers configuration
alice ALL=(ALL:ALL) APPARMOR_PROFILE=unconfined ALL
allows alice to run any command unconfined (i.e., without an AppArmor
profile), while
alice ALL=(ALL:ALL) APPARMOR_PROFILE=foo//&bar ALL
tells sudoers that alice can run any command under the stacked AppArmor
profiles 'foo' and 'bar'.
The intention of this option is to give sysadmins on Linux distros
supporting AppArmor better options for fine-grained access control.
Among other things, this option can enforce mandatory access control
(MAC) over the operations that a privileged user is able to perform to
ensure that they cannot privesc past the boundaries of a specified
profile. It can also be used to limit which users are able to get
unconfined system access, by enforcing a default AppArmor profile on all
users and then specifying 'APPARMOR_PROFILE=unconfined' for a privileged
subset of users.
The hook can be used to log parser errors (sudoers module) or keep
track of which files have an error (visudo).
Previously, we only kept track of a single parse error.
Previously, we checked that the previous entry's binding pointer
was not the same while freeing. However, to be able to merge
Defaults records we cannot rely on Defaults entries with the same
binding being immediately adjacent. This removes the prev_binding
checks in favor of a reference count which allows us to plug the
memory leak in cvtsudoers when merging Defaults.
This means that lhost and shost in struct sudoers_parse_tree
are no longer const and that free_parse_tree() will free lhost/shost.
The only consumer that passed in lho.st/shost was the SSSD back-end
which has been updated to avoid a double-free.
Duplicate aliases are remove. If there are conflicting alias names,
the conflicts are renamed by appending a numerical suffix.
For example, if there are two SERVERS Host_Aliases, the second one
will be renamed to SERVERS_1.
With this change, a shell in intercept mode cannot run a setuid or
setgid binary by default. On most systems, the dynamic loader will
ignore LD_PRELOAD for setuid/setgid binaries such as sudo which
would effectively disable intercept mode.
This causes "intercept" to be set to true in command_info[] which
the sudo front-end will use to determine whether or not to intercept
attempts to run further commands, such as from a shell. Also add
"log_children" which will use the same mechanism but only log (audit)
further commands.