Memcached TODO list?

Lisa Marie Seelye lisa@gentoo.org
Fri, 29 Aug 2003 00:16:18 -0400


--=-nCdao2ZCRaW7NKj58fmr
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

On Thu, 2003-08-28 at 05:12, Anatoly Vorobey wrote:
> - have a command-line switch "-u user" meaning "assume identity of user  
>   when run as root"
> - refuse to run as root unless the switch is given.


To this end, here is a revised patch.
If it fails to be presented in a text/plain format, it can be found at
http://dev.gentoo.org/~lisa/memcached/setuid1.patch (note the '1')

How is this?  It passes my local tests.  Not sure if I got the logic
down right... check the comments in the setuid.c file for how I
interpreted it.

-- 
Regards,
-Lisa
<Vix ulla tam iniqua pax, quin bello vel aequissimo sit potior>

--=-nCdao2ZCRaW7NKj58fmr
Content-Disposition: attachment; filename=setuid1.patch
Content-Type: text/x-patch; name=setuid1.patch; charset=iso-8859-1
Content-Transfer-Encoding: 7bit

Common subdirectories: cvs/.deps and cvs-diff/.deps
Common subdirectories: cvs/CVS and cvs-diff/CVS
diff -uN cvs/Makefile.am cvs-diff/Makefile.am
--- cvs/Makefile.am	2003-08-27 14:52:29.000000000 -0400
+++ cvs-diff/Makefile.am	2003-08-27 13:48:31.000000000 -0400
@@ -1,6 +1,6 @@
 bin_PROGRAMS = memcached
 
-memcached_SOURCES = memcached.c slabs.c items.c memcached.h assoc.c
+memcached_SOURCES = memcached.c slabs.c items.c memcached.h assoc.c setuid.c setuid.h errors.h
 
 DIST_SUBDIRS = doc
 EXTRA_DIST = doc TODO
Common subdirectories: cvs/api and cvs-diff/api
Common subdirectories: cvs/doc and cvs-diff/doc
diff -uN cvs/errors.h cvs-diff/errors.h
--- cvs/errors.h	1969-12-31 19:00:00.000000000 -0500
+++ cvs-diff/errors.h	2003-08-28 15:41:23.000000000 -0400
@@ -0,0 +1,10 @@
+/***************************************************************************
+ *            errors.h
+ *
+ *  Wed Aug 27 14:01:16 2003
+ *  Lisa Seelye <lisa@gentoo.org>, for memcached
+ ****************************************************************************/
+
+#define MCD_ERROR_SETUID 100
+#define MCD_RUNNING_AS_ROOT 90
+#define MCD_NO_SPECIFIED_USERNAME 91
diff -uN cvs/memcached.c cvs-diff/memcached.c
--- cvs/memcached.c	2003-08-27 14:52:30.000000000 -0400
+++ cvs-diff/memcached.c	2003-08-29 00:10:59.000000000 -0400
@@ -47,6 +47,7 @@
 #endif
 
 #include "memcached.h"
+#include "errors.h" //setuid error codes live within
 
 struct stats stats;
 struct settings settings;
@@ -1249,13 +1250,18 @@
     struct in_addr addr;
     int lock_memory = 0;
     int daemonize = 0;
+	int setuid_error = 0;
+	char *username = "";
 
     /* init settings */
-    settings_init();
+	settings_init();
 
     /* process arguments */
-    while ((c = getopt(argc, argv, "p:m:c:khivdl:")) != -1) {
+    while ((c = getopt(argc, argv, "u:p:m:c:khivdl:")) != -1) {
         switch (c) {
+		case 'u':
+			username = optarg;
+			break;
         case 'p':
             settings.port = atoi(optarg);
             break;
@@ -1338,9 +1344,18 @@
     todelete = malloc(sizeof(item *)*deltotal);
     delete_handler(0,0,0); /* sets up the event */
 
+	/* I think here would be a good place to discard (or attempt to) our 
+	 * priveledges.
+	*/
+
+	setuid_error = switch_user(username);
+	if (setuid_error) {
+		fprintf(stderr,"Failed to setuid %s\n",username);
+		exit(MCD_ERROR_SETUID);
+	}
+
     /* enter the loop */
     event_loop(0);
 
     return 0;
 }
-
diff -uN cvs/setuid.c cvs-diff/setuid.c
--- cvs/setuid.c	1969-12-31 19:00:00.000000000 -0500
+++ cvs-diff/setuid.c	2003-08-29 00:08:33.000000000 -0400
@@ -0,0 +1,105 @@
+/***************************************************************************
+ *            setuid.c
+ *
+ *  Wed Aug 27 13:59:36 2003
+ *  Lisa Seelye <lisa@gentoo.org>, for memcached
+ ****************************************************************************/
+
+#include <stdio.h> 
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <ctype.h>
+
+#include "errors.h" //setuid errors live within
+
+int switch_user(char *username);
+static int get_id(char *username, uid_t *uid, gid_t *gid);
+int is_superuser(void);
+
+int is_superuser(void) { 
+	/* quickie to see if we're the superuser or not */
+	return ( (getuid() == 0 && getgid() == 0) ); 
+}
+
+static int get_id(char *username, uid_t *uid, gid_t *gid) {
+	/* Set uid and gid to the preferred user (found in setuid.h). Can either be
+	 * numeric or a string, found in /etc/passwd.
+	*/
+	struct passwd *pw;
+
+	if ((pw = getpwnam(username))) {
+		// Name exists
+		*uid = pw->pw_uid;
+		*gid = pw->pw_gid;
+		return 0;
+	}
+	/* something Bad happened, so send back an error */
+	return MCD_ERROR_SETUID;	
+}
+
+int switch_user(char *username) {
+	/* Set uid and gid to the username specified in the function parameters.
+	 *
+	 * If the user starts memcached as root and fails to specify a username to 
+	 * switch to (`-u username'), we will return MCD_NO_SPECIFIED_USERNAME
+	 * 
+	 * If memcached is started by a non-root user, we will attempt to switch to
+	 * the username specified (`-u username'), and issue an error if we can't
+	 * MCD_ERROR_SETUID.
+	 * 
+	 * If the root user starts memcached and specifies `-u root' we will let
+	 * them run as root.
+	*/
+
+	uid_t uid; gid_t gid;
+	
+
+	if (is_superuser()) {
+		// we are root
+		if (strcmp(username,"") == 0) {
+			// username isnt set and we're running as root. let's get outta here
+			fprintf(stderr,"No username specified with -u option!\n");
+			exit(MCD_NO_SPECIFIED_USERNAME);
+		}
+		else {
+			// We're root, but the user gave us a username to switch too.
+			int retval;
+			retval = get_id(username,&uid,&gid);
+			if (retval) {
+				//fprintf(stderr,"An error occurred while trying to setuid\nExiting...\n");
+				return retval;
+			} // Error in getting uid/gid.
+		} // we're okay for the setuid/setgid command Down Below
+	}
+	else {
+		//we are not root
+		if (strcmp(username,"") == 0) {
+			//no username, so we'll just run as $USER
+			return 0;
+		}
+		else {
+			/* Here we really have an option to let the user continue running as
+			 * themselves, or to quit outright.  I've decided to exit.
+			*/
+			int retval;
+			retval = get_id(username,&uid,&gid);
+			if (retval) {
+				//fprintf(stderr,"An error occurred while trying to setuid\nExiting...\n");
+				return retval;
+			} // Error in getting uid/gid.
+		}
+	}
+	if (setgid(gid)) 
+		return MCD_ERROR_SETUID;
+	if (setuid(uid))
+		return MCD_ERROR_SETUID;
+
+	if ((getuid() == 0 || getgid() == 0) && strcmp(username,"root") != 0) {
+		/* We're still root, and we shouldn't be! */
+		return MCD_ERROR_SETUID;
+	}
+	return 0;
+}
Common subdirectories: cvs/website and cvs-diff/website

--=-nCdao2ZCRaW7NKj58fmr--