#define _GNU_SOURCE #include #include #include #include #include #include #include #include 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 ); }