why unix | RBL service | netrs | please | ripcalc | linescroll
hosted services

hosted services

an alternative

Don't forget to look at please.html, a rust sudo alternative.

time restricted entries

A little known feature of sudo is that you can specify NOTBEFORE and NOTAFTER rules. This means, if someone should only be able to run a command until a certain time, or not before a given time, it can be specified using these keywords.

Maybe Alice changes her role from web developer at the end of 2019, so no longer requires the ability to run the apache scripts:

alice ALL=(ALL) NOTAFTER=20191231235959 NOPASSWD: \
    /usr/sbin/apache2ctl restart, /usr/sbin/apache2ctl stop, \
    /usr/sbin/apache2ctl start, /usr/sbin/apache2ctl configtest

runaway wildcards

Most of us know that the following is rather dangerous to use in a sudoers file:


Well, to be more specific, something like the following:

user ALL=ALL /bin/cat /var/log/messages*

As the documentation points out, that * can expand to ANY character, any number of times. That would permit the following:

sudo /bin/cat /var/log/messages /etc/shadow

All we had to do was match the initial command and first argument. If you rotate log files, then the chances are you use the date as the file suffix, perhaps in ISO8601 format like a good citizen.

What we'd like to describe, is something like this, the messages file with, or without the date extension followed by .gz or, in regex:

user ALL=ALL /bin/cat /var/log/messages(-\d[8].gz)?

Wouldn't it be nice if we could do this?

It just so happens, that there's a patch for this.

Once it is applied, you can use the following syntax:

user ALL=ALL /bin/cat m{/var/log/messages((.[0-9]+|-[0-9]+)(.gz)?)?}

How about more log files, using the same extension format:

user ALL=ALL /bin/cat m{/var/log/(messages|syslog|maillog|kern|user)((.[0-9]+|-[0-9]+)(.gz)?)?}

You're welcome. One thing, the command must not be a regex, visudo checks the command part is valid.

What if you're not in a position where you can use this because you cannot deploy a source code build? Well, there is one last option. You can do something like this:

user ALL=ALL /bin/cat /var/log/messages*
user ALL=ALL !/bin/cat /var/log/messages* *

If you were to include any file following a trailing / then you need to add an additional exclusion to prevent path traversal (that's a word I've not thought about since early IIS web server issues, and sometimes I still see ..%255c..%255cwinnt/system32/cmd.exe in log files):

user ALL=ALL /bin/cat /var/log/*
user ALL=ALL !/bin/cat /var/log/* *
user ALL=ALL !/bin/cat /var/log/*..*

This can limit the damage, but it's not as tight as a regex. Ordering matters, if you reverse the instructions, or place the first after the last, then it is possible to read /etc/shadow again.

With the above pattern matching, the last match will win, ensure you include the negative matches last.

what if we need to include two wild cards in a rule?

Remember the rules above, always put the positive match at the top, and follow it with negatives as the last match has effect.

user ALL=(www-data) /usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache* */bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache*..*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/* */maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*..*/maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/* *.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*..*.db

I hope you find this patch useful.

safe file edits

Imagine you're managing the configuration for a busy computer. A new user joins the company and you need to re-push the configuration file.

In pushing out the configuration file you find that the disk filled, and the configuration was left in a partial state, a line was not finished as it crossed a block boundary. As a result sudo will now fail to parse the configuration and will not allow users to elevate. That's a shame.

To avoid problems like this, use visudo. You can use this interactive editor to modify sudoers or other sudoers files with -f:

visudo -f /etc/sudoers.d/users

This is great for interactive editing. To edit with sed, or echo >>, you can do something like this (append):

export EDITOR='tee -a'
echo 'alice ALL=ALL /usr/sbin/apache2ctl' \
| visudo -f /etc/sudoers.d/alice

To filter, like with sed, you can do the following (replace alice with bo and remove apche2ctl:

export EDITOR='tee -a'
cat /etc/sudoers.d/bob \
| grep -v /usr/sbin/apache2ctl \
| sed -e 's/^alice/bob/g' \
| visudo -f /etc/sudoers.d/bob

visudo will test the configuration before putting the files in place. This is very important so that end users do not experience breakage in their access. sudo is very critical to the stable running of systems whist ensuring least privilege access is maintained in place. Don't give your users excuse to have higher access than they need, they'll likely come running for root credentials as soon as lower access breaks, especially if they're from a windows background!

something with a space in the argument

If you want to permit something like the following (for when you don't have root login on the remote machine, but can run sudo):

sudo rsync -avP --rsync-path="sudo rsync" /source/directory user@remote:/some/where/to/copy/to

This might seem odd, but we'll get there, you could add an entry like the following in sudoers:

user ALL=ALL /usr/bin/rsync -avP --rsync-path=sudo\ rsync /source/directory user@remote:/some/where/to/copy/to

It's important to note the absence of quote marks around sudo rsync, and the backslash separating the two words. This is down to how the shell unqoutes the parameters.

safely edit a file that belongs to another user

Suppose you wish to permit a user (frank) to edit files belonging to opendkim in /etc/opendkim/* and /etc/opendkim.conf, but we don't know all their names yet:

frank ALL = (opendkim) sudoedit /etc/opendkim.conf
frank ALL = (opendkim) sudoedit /etc/opendkim/*
frank ALL = (opendkim) !sudoedit /etc/opendkim/*..*
frank ALL = (opendkim) !sudoedit /etc/opendkim/* *

Now, all frank needs to do is:

$ sudoedit -u opendkim /etc/opendkim.conf

You could easily modify files belonging to any other user by changing the relevant bits above.

how do i use : within a chown user:group sudo rule

: is a control character. In fact the following should be treated as control characters: , : = \.

character example use
, separates rules: frank ALL = (ALL) /bin/ls, /bin/cat
: join character for aliases
= used in definitions
\ used as an escape character

In order to use : within a rule, such as chown, you may do the following:

frank ALL = (root) /bin/chown frank\:frank -R /home/frank