4

I'm currently trying to figure out how the SUID-bit and the corresponding functions seteuid and geteuid work. So I wrote this little program:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char **argv) {

    printf("oldid %d\n", geteuid());
    if(seteuid(0) == -1)
        perror("seteuid faied");
    printf("newid %d\n", geteuid());

    return 0;

}

Compiled it, changed its owner to root and the s-bit for the owner of the file:

[chris@myhost Test]$ ls -l test
-rwsr-xr-x 1 root root 4830 Apr  5 07:56 test

But then the produced output looks like this:

[chris@myhost Test]$ ./test
oldid 0
newid 0

And this is something I do not understand. According to what I have found the first call of geteuid should actually return the userid of the caller of this program (i.e. chris - my ID would be 1000), but the program shows root as the effective user id. Can anyone explain me why this is the case?

Chris
  • 2,030
  • 1
  • 16
  • 22

1 Answers1

7

From the man page of geteuid() on my Mac (OS X 10.6.7):

The real user ID is that of the user who has invoked the program. As the effective user ID gives the process additional permissions during execution of ``set-user-ID'' mode processes, getuid() is used to determine the real-user-id of the calling process.

Since you have set the suid bit, the effective user id of the program is the file owner (root) from the start of execution.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Ok, thank you (that info wasn't in my manpage). But then the whole concept seems useless? Assume I have a small piece of code within my program which I want to execute with root rights. My plan was to make root the owner of the whole program, set the SUID-bit and than change the effective userid for just the small part... How can I achieve this then? – Chris Apr 05 '11 at 08:26
  • @Chris: That's a big topic and may vary depending on your operating system. On Mac OS X, the general strategy always *used* to be to have a separate program that does the bit requiring privileges and make that the setuid program. The main program would fork and exec to run the separate program. That makes the setuid part very small and less likely to have security holes. – JeremyP Apr 05 '11 at 10:10
  • @Chris: Current best practice on OS X is to create a launch daemon that runs as root and use it to service requests via a Unix domain socket. In both the old way and the new way, you need to authenticate the user in the privileged code to make sure they are authorised to do the operation (OS X provides an API to do this). – JeremyP Apr 05 '11 at 10:12
  • 1
    @Chris: I'll comment for the sake of the record and to help a poor soul in future perhaps. Its not useless. It just works the other way around from what you think. You need to immediately seteuid to your own user at startup and thereafter switch for short whiles to the other user. The Unix design flaw is perhaps that it starts out as the other user instead of yourself (see Advanced Programming in the UNIX Environment 8.10) – Waslap May 30 '16 at 12:59
  • To do something as root and then drop back to normal user id, you need to use something like `getresuid()` (assuming you have Linux). However, that is not defined by POSIX so you may need to figure out the similar features for other UNIX-like systems. See also: https://stackoverflow.com/q/34452939/334451 – Mikko Rantalainen Mar 14 '18 at 08:08