How to Restrict sudo Command to Accept Exactly One Argument in sudoers File


4 views

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)