diff options
author | Julian Blake Kongslie <jblake@omgwallhack.org> | 2010-12-27 13:49:05 -0800 |
---|---|---|
committer | Julian Blake Kongslie <jblake@omgwallhack.org> | 2010-12-27 13:49:05 -0800 |
commit | 88b8f280e996c5b0d04d306dd0f0e09806a6547e (patch) | |
tree | 8957f317597a5bd986a9eba089e90b1df1d7495d /pinyweb/suid/piny-suid.c | |
parent | 8f342b641236d9c15530664c00889d00635b61f6 (diff) | |
download | piny-code-88b8f280e996c5b0d04d306dd0f0e09806a6547e.tar.gz piny-code-88b8f280e996c5b0d04d306dd0f0e09806a6547e.zip |
Adding setuid wrapper.
Diffstat (limited to 'pinyweb/suid/piny-suid.c')
-rw-r--r-- | pinyweb/suid/piny-suid.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/pinyweb/suid/piny-suid.c b/pinyweb/suid/piny-suid.c new file mode 100644 index 0000000..251e3e1 --- /dev/null +++ b/pinyweb/suid/piny-suid.c @@ -0,0 +1,121 @@ +#include <errno.h> +#include <pwd.h> +#include <regex.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <syslog.h> +#include <unistd.h> + +int main( int argc, char *argv[] ) { + + int err; + + openlog( "piny-suid", LOG_ODELAY, LOG_AUTHPRIV ); + + if ( argc < 3 ) { + syslog( LOG_ERR, "Invalid usage" ); + fprintf( stderr, "Usage: %s username command [args ...]\n", argv[0] ); + return 1; + }; + + regex_t user_reg; + + // Please note that these regular expressions should duplicate the language for usernames described in Piny::User. + if ( ( err = regcomp( &user_reg, "^[a-zA-Z][a-zA-Z0-9_.-]*$", REG_EXTENDED | REG_NOSUB ) ) != 0 ) { + size_t sz = regerror( err, &user_reg, NULL, 0 ); + char buf[sz]; + regerror( err, &user_reg, buf, sz ); + syslog( LOG_CRIT, "Internal error; first regex, %s", buf ); + fprintf( stderr, "Internal error compiling first regular expression: %s\n", buf ); + return 1; + }; + + if ( regexec( &user_reg, argv[1], 0, NULL, 0 ) ) { + syslog( LOG_ERR, "Invalid username '%s' (first regex)", argv[1] ); + fprintf( stderr, "'%s' does not appear to be a valid username!\n", argv[1] ); + return 1; + }; + + regfree( &user_reg ); + + if ( ( err = regcomp( &user_reg, "^(git|ikiwiki)-", REG_EXTENDED | REG_NOSUB ) ) != 0 ) { + size_t sz = regerror( err, &user_reg, NULL, 0 ); + char buf[sz]; + regerror( err, &user_reg, buf, sz ); + syslog( LOG_CRIT, "Internal error: second regex, %s", buf ); + fprintf( stderr, "Internal error compiling second regular expression: %s\n", buf ); + return 1; + }; + + if ( ! regexec( &user_reg, argv[1], 0, NULL, 0 ) ) { + syslog( LOG_ERR, "Invalid username '%s' (second regex)", argv[1] ); + fprintf( stderr, "'%s' does not appear to be a valid username!\n", argv[1] ); + return 1; + }; + + regfree( &user_reg ); + + regex_t cmd_reg; + + if ( ( err = regcomp( &cmd_reg, "/", REG_EXTENDED | REG_NOSUB ) ) != 0 ) { + size_t sz = regerror( err, &cmd_reg, NULL, 0 ); + char buf[sz]; + regerror( err, &cmd_reg, buf, sz ); + syslog( LOG_CRIT, "Internal error: third regex, %s", buf ); + fprintf( stderr, "Internal error compiling third regular expression: %s\n", buf ); + return 1; + }; + + if ( ! regexec( &cmd_reg, argv[2], 0, NULL, 0 ) ) { + syslog( LOG_ERR, "Invalid command '%s' (third regex)", argv[2] ); + fprintf( stderr, "'%s' does not appear to be a valid command!\n", argv[2] ); + return 1; + }; + + regfree( &cmd_reg ); + + struct passwd *pwd = getpwnam( argv[1] ); + + if ( ! pwd ) { + syslog( LOG_ERR, "Invalid username '%s' (getpwnam)", argv[1] ); + fprintf( stderr, "'%s' does not appear to be a valid username!\n", argv[1] ); + return 1; + }; + + if ( pwd->pw_uid < 1000 ) { + syslog( LOG_ERR, "Invalid username '%s' (uid)", argv[1] ); + fprintf( stderr, "'%s' does not appear to be a valid username!\n", argv[1] ); + return 1; + }; + + if ( setregid( pwd->pw_gid, pwd->pw_gid ) != 0 ) { + err = errno; + syslog( LOG_ERR, "Unable to change GID: %s, %s", argv[2], strerror( err ) ); + fprintf( stderr, "Unable to change GID: %s\n", strerror( err ) ); + return 1; + }; + + if ( setreuid( pwd->pw_uid, pwd->pw_uid ) != 0 ) { + err = errno; + syslog( LOG_ERR, "Unable to change UID: %s, %s", argv[2], strerror( err ) ); + fprintf( stderr, "Unable to change UID: %s\n", strerror( err ) ); + return 1; + }; + + size_t sz = snprintf( NULL, 0, "/usr/share/piny-suid/%s", argv[2] ); + char buf[sz]; + snprintf( buf, sz, "/usr/share/piny-suid/%s", argv[2] ); + + char * const env[] = + { NULL + }; + + syslog( LOG_NOTICE, "Going to exec '%s' as '%s'", argv[2], argv[1] ); + execve( buf, argv + 2, env ); + + syslog( LOG_ERR, "Invalid command '%s' (fell past exec)", argv[2] ); + fprintf( stderr, "'%s' does not appear to be a valid command!\n", argv[2] ); + return 1; + +}; |