11

I'm trying to do the safe thing, and have a program that needs to runs as root to drop its privileges when it doesn't need them. This works well if I chmod my binary with the SUID bit, and make it belong to root, as now I have UID = some user, and EUID = root, so I can use seteuid(0) and seteuid(getuid()) to respectively raise and drop admin rights.

But if I use sudo instead of setting the SUID, then UID == EUID == 0, and so calling seteuid(getuid()) won't have any effect. And I can't just change UID to some value from some random user, as the setuid() man page clearly states that if it is called from a program running as root, one loses the privileges for good, with no hope of getting them back.

So, how do I make my program lose temporarily its privileges when run using sudo?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Florian
  • 1,725
  • 3
  • 14
  • 13

4 Answers4

11

seteuid(some random uid) to drop privileges, seteuid(0) to get them back, when running as root.

Aidan Cully
  • 5,457
  • 24
  • 27
  • 3
    Of course - that leaves the problem of getting the original UID of the user who called `sudo` - if the OP needs to go back to that user? – Douglas Leeder Feb 16 '10 at 18:52
  • Of course, there's a chance that the random UID you switch to just happens to be the sysadmin's UID. – user253751 Sep 25 '16 at 21:09
  • sudo creates environment variables containing the UID and GID of the calling user. You can switch to "nobody" read the variable and switch to that user. I don't recommend reading environment variables as root. "nobody" is restricted account present on most unix systems. – wheredidthatnamecomefrom Feb 18 '18 at 23:28
6

It seems like seteuid(x) should work to drop and re-raise privs...

$ cat > t12.c
#include <stdio.h>
#include <unistd.h>

void p(void) { printf("euid=%4d uid=%4d\n", geteuid(), getuid()); }

int main(void) { p(); seteuid(100); p(); seteuid(0); p(); return 0; }
$ cc -Wall t12.c
$ sudo chown root a.out && sudo chmod 4555 a.out
$ sudo ./a.out
euid=   0 uid=   0
euid= 100 uid=   0
euid=   0 uid=   0
$ ./a.out
euid=   0 uid= 501
euid= 100 uid= 501
euid=   0 uid= 501
$ 
DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
3

Not a direct answer, just would like to point you to the idea of privilege separation. Here's a great presentation by OpenBSD founder Theo de Raadt.

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
1

Fork() before you drop privileges. Wait in the parent task until the child with reduced privileges is done, then resume in the parent with root.

seteuid is not portable to all unices and has other drawbacks too.

Jürgen Strobel
  • 2,200
  • 18
  • 30