setuid patch

Lisa Seelye lisa@gentoo.org
Fri, 05 Sep 2003 18:13:29 -0400


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

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


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

--=-AH64vj0YabYs1WcjVtjM
Content-Disposition: attachment; filename=setuid.patch
Content-Type: text/x-patch; name=setuid.patch; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

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-09-05 16:19:49.000000000 -0400
@@ -1,9 +1,8 @@
 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 errors.h
 
 DIST_SUBDIRS = doc
 EXTRA_DIST = doc TODO
 
 AM_CFLAGS=-DNDEBUG
-
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-09-05 16:19:17.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
Common subdirectories: cvs/frontends and cvs-diff/frontends
diff -uN cvs/memcached.c cvs-diff/memcached.c
--- cvs/memcached.c	2003-09-05 16:11:53.000000000 -0400
+++ cvs-diff/memcached.c	2003-09-05 16:53:56.000000000 -0400
@@ -47,6 +47,7 @@
 #endif
 
 #include "memcached.h"
+#include "errors.h" // setuid errors live within
 
 struct stats stats;
 struct settings settings;
@@ -1250,13 +1251,16 @@
     struct in_addr addr;
     int lock_memory = 0;
     int daemonize = 0;
-
+	char *username = "";
     /* init settings */
     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;
@@ -1339,9 +1343,13 @@
     todelete = malloc(sizeof(item *)*deltotal);
     delete_handler(0,0,0); /* sets up the event */
 
+	if (switch_user(username)) {
+		fprintf(stderr,"Failed to setuid %s\n",username);
+		exit(MCD_ERROR_SETUID);
+	}
+
     /* enter the loop */
-    event_loop(0);
+	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-09-05 16:19:17.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

--=-AH64vj0YabYs1WcjVtjM--