summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Blake Kongslie <jblake@omgwallhack.org>2012-11-07 11:40:57 -0800
committerJulian Blake Kongslie <jblake@omgwallhack.org>2012-11-07 11:40:57 -0800
commit6d8606941c7bbdb72c76c81fef8eb91232ffc918 (patch)
treee4c9046aa399c437b709090d977f52bcfcc8fa21
parentefeb94cdab68ecb81cae8b0bba816a6ee55207c2 (diff)
downloadinsecuresuexec-6d8606941c7bbdb72c76c81fef8eb91232ffc918.tar.gz
insecuresuexec-6d8606941c7bbdb72c76c81fef8eb91232ffc918.zip
Joe wanted it configurable. Laaame.
-rw-r--r--Makefile4
-rw-r--r--main.c62
-rw-r--r--main.cc214
3 files changed, 216 insertions, 64 deletions
diff --git a/Makefile b/Makefile
index 43d9995..30df8d4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-insecuresuexec: main.c
- clang -Wall -Werror -Os -o $@ $+
+insecuresuexec: main.cc
+ clang++ -Wall -Werror -std=c++11 -Os -g -o $@ $+
clean:
rm -f insecuresuexec
diff --git a/main.c b/main.c
deleted file mode 100644
index 8d07953..0000000
--- a/main.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#define _GNU_SOURCE
-
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-int main( int argc, char *argv[] ) {
-
- if ( argc < 4 ) {
- fprintf( stderr, "Usage: %s user group cmd [args..]\n", argv[0] );
- return 1;
- };
-
- char *user = argv[1];
- char *group = argv[2];
- char *cmd = argv[3];
- char **args = argv + 3;
-
- char *end;
- unsigned long tmp;
-
- struct passwd *userpw;
- struct group *grouppw;
-
- tmp = strtoul( user, &end, 10 );
- if ( end != user && ! *end ) {
- userpw = getpwuid( tmp );
- } else {
- userpw = getpwnam( user );
- };
- assert( userpw != NULL );
-
- tmp = strtoul( group, &end, 10 );
- if ( end != user && ! *end ) {
- grouppw = getgrgid( tmp );
- } else {
- grouppw = getgrnam( group );
- };
- assert( grouppw != NULL );
-
- // literally the only security check
- assert( grouppw->gr_gid != 0 );
- assert( userpw->pw_uid != 0 );
-
- if ( setgroups( 0, NULL ) != 0 )
- assert_perror( errno );
-
- if ( setregid( grouppw->gr_gid, grouppw->gr_gid ) != 0 )
- assert_perror( errno );
-
- if ( setreuid( userpw->pw_uid, userpw->pw_uid ) != 0 )
- assert_perror( errno );
-
- execv( cmd, args );
- assert_perror( errno );
-
-}
diff --git a/main.cc b/main.cc
new file mode 100644
index 0000000..27c7806
--- /dev/null
+++ b/main.cc
@@ -0,0 +1,214 @@
+#include <assert.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+uid_t parse_user( const char *user ) {
+
+ char *end;
+ unsigned long tmp;
+
+ tmp = strtoul( user, &end, 10 );
+ if ( end != user && ! *end ) {
+ return tmp;
+ } else {
+ struct passwd *pw = getpwnam( user );
+ assert( pw );
+ return pw->pw_uid;
+ };
+
+}
+
+gid_t parse_group( const char *group ) {
+
+ char *end;
+ unsigned long tmp;
+
+ tmp = strtoul( group, &end, 10 );
+ if ( end != group && ! *end ) {
+ return tmp;
+ } else {
+ struct group *gr = getgrnam( group );
+ assert( gr );
+ return gr->gr_gid;
+ };
+
+}
+
+class permission {
+
+ uid_t min_uid, max_uid;
+ gid_t min_gid, max_gid;
+
+public:
+
+ permission( std::pair< uid_t, uid_t > uids, std::pair< gid_t, gid_t > gids )
+ : min_uid( uids.first )
+ , max_uid( uids.second )
+ , min_gid( gids.first )
+ , max_gid( gids.second )
+ {
+
+
+ }
+
+ const bool allows( uid_t uid, gid_t gid ) {
+ return uid >= min_uid && uid <= max_uid && gid >= min_gid && gid <= max_gid;
+ }
+
+};
+
+template< typename thing > std::pair< thing, thing > parse_pair( const char *line, thing (*parse_one)( const char *part ) ) {
+
+ std::pair< thing, thing > ret( 0, -1 );
+
+ size_t part_len = strlen( line );
+ assert( part_len > 0 );
+
+ char part[part_len + 1];
+ strncpy( part, line, part_len );
+ part[part_len] = 0;
+
+ size_t comma = strcspn( line, "," );
+
+ if ( comma == part_len ) {
+
+ thing it = parse_one( part );
+
+ ret.first = it;
+ ret.second = it;
+
+ } else {
+
+ size_t first_len = comma;
+ size_t second_len = part_len - comma - 1;
+
+ char first[first_len + 1];
+ strncpy( first, part, first_len );
+ first[first_len] = 0;
+
+ char second[second_len + 1];
+ strncpy( second, part + comma + 1, second_len );
+ second[second_len] = 0;
+
+ if ( first_len )
+ ret.first = parse_one( first );
+
+ if ( second_len )
+ ret.second = parse_one( second );
+
+ };
+
+ return ret;
+
+}
+
+permission parse_line( const char *line ) {
+
+ size_t line_len = strcspn( line, "\n" );
+ assert( line_len > 0 );
+
+ size_t user_len = strcspn( line, ":" );
+ assert( user_len != line_len );
+
+ size_t group_len = line_len - user_len - 1;
+
+ char user[user_len + 1];
+ strncpy( user, line, user_len );
+ user[user_len] = 0;
+
+ char group[group_len + 1];
+ strncpy( group, line + user_len + 1, group_len );
+ group[group_len] = 0;
+
+ auto uid_part = parse_pair< uid_t >( user, parse_user );
+ auto gid_part = parse_pair< gid_t >( group, parse_group );
+
+ return permission( uid_part, gid_part );
+
+}
+
+std::vector< permission > * read_permissions( const char *file ) {
+
+ FILE *fh = fopen( file, "r" );
+ if ( not fh )
+ assert_perror( errno );
+
+ auto *ret = new std::vector< permission >( );
+
+ char *line = 0;
+ size_t size = 0;
+
+ for ( ; getline( &line, &size, fh ) != -1; ) {
+
+ size_t line_len = strcspn( line, "\n" );
+ if ( line_len ) {
+ ret->push_back( parse_line( line ) );
+ };
+
+ };
+
+ if ( line )
+ free( line );
+
+ return ret;
+
+}
+
+int main( int argc, char *argv[] ) {
+
+ if ( argc < 4 ) {
+ fprintf( stderr, "Usage: %s user group cmd [args..]\n", argv[0] );
+ return 1;
+ };
+
+ char *user = argv[1];
+ char *group = argv[2];
+ char *cmd = argv[3];
+ char **args = argv + 3;
+
+ uid_t uid;
+ gid_t gid;
+
+ uid = parse_user( user );
+ gid = parse_group( group );
+
+ // literally the only hard-coded security check
+ if ( not uid || not gid ) {
+ fprintf( stderr, "Neither uid nor gid may be zero!\n" );
+ _exit( 1 );
+ };
+
+ auto allowed = read_permissions( "/etc/insecuresuexec/permissions" );
+
+ // the configurable security checks
+ bool ok = false;
+ for ( auto i = allowed->begin( ); i != allowed->end( ); ++i ) {
+ ok |= i->allows( uid, gid );
+ if ( ok ) break;
+ };
+ if ( not ok ) {
+ fprintf( stderr, "The uid/gid pair %u/%u is not allowed!\n", uid, gid );
+ _exit( 1 );
+ };
+
+ if ( setgroups( 0, NULL ) != 0 )
+ assert_perror( errno );
+
+ if ( setregid( gid, gid ) != 0 )
+ assert_perror( errno );
+
+ if ( setreuid( uid, uid ) != 0 )
+ assert_perror( errno );
+
+ execv( cmd, args );
+ assert_perror( errno );
+
+}