32

I want to allow one user to run grep (through sudo), and to grep for one specific string in one specific file. I don't want to allow this user to be able to run grep on all files. The user doesn't have read access to the file, hence the requirement to use sudo. I am trying to write a nagios check which greps the log file of another service on the machine.

However it doesn't work, sudo keeps asking for a password.

My command is: sudo grep "string I want (" /var/log/thefilename.log (yes, there is a raw ( and some spaces in the string I want to grep)

/etc/sudoers.d/user-can-grep has this content:

user ALL=(root) NOPASSWD: /bin/grep "string I want (" /var/log/thefilename.log

This sudoers file is owned by root:root and has permissions -r--r-----

The server is Ubuntu trusty 14.04.3 LTS.

How can I make this work?

Braiam
  • 35,991
Amandasaurus
  • 1,256
  • Is the nagios check explicitly calling /bin/grep, or /usr/bin/grep? – Jeff Schaller Apr 26 '16 at 10:09
  • 1
    Write a shell script that does this, and then let the script be run through sudo. – user253751 Apr 26 '16 at 22:22
  • 1
    @JeffSchaller FYI the script just calls grep, and which grep tells me it's using /bin/grep. AFAIK in sudo file you need to specify the full path of the binary, even if you call it without the full path. – Amandasaurus Apr 27 '16 at 08:16

4 Answers4

43
  1. Write a script (writeable only by root)
  2. In that script, execute the grep you need
  3. In the sudoers config, allow only access to that script
  4. Configure whatever tool or advise whichever user to just run the script via sudo

Much easier to debug, easier to lock down specific access to a specific file, and much harder to exploit.

EightBitTony
  • 21,373
  • 1
    Two issues so far. 1. /etc/sudoers doesn't quite supports arguments, so that's why the additional script. Usually, the script must not exist in a user's directory since it would be still writable. 2. Where to put the script so to have it relatively organized? – Artfaith Dec 19 '21 at 07:19
20

Apparently, sudo flattens the command into a string before comparing it to a specification in the sudoers file. So, in your case, you don't need to use quotes or any other form of escaping:

user ALL=(root) NOPASSWD: /bin/grep string I want ( /var/log/thefilename.log

Edit: As @user23013 points out in the comments, this can be exploited to grep for "string I want" in any file (and, by extension, also for "string I" and "string".) Please make a careful consideration before using sudo's argument checking!


Also note that the following invocations are equivalent, i.e. you won't be able to restrict users to one specific representation:

sudo grep "string I want (" /var/log/thefilename.log
sudo grep 'string I want (' /var/log/thefilename.log
sudo grep string\ I\ want\ \( /var/log/thefilename.log

This is due to the fact that quotes and escaping is handled by the shell and never reach sudo.

  • 1
    Interesting, I wonder if that's exploitable, i.e. convince sudo you typed one thing (which matches the specification) but when it comes to execute it, it is something else entirely. – EightBitTony Apr 26 '16 at 11:05
  • 4
    @EightBitTony Of course it is! In your sudoers: user host = NOPASSWD: /usr/bin/vim Editing sudoers file (with intention to let users edit "Editing sudoers file") can be exploited by cd'ing into /etc/ and running sudo vim Editing sudoers file. I'd say that for any command of reasonable complexity one should go with approach suggested in your comment—shell provides $@ variable where you can check that the arguments are grouped the way you expect them to be grouped. – Alexander Batischev Apr 26 '16 at 11:20
  • 9
    Create a path ( /var/log anywhere and symlink thefilename.log to any file, the user can grep string I want from any file then. – user23013 Apr 26 '16 at 11:20
  • 3
    @EightBitTony's answer (write a wrapper script, allow sudo access to that script) is much better and safer. – cas Apr 27 '16 at 01:41
  • Wow, that's extremely poor practice for a security-focused tool. – Sam Watkins May 09 '18 at 07:46
5

Since you only need root for the file access, consider using cat, tee or something similar and piping that to grep or whatever program you need to run. E.g. sudo cat /file/path | grep … This way you restrict root to where you absolutely need it.

2

sudo is great, but sometimes it is not the best fit. For this I like to use super. super also allows elevated permissions, however it assumes command aliases, which is convenient when allowing complicated command lines, because they are used as simple command lines.

your super.tab would look like:

grepcmd "grep 'string I want (' /var/log/thefilename.log" user

and would be invoked as super grepcmd.

hildred
  • 5,829
  • 3
  • 31
  • 43
  • 1
    sudo has Cmnd_Alias (which can contain one or more commands, with or without arg restrictions). – cas Apr 27 '16 at 01:36
  • Not the same thing at all. Cmnd_Alias is a tool for simplifying the configuration file, it does not expose an alias to the user which is super's primary mode of operation (which is why I use sudo when I am not either aliasing commands or running suid scripts (most of the time), and super for these two use cases). – hildred Apr 27 '16 at 01:46
  • that's what wrapper scripts are for...and they aren't limited to one-liners or have annoying quoting issues. – cas Apr 27 '16 at 03:18