Perform command escaping for "sudo -s" and "sudo -i" after validating
sudoers so the sudoers entries don't need to have all the backslashes.
This commit is contained in:
7
NEWS
7
NEWS
@@ -64,6 +64,13 @@ What's new in Sudo 1.7.5?
|
|||||||
|
|
||||||
* The I/O log directory may now be specified in the sudoers file.
|
* The I/O log directory may now be specified in the sudoers file.
|
||||||
|
|
||||||
|
* Sudo will no longer refuse to run if the sudoers file is writable
|
||||||
|
by root.
|
||||||
|
|
||||||
|
* Sudo now performs command line escaping for "sudo -s" and "sudo -i"
|
||||||
|
after validating the command so the sudoers entries do not need
|
||||||
|
to include the backslashes.
|
||||||
|
|
||||||
What's new in Sudo 1.7.4p6?
|
What's new in Sudo 1.7.4p6?
|
||||||
|
|
||||||
* A bug has been fixed in the I/O logging support that could cause
|
* A bug has been fixed in the I/O logging support that could cause
|
||||||
|
@@ -382,38 +382,17 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
|
|||||||
memcpy(av + 1, argv, argc * sizeof(char *));
|
memcpy(av + 1, argv, argc * sizeof(char *));
|
||||||
} else {
|
} else {
|
||||||
/* shell -c "command" */
|
/* shell -c "command" */
|
||||||
size_t cmnd_size = 1024;
|
char *src, *dst, *end;
|
||||||
char *cmnd, *src, *dst, **ap;
|
size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
|
||||||
|
strlen(argv[argc - 1]) + 1;
|
||||||
cmnd = dst = emalloc(cmnd_size);
|
|
||||||
for (ap = argv; *ap != NULL; ap++) {
|
|
||||||
for (src = *ap; *src != '\0'; src++) {
|
|
||||||
/* reserve room for an escaped char + space */
|
|
||||||
if (cmnd_size < (dst - cmnd) + 3) {
|
|
||||||
char *new_cmnd;
|
|
||||||
cmnd_size <<= 1;
|
|
||||||
new_cmnd = erealloc(cmnd, cmnd_size);
|
|
||||||
dst = new_cmnd + (dst - cmnd);
|
|
||||||
cmnd = new_cmnd;
|
|
||||||
}
|
|
||||||
if (isalnum((unsigned char)*src) || *src == '_' || *src == '-') {
|
|
||||||
*dst++ = *src;
|
|
||||||
} else {
|
|
||||||
/* quote potential meta character */
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = *src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dst++ = ' ';
|
|
||||||
}
|
|
||||||
if (cmnd != dst)
|
|
||||||
dst--; /* replace last space with a NUL */
|
|
||||||
*dst = '\0';
|
|
||||||
|
|
||||||
ac = 3;
|
ac = 3;
|
||||||
av = emalloc2(ac + 1, sizeof(char *));
|
av = emalloc2(ac + 1, sizeof(char *));
|
||||||
av[1] = "-c";
|
av[1] = "-c";
|
||||||
av[2] = cmnd;
|
av[2] = dst = emalloc(cmnd_size);
|
||||||
|
src = argv[0];
|
||||||
|
for (end = src + cmnd_size - 1; src < end; src++, dst++)
|
||||||
|
*dst = *src == '\0' ? ' ' : *src;
|
||||||
|
*dst = '\0';
|
||||||
}
|
}
|
||||||
av[0] = (char *)user_details.shell; /* plugin may override shell */
|
av[0] = (char *)user_details.shell; /* plugin may override shell */
|
||||||
av[ac] = NULL;
|
av[ac] = NULL;
|
||||||
|
34
src/sudo.c
34
src/sudo.c
@@ -51,12 +51,13 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif /* HAVE_UNISTD_H */
|
#endif /* HAVE_UNISTD_H */
|
||||||
#include <pwd.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
#if TIME_WITH_SYS_TIME
|
#if TIME_WITH_SYS_TIME
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -117,6 +118,7 @@ static int iolog_open(struct plugin_container *plugin, char * const settings[],
|
|||||||
int argc, char * const argv[], char * const user_env[]);
|
int argc, char * const argv[], char * const user_env[]);
|
||||||
static void iolog_close(struct plugin_container *plugin, int exit_status,
|
static void iolog_close(struct plugin_container *plugin, int exit_status,
|
||||||
int error);
|
int error);
|
||||||
|
static char *escape_cmnd(const char *src);
|
||||||
|
|
||||||
/* Policy plugin convenience functions. */
|
/* Policy plugin convenience functions. */
|
||||||
static int policy_open(struct plugin_container *plugin, char * const settings[],
|
static int policy_open(struct plugin_container *plugin, char * const settings[],
|
||||||
@@ -278,6 +280,12 @@ main(int argc, char *argv[], char *envp[])
|
|||||||
if (ISSET(command_details.flags, CD_SUDOEDIT)) {
|
if (ISSET(command_details.flags, CD_SUDOEDIT)) {
|
||||||
exitcode = sudo_edit(&command_details, argv_out, user_env_out);
|
exitcode = sudo_edit(&command_details, argv_out, user_env_out);
|
||||||
} else {
|
} else {
|
||||||
|
if (ISSET(sudo_mode, MODE_SHELL)) {
|
||||||
|
/* Escape meta chars if running a shell with args. */
|
||||||
|
if (argv_out[1] != NULL && strcmp(argv_out[1], "-c") == 0 &&
|
||||||
|
argv_out[2] != NULL && argv_out[3] == NULL)
|
||||||
|
argv_out[2] = escape_cmnd(argv_out[2]);
|
||||||
|
}
|
||||||
exitcode = run_command(&command_details, argv_out, user_env_out);
|
exitcode = run_command(&command_details, argv_out, user_env_out);
|
||||||
}
|
}
|
||||||
/* The close method was called by sudo_edit/run_command. */
|
/* The close method was called by sudo_edit/run_command. */
|
||||||
@@ -907,6 +915,30 @@ done:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Escape any non-alpha numeric or blank characters to make sure
|
||||||
|
* they are not interpreted specially by the shell.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
escape_cmnd(const char *src)
|
||||||
|
{
|
||||||
|
char *cmnd, *dst;
|
||||||
|
|
||||||
|
/* Worst case scenario, we have to escape everything. */
|
||||||
|
cmnd = dst = emalloc((2 * strlen(src)) + 1);
|
||||||
|
while (*src != '\0') {
|
||||||
|
if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) &&
|
||||||
|
*src != '_' && *src != '-') {
|
||||||
|
/* quote potential meta character */
|
||||||
|
*dst++ = '\\';
|
||||||
|
}
|
||||||
|
*dst++ = *src++;
|
||||||
|
}
|
||||||
|
*dst++ = '\0';
|
||||||
|
|
||||||
|
return cmnd;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the command and wait for it to complete.
|
* Run the command and wait for it to complete.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user