X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fmisc-progs%2Fsetuid.c;h=efd181ad8c51beb0e709dc4da0a5ac3a0a482436;hb=84de1f087c8a3bb0b5ca58503101f95117a69cf0;hp=e54b5d3abe7b66e20e76f6cc66cd91db1fab8ac8;hpb=0037264780e516ef1cd85c1a73b178097b3201d6;p=ipfire-2.x.git diff --git a/src/misc-progs/setuid.c b/src/misc-progs/setuid.c index e54b5d3abe..efd181ad8c 100644 --- a/src/misc-progs/setuid.c +++ b/src/misc-progs/setuid.c @@ -20,6 +20,7 @@ * */ +#include #include #include #include @@ -41,6 +42,8 @@ #define OPEN_MAX 256 #endif +#define MAX_ARGUMENTS 128 + /* Trusted environment for executing commands */ char * trusted_env[4] = { "PATH=/usr/bin:/usr/sbin:/sbin:/bin", @@ -49,37 +52,40 @@ char * trusted_env[4] = { NULL }; -/* Spawns a child process that uses /bin/sh to interpret a command. - * This is much the same in use and purpose as system(), yet as it uses execve - * to pass a trusted environment it's immune to attacks based upon changing - * IFS, ENV, BASH_ENV and other such variables. - * Note this does NOT guard against any other attacks, inparticular you MUST - * validate the command you are passing. If the command is formed from user - * input be sure to check this input is what you expect. Nasty things can - * happen if a user can inject ; or `` into your command for example */ -int safe_system(char* command) { - return system_core(command, 0, 0, "safe_system"); -} - -/* Much like safe_system but lets you specify a non-root uid and gid to run - * the command as */ -int unpriv_system(char* command, uid_t uid, gid_t gid) { - return system_core(command, uid, gid, "unpriv_system"); -} - -int system_core(char* command, uid_t uid, gid_t gid, char *error) { +static int system_core(char* command, char** args, uid_t uid, gid_t gid, char *error) { int pid, status; + char* argv[MAX_ARGUMENTS + 1]; + unsigned int argc = 0; + if(!command) return 1; +#if 0 + // Add command as first element to argv + argv[argc++] = command; +#endif + + // Add all other arguments + if (args) { + while (*args) { + argv[argc++] = *args++; + + // Break when argv is full + if (argc >= MAX_ARGUMENTS) { + return 2; + } + } + } + + // Make sure that argv is NULL-terminated + argv[argc] = NULL; + switch(pid = fork()) { case -1: return -1; case 0: /* child */ { - char *argv[4]; - if (gid && setgid(gid)) { fprintf(stderr, "%s: ", error); perror("Couldn't setgid"); @@ -92,11 +98,8 @@ int system_core(char* command, uid_t uid, gid_t gid, char *error) { exit(127); } - argv[0] = "sh"; - argv[1] = "-c"; - argv[2] = command; - argv[3] = NULL; - execve("/bin/sh", argv, trusted_env); + execve(command, argv, trusted_env); + fprintf(stderr, "%s: ", error); perror("execve failed"); exit(127); @@ -115,6 +118,35 @@ int system_core(char* command, uid_t uid, gid_t gid, char *error) { } +int run(char* command, char** argv) { + return system_core(command, argv, 0, 0, "run"); +} + +/* Spawns a child process that uses /bin/sh to interpret a command. + * This is much the same in use and purpose as system(), yet as it uses execve + * to pass a trusted environment it's immune to attacks based upon changing + * IFS, ENV, BASH_ENV and other such variables. + * Note this does NOT guard against any other attacks, inparticular you MUST + * validate the command you are passing. If the command is formed from user + * input be sure to check this input is what you expect. Nasty things can + * happen if a user can inject ; or `` into your command for example */ +int safe_system(char* command) { + char* argv[4] = { + "/bin/sh", + "-c", + command, + NULL, + }; + + return system_core(argv[0], argv, 0, 0, "safe_system"); +} + +/* Much like safe_system but lets you specify a non-root uid and gid to run + * the command as */ +int unpriv_system(char* command, uid_t uid, gid_t gid) { + return system_core(command, NULL, uid, gid, "unpriv_system"); +} + /* General routine to initialise a setuid root program, and put the * environment in a known state. Returns 1 on success, if initsetuid() returns * 0 then you should exit(1) immediately, DON'T attempt to recover from the @@ -167,3 +199,42 @@ int initsetuid(void) { return 1; } + +/* Checks if a string only contains alphanumerical characters, dash or underscore */ +int is_valid_argument_alnum(const char* arg) { + size_t l = strlen(arg); + + for (unsigned int i = 0; i < l; i++) { + char c = arg[i]; + + // Dash or underscore + if (c == '-' || c == '_') + continue; + + // Any alphanumerical character + if (isalnum(c)) + continue; + + // Invalid + return 0; + } + + return 1; +} + +int is_valid_argument_num(const char* arg) { + size_t l = strlen(arg); + + for (unsigned int i = 0; i < l; i++) { + char c = arg[i]; + + // Any digit + if (isdigit(c)) + continue; + + // Invalid + return 0; + } + + return 1; +}