When configuring sudo privileges, we often encounter scenarios where we need to strictly control the number of arguments passed to a command. The current sudoers syntax provides some pattern matching capabilities, but enforcing exact argument counts requires careful consideration.
The example shows a sudoers entry attempting to restrict /bin/echo
to accept arguments matching [a-z]*
pattern:
# tail -1 /etc/sudoers
ALL ALL = (:tool) NOPASSWD: /bin/echo [a-z]*
This approach has two key limitations:
- It allows multiple arguments (as shown by
echo abc def
working) - It fails to properly handle option arguments (
-abc
triggers password prompt)
The sudoers file supports some basic pattern matching but lacks direct argument count control. We can attempt these approaches:
# Option 1: Wildcard pattern (still allows multiple args)
ALL ALL = (:tool) NOPASSWD: /bin/echo [a-z]
# Option 2: Trying to enforce single arg (won't work)
ALL ALL = (:tool) NOPASSWD: /bin/echo [a-z][^ ]*
Neither solution properly restricts to exactly one argument while allowing both options and regular arguments.
The most reliable solution involves creating a wrapper script with strict argument validation:
#!/bin/bash
# /usr/local/bin/restricted_echo
if [ $# -ne 1 ]; then
echo "Error: Exactly one argument required" >&2
exit 1
fi
/bin/echo "$1"
Then configure sudoers to only allow this wrapper:
ALL ALL = (:tool) NOPASSWD: /usr/local/bin/restricted_echo
For simple cases, we can combine multiple patterns to approximate single-argument behavior:
# Allow either one option or one non-option argument
ALL ALL = (:tool) NOPASSWD: /bin/echo -*, /bin/echo [a-zA-Z0-9]*
Key limitations:
- Still technically permits multiple args if they match the pattern
- Character classes must be carefully defined
- May become unwieldy for complex requirements
When implementing argument restrictions:
- Wrapper scripts must be immutable (chattr +i) and root-owned
- Prefer absolute paths in sudoers entries
- Consider SELinux/AppArmor context if enabled
- Test with various argument combinations including special characters
Always validate your configuration with various test cases:
# Should work
sudo -g tool /bin/echo singleargument
sudo -g tool /bin/echo -n
# Should fail
sudo -g tool /bin/echo first second
sudo -g tool /bin/echo "contains spaces"
sudo -g tool /bin/echo *
Remember that sudoers syntax has limitations, and for precise control, wrapper scripts often provide the most reliable solution.
When configuring sudo privileges, administrators often need to precisely control command arguments. The original poster's case presents an interesting challenge: allowing execution of /bin/echo
with exactly one non-option argument (like abc
) while rejecting multiple arguments (like abc def
) or option-style arguments (like -abc def
).
The existing sudoers entry:
ALL ALL = (:tool) NOPASSWD: /bin/echo [a-z]*
This pattern matches:
- Single arguments (
abc
) - Multiple arguments (
abc def
) - But interestingly fails on option-style arguments (
-abc def
)
The [a-z]*
pattern in sudoers is a simple wildcard that:
- Doesn't count arguments
- Doesn't distinguish between options and non-options
- Only performs basic pattern matching on the entire argument string
Unfortunately, sudoers syntax can't directly enforce an exact argument count. The closest approximation:
ALL ALL = (:tool) NOPASSWD: /bin/echo [^-][a-z]*
This will:
- Allow
abc
- Prevent
-abc
- But still allow
abc def
The most reliable method is creating a wrapper script that enforces argument rules:
#!/bin/bash
# /usr/local/bin/restricted_echo
if [ $# -ne 1 ] || [[ $1 == -* ]]; then
echo "Error: Exactly one non-option argument required" >&2
exit 1
fi
/bin/echo "$1"
Then in sudoers:
ALL ALL = (:tool) NOPASSWD: /usr/local/bin/restricted_echo
Test cases:
$ sudo -g tool /usr/local/bin/restricted_echo abc
abc
$ sudo -g tool /usr/local/bin/restricted_echo abc def
Error: Exactly one non-option argument required
$ sudo -g tool /usr/local/bin/restricted_echo -abc def
Error: Exactly one non-option argument required
For simple cases, you might combine sudoers patterns with shell features:
ALL ALL = (:tool) NOPASSWD: /bin/sh -c '[[ $# -eq 1 && $1 != -* ]] && /bin/echo "$1"' sh
But this becomes complex to maintain and audit.
When implementing argument restrictions:
- Always audit wrapper scripts for potential injection vectors
- Consider filesystem permissions on wrapper scripts
- Document the restrictions clearly in sudoers comments
- Test edge cases thoroughly (empty arguments, special characters)