[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [BusyBox] Patch for extended SUID managment
From:       Robert Griebl <griebl () gmx ! de>
Date:       2002-05-23 15:53:05
[Download RAW message or body]

I habe discussed my first approach to tinylogin integration with vodz and 
this patch is the result (of which we both think it is a nice solution =) )

The approach is similiar to current tinylogin SUID managment - add a field to 
each BB_applet, specifing if this applet requires SUID, doesn't care if it is 
run SUID or does not want to be run SUID (ALWAYS, MAYBE, NEVER)

Additionally you can enabled CONFIG_FEATURE_SUID_CONFIG. This enabled runtime 
configuration via /etc/busybox.conf. This file is parsed like a INI file. 
Currently only the section [SUID] is recognized. In this section you can 
entries to override the compiled in SUID behaviour like:
<applet>[ ]*=[ ]*(n|m|a[ ]+[euid][ ]+[egid])

Examples:
-->8------------------------------8<--
[SUID]
# comment
su=a 0 0  # su now requires SUID and tries to set euid/egid to root/root
ping=m    # ping does not really care, but also does not drop priv.
ash=a 500 # ash now runs as user with uid==500 even when bb binary 
            is SUID root
mount=n   # mount now always drops all priviledges, regardless of compile     
            time config

[This]
# is ignored
-->8------------------------------8<--

So IMHO for small embedded systems, the compile time options will suffice. 
For more sophisticated usage you can activate the CONFIG and set everything 
in /etc/busybox.conf

Comments anybody :) ??

-- 
cu
Robert

--
Real programmers dont write documentation -
leave that to the maintenance people.

["suid.patch2" (text/x-diff)]

Index: applets/applets.c
===================================================================
RCS file: /var/cvs/busybox/applets/applets.c,v
retrieving revision 1.9
diff -u -3 -p -r1.9 applets.c
--- applets/applets.c	27 Aug 2001 17:19:38 -0000	1.9
+++ applets/applets.c	23 May 2002 21:49:26 -0000
@@ -25,11 +25,15 @@
  *
  */
 
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "busybox.h"
 
+#define CONFIG_FEATURE_SUID_CONFIG	1
+
+
 #undef APPLET
 #undef APPLET_NOUSAGE
 #undef PROTOTYPES
@@ -40,6 +44,35 @@ struct BB_applet *applet_using;
 /* The -1 arises because of the {0,NULL,0,-1} entry above. */
 const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
 
+#ifdef CONFIG_FEATURE_SUID_CONFIG
+
+#include <sys/stat.h>
+#include <ctype.h>
+
+void parse_error ( int line, const char *err );
+void parse_config_file ( void );
+
+#define CONFIG_FILE "/etc/busybox.conf"
+
+// applets [] is const, so we have to define this "override" structure
+typedef struct suid_config_ {
+	struct BB_applet *m_applet;
+
+	uid_t m_euid;
+	gid_t m_egid;
+	
+	int m_need_suid : 4;
+	int m_set_euid  : 1;
+	int m_set_egid  : 1;
+	
+	struct suid_config_ *m_next;
+} suid_config_t;
+
+static suid_config_t *suid_config;
+
+#endif
+
+
 extern void show_usage(void)
 {
 	const char *format_string;
@@ -80,6 +113,11 @@ void run_applet_by_name(const char *name
 	static int recurse_level = 0;
 	extern int been_there_done_that; /* From busybox.c */
 
+#ifdef CONFIG_FEATURE_SUID_CONFIG
+	if ( recurse_level == 0 )
+		parse_config_file ( );
+#endif
+
 	recurse_level++;
 	/* Do a binary search to find the applet entry given the name. */
 	if ((applet_using = find_applet_by_name(name)) != NULL) {
@@ -96,6 +134,43 @@ void run_applet_by_name(const char *name
 			been_there_done_that=1;
 			busybox_main(0, NULL);
 		}
+
+		{
+#ifdef CONFIG_FEATURE_SUID_CONFIG
+			suid_config_t *sct;
+			int suidflags;
+			
+			for ( sct = suid_config; sct; sct = sct-> m_next ) {
+				if ( sct-> m_applet == applet_using )
+					break;
+			}
+			
+			suidflags = sct ? sct-> m_need_suid : applet_using-> need_suid;
+#else
+			int suidflags = applet_using-> need_suid;
+#endif
+
+			if ( suidflags == _BB_SUID_ALWAYS ) {
+#ifdef CONFIG_FEATURE_SUID_CONFIG 
+				if ( sct && sct-> m_set_euid ) {
+					if ( sct-> m_set_egid ) {
+						if ( setegid ( sct-> m_egid ))
+							error_msg_and_die ( "This applet failed to do the necessary SGID" );
+					}
+					if ( seteuid ( sct-> m_euid ))
+						error_msg_and_die ( "This applet failed to do the necessary SUID" );
+				} else 
+#endif
+				if ( geteuid ( ) != 0 ) 
+					error_msg_and_die("This applet requires root priviledges!\n");
+			} 
+			else if ( suidflags == _BB_SUID_NEVER ) {
+				setuid ( getuid ( )); // drop all priviledges
+				setgid ( getgid ( ));
+			}		
+		}
+
+			
 		exit((*(applet_using->main)) (argc, argv));
 	}
 	/* Just in case they have renamed busybox - Check argv[1] */
@@ -105,6 +180,118 @@ void run_applet_by_name(const char *name
 	recurse_level--;
 }
 
+#ifdef CONFIG_FEATURE_SUID_CONFIG
+
+void parse_error ( int line, const char *err )
+{
+	char msg [512];
+	snprintf ( msg, sizeof( msg ) - 1, "Parse error in %s, line %d: %s", CONFIG_FILE, line, err );
+
+	error_msg_and_die ( msg );
+}
+
+
+void parse_config_file ( void )
+{
+	struct stat st;
+
+	suid_config = 0;
+	
+	// is there a config file ?
+	if ( stat ( CONFIG_FILE, &st ) == 0 ) {
+		// is it owned by root with no write perm. for group and others ?
+		if ( S_ISREG( st. st_mode ) && ( st. st_uid == 0 )	&& (!( st. st_mode & ( S_IWGRP | S_IWOTH )))) {
+			// that's ok .. then try to open it
+			FILE *f = fopen ( CONFIG_FILE, "r" );
+
+			if ( f ) {
+				char buffer [4096];
+				int section = 0;
+				int lc = 0;
+				
+				while ( fgets ( buffer, sizeof( buffer ) - 1, f )) {
+					char c = buffer [0];
+				
+					lc++;
+					
+					if ( !c || ( c == '#' ) || ( c == '\'' ) || isspace ( c )) // comment
+						continue;
+				
+					if ( c == '[' ) {
+						char *end = strchr ( buffer, ']' );
+						
+						if ( !end || ( end == ( buffer + 1 )))  // no matching ] or empty []
+							parse_error ( lc, "malformed section header" );
+
+						*end = 0;
+						
+						if ( strcasecmp ( buffer + 1, "SUID" ) == 0 )
+							section = 1;
+						else
+							section = -1; // unknown section - just skip
+					}
+					else if ( section ) {
+						switch ( section ) {
+							case 1: { // SUID
+								char *eq = strchr ( buffer, '=' ); // <key>[::space::]*=[::space::]*<value>
+								int l;
+								struct BB_applet *applet;
+								
+								if ( !eq || ( eq == ( buffer + 1 ))) // no = or key is empty
+									parse_error ( lc, "malformed keyword" );
+								
+								l = eq - buffer;
+								while ( isspace ( buffer [--l] )) { } // skip whitespace
+								
+								buffer [l+1] = 0;
+								
+								if (( applet = find_applet_by_name ( buffer ))) {
+									int newsuid = applet-> need_suid;
+									int euid, egid;
+									int set_euid = 0, set_egid = 0;
+								
+									while ( isspace ( *++eq )) { } // skip whitespace
+																		
+									switch ( *eq ) {
+										case 'a': 
+											newsuid = _BB_SUID_ALWAYS; 
+											switch ( sscanf ( eq + 1, " %i %i", &euid, &egid )) {
+												case 2: set_egid = 1; // fall trough
+												case 1: set_euid = 1;
+											}
+											break;
+										case 'n': newsuid = _BB_SUID_NEVER; break;
+										case 'm': newsuid = _BB_SUID_MAYBE; break;
+										default : parse_error ( lc, "malformed value for key" );
+									}
+									if ( newsuid != applet-> need_suid ) {
+										suid_config_t *sct = xmalloc ( sizeof( suid_config_t ));
+										sct-> m_applet = applet;
+										sct-> m_need_suid = newsuid;
+										sct-> m_set_euid = set_euid;
+										sct-> m_set_egid = set_euid;
+										sct-> m_euid = euid;
+										sct-> m_egid = egid;
+										sct-> m_next = suid_config;
+										suid_config = sct;
+									}									
+								}
+								break;
+							}
+							default: // unknown - skip
+								break;
+						}					
+					}
+					else
+						parse_error ( lc, "keyword not within section" );
+				}				
+				fclose ( f );
+			}
+		}
+	}
+}
+
+#endif
 
 /* END CODE */
 /*
Index: include/busybox.h
===================================================================
RCS file: /var/cvs/busybox/include/busybox.h,v
retrieving revision 1.49
diff -u -3 -p -r1.49 busybox.h
--- include/busybox.h	16 Mar 2002 02:12:30 -0000	1.49
+++ include/busybox.h	23 May 2002 21:49:26 -0000
@@ -48,10 +48,17 @@ enum Location {
 	_BB_DIR_USR_SBIN
 };
 
+enum SUIDRoot {
+	_BB_SUID_NEVER = 0,
+	_BB_SUID_MAYBE,
+	_BB_SUID_ALWAYS
+};
+
 struct BB_applet {
 	const	char*	name;
 	int	(*main)(int argc, char** argv);
-	enum	Location	location;
+	enum	Location	location  : 4;
+	enum 	SUIDRoot	need_suid : 4;
 };
 /* From busybox.c */
 extern const struct BB_applet applets[];


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic