Question

I compiled this sample set-root-id program:

  #define _GNU_SOURCE

  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>


  void print_ids()
     {
     uid_t ruid, euid, suid, rgid, egid, sgid;

     getresuid(&ruid, &euid, &suid);
     printf("\nruid=%d, euid=%d, suid=%d\n", ruid, euid, suid);

     getresgid(&rgid, &egid, &sgid);
     printf("rgid=%d, egid=%d, sgid=%d\n\n", rgid, egid, sgid);
     }


  void main(int argc, char *argv[])
     {
     print_ids();
     seteuid(1000); printf("seteuid(1000): %s\n", strerror(errno));
     print_ids();
     seteuid(1001); printf("seteuid(1001): %s\n", strerror(errno));
     print_ids();
     seteuid(0);    printf("seteuid(0): %s\n",    strerror(errno));   
     print_ids();
     }

Call to seteuid(0) works, but dislays an error message: "Operation not permitted":

$ gcc -Wall ./p3.c -o p3
./p3.c:32: warning: return type of ‘main’ is not ‘int’
$ su -c "chown root:root ./p3 ; chmod 4755 ./p3"
Password: ****
$ ls -l ./p3
-rwsr-xr-x 1 root root 7697  2 gen 19.21 ./p3
$ ./p3

ruid=1000, euid=0, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(1000): Success

ruid=1000, euid=1000, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(1001): Operation not permitted

ruid=1000, euid=1000, suid=0
rgid=1000, egid=1000, sgid=1000

seteuid(0): Operation not permitted

ruid=1000, euid=0, suid=0
rgid=1000, egid=1000, sgid=1000

$

Why seteuid(0) works but displays the error message? I noticed that omitting call to seteuid(1001) or call to seteuid(1000) no error messages appear.

Thank you

(I work on Debian 6, gcc version 4.4.5)

Was it helpful?

Solution

The old EPERM is still in errno from the previous call. Successful system calls do not set errno to 0; you have to do that yourself.

Usually, you don't need to set errno to 0. You check the return value of the system call, and then if that indicates failure, you check errno for more details. errno doesn't tell you that something failed - it tells you how something failed.

There's an exception to this general rule for functions with no distinct error indicator in their return value, like strtoul, but seteuid isn't one of those. It has a clean return value. If it returns 0, you shouldn't print an error message at all.

And relying on strerror(0) to produce a "success message" isn't clean either - in current glibc it says "Success" but I can still remember when strerror(0) was "Unknown error 0". Maybe somewhere it still is.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top