diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | main.cc | 131 | ||||
-rw-r--r-- | overrides | 1 | ||||
-rw-r--r-- | permissions | 1 |
4 files changed, 126 insertions, 11 deletions
@@ -1,10 +1,10 @@ default: insecuresuexec insecuresuexec-noisy insecuresuexec: main.cc - clang++ -Wall -Werror -std=c++11 -Os -o $@ $+ + g++ -Wall -Werror -std=c++11 -Os -o $@ $+ insecuresuexec-noisy: main.cc - clang++ -Wall -Werror -std=c++11 -Os -o $@ -DNOISY $+ + g++ -Wall -Werror -std=c++11 -Os -o $@ -DNOISY $+ clean: rm -f insecuresuexec insecuresuexec-noisy @@ -2,6 +2,7 @@ #include <errno.h> #include <grp.h> #include <pwd.h> +#include <regex> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -76,6 +77,7 @@ public: , max_gid( gids.second ) { + DEBUG( "insecuresuexec permission( %u-%u, %u-%u )\n", min_uid, max_uid, min_gid, max_gid ); } @@ -85,6 +87,31 @@ public: }; +class override { + + std::regex constraint; + +public: + + uid_t uid; + gid_t gid; + + override( uid_t _uid, gid_t _gid, const char *ex ) + : constraint( ex, std::regex_constants::basic ) + , uid( _uid ) + , gid( _gid ) + { + + DEBUG( "insecuresuexec override( %u, %u, %s )\n", _uid, _gid, ex ); + + } + + const bool match( const char *str ) { + return regex_match( str, constraint, std::regex_constants::match_continuous ); + } + +}; + 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 ); @@ -130,7 +157,7 @@ template< typename thing > std::pair< thing, thing > parse_pair( const char *lin } -permission parse_line( const char *line ) { +permission parse_permission_line( const char *line ) { size_t line_len = strcspn( line, "\n" ); assert( line_len > 0 ); @@ -155,6 +182,38 @@ permission parse_line( const char *line ) { } +override parse_override_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 = strcspn( line + user_len + 1, " " ); + assert( group_len != line_len - user_len - 1 ); + + size_t ex_len = line_len - user_len - 1 - group_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; + + char ex[ex_len + 1]; + strncpy( ex, line + user_len + 1 + group_len + 1, ex_len ); + ex[ex_len] = 0; + + uid_t uid_part = parse_user( user ); + gid_t gid_part = parse_group( group ); + + return override( uid_part, gid_part, ex ); + +} + std::vector< permission > * read_permissions( const char *file ) { FILE *fh = fopen( file, "r" ); @@ -170,7 +229,34 @@ std::vector< permission > * read_permissions( const char *file ) { size_t line_len = strcspn( line, "\n" ); if ( line_len ) { - ret->push_back( parse_line( line ) ); + ret->push_back( parse_permission_line( line ) ); + }; + + }; + + if ( line ) + free( line ); + + return ret; + +} + +std::vector< override > * read_overrides( const char *file ) { + + FILE *fh = fopen( file, "r" ); + if ( not fh ) + assert_perror( errno ); + + auto *ret = new std::vector< override >( ); + + 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_override_line( line ) ); }; }; @@ -184,6 +270,14 @@ std::vector< permission > * read_permissions( const char *file ) { int main( int argc, char *argv[] ) { + DEBUG( "insecuresuexec is parsing the stored permissions...\n" ); + + auto allowed = read_permissions( "/etc/insecuresuexec/permissions" ); + + DEBUG( "insecuresuexec is parsing the stored overrides...\n" ); + + auto override = read_overrides( "/etc/insecuresuexec/overrides" ); + if ( argc < 4 ) { fprintf( stderr, "Usage: %s user group cmd [args..]\n", argv[0] ); return 1; @@ -199,10 +293,33 @@ int main( int argc, char *argv[] ) { uid_t uid; gid_t gid; - DEBUG( "insecuresuexec is parsing the command-line user and group...\n" ); + DEBUG( "insecuresuexec is checking the overrides...\n" ); + + bool did_override = false; + for ( auto i = override->begin( ); i != override->end( ); ++i ) { + if ( i->match( cmd ) ) { - uid = parse_user( user ); - gid = parse_group( group ); + DEBUG( " cmd matched, now uid=%u gid=%u\n", i->uid, i->gid ); + + uid = i->uid; + gid = i->gid; + + did_override = true; + + break; + }; + }; + + if ( ! did_override ) { + + DEBUG( " no matching override found\n" ); + + DEBUG( "insecuresuexec is parsing the command-line user and group...\n" ); + + uid = parse_user( user ); + gid = parse_group( group ); + + }; // literally the only hard-coded security check if ( not uid || not gid ) { @@ -210,10 +327,6 @@ int main( int argc, char *argv[] ) { _exit( 1 ); }; - DEBUG( "insecuresuexec is parsing the stored permissions...\n" ); - - auto allowed = read_permissions( "/etc/insecuresuexec/permissions" ); - DEBUG( "insecuresuexec is running the configured security checks...\n" ); // the configurable security checks diff --git a/overrides b/overrides new file mode 100644 index 0000000..abf3d53 --- /dev/null +++ b/overrides @@ -0,0 +1 @@ +www-data:www-data .*/id diff --git a/permissions b/permissions new file mode 100644 index 0000000..b229b80 --- /dev/null +++ b/permissions @@ -0,0 +1 @@ +www-data:www-data |