[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