setuid patch

Brad Fitzpatrick brad@danga.com
Tue, 9 Sep 2003 11:15:58 -0700 (PDT)


Checked in.

Lisa, your patch was okay, but it was a little too Perl-ish (char* foo = "")
and Avva's is just smaller, which is always nicer.  In any case, I gave
you credit too for doing the bulk of the effort/push.

- Brad


On Sun, 7 Sep 2003, Anatoly Vorobey wrote:

> On Fri, Sep 05, 2003 at 06:13:29PM -0400, Lisa Seelye wrote:
> > Attached is a patch made against the v1.38 memcached.c file to make
> > dropping root privileges possible (with the -u flag).
> >
> > The patch is also available at:
> > http://dev.gentoo.org/~lisa/memcached/setuid.patch
>
> Well... I have to admit it still looks much too large to me, considering
> its rather small (albeit significant) role in the larger scheme of
> things. It still takes up two source files, adds a few error codes used
> just in one place, and hardcodes a username ("root" - I don't know if
> there're admins out there sick enough to use a different username with
> userid 0, but it's possible. I think your testing getuid() after
> setuid() returned success is a shade too paranoid. If we can't trust
> the system functions, who *can* we trust? ;) ).
>
> Consider the following patch, which I've done by basically using your
> code, changing the root-detection logic a little as described in my
> previous mail, condensing and moving to memcached.c. It adds about
> 15 lines of code, defines no new constants or functions, and, I think,
> gets the job done (note that in case the program isn't run as root,
> the -u switch is ignored, which is documented in -h, and seems to be
> adequate).
>
> Note: I've only tested it on Linux, someone should test on a BSD.
>
> main -> wcmtools          src/memcached/memcached.c
> --- cvs/wcmtools/memcached/memcached.c	Fri Sep  5 11:37:49 2003
> +++ src/memcached/memcached.c	Sat Sep  6 14:04:03 2003
> @@ -28,6 +28,7 @@
>  #ifndef _P1003_1B_VISIBLE
>  #define _P1003_1B_VISIBLE
>  #endif
> +#include <pwd.h>
>  #include <sys/mman.h>
>  #include <fcntl.h>
>  #include <stdlib.h>
> @@ -1161,6 +1162,7 @@
>      printf("-p <num>      port number to listen on\n");
>      printf("-l <ip_addr>  interface to listen on, default is INDRR_ANY\n");
>      printf("-d            run as a daemon\n");
> +    printf("-u <username> assume identity of <username> (only when run as root)\n");
>      printf("-m <num>      max memory to use for items in megabytes, default is 64 MB\n");
>      printf("-c <num>      max simultaneous connections, default is 1024\n");
>      printf("-k            lock down all paged memory\n");
> @@ -1250,12 +1252,14 @@
>      struct in_addr addr;
>      int lock_memory = 0;
>      int daemonize = 0;
> +    char *username = 0;
> +    struct passwd *pw;
>
>      /* init settings */
>      settings_init();
>
>      /* process arguments */
> -    while ((c = getopt(argc, argv, "p:m:c:khivdl:")) != -1) {
> +    while ((c = getopt(argc, argv, "p:m:c:khivdl:u:")) != -1) {
>          switch (c) {
>          case 'p':
>              settings.port = atoi(optarg);
> @@ -1289,6 +1293,9 @@
>          case 'd':
>              daemonize = 1;
>              break;
> +        case 'u':
> +            username = optarg;
> +            break;
>          default:
>              fprintf(stderr, "Illegal argument \"%c\"\n", c);
>              return 1;
> @@ -1310,6 +1317,22 @@
>  #else
>          fprintf(stderr, "warning: mlockall() not supported on this platform.  proceeding without.\n");
>  #endif
> +    }
> +
> +    /* lose root privileges if we have them */
> +    if (getuid()== 0 || geteuid()==0) {
> +        if (username==0 || *username=='\0') {
> +            fprintf(stderr, "can't run as root without the -u switch\n");
> +            return 1;
> +        }
> +        if ((pw = getpwnam(username)) == 0) {
> +            fprintf(stderr, "can't find the user %s to switch to\n", username);
> +            return 1;
> +        }
> +        if (setgid(pw->pw_gid)<0 || setuid(pw->pw_uid)<0) {
> +            fprintf(stderr, "failed to assume identity of user %s\n", username);
> +            return 1;
> +        }
>      }
>
>      if (daemonize) {
>
>