Skip to content

Commit 8255ed6

Browse files
committed
Go back to escaping the command args for "sudo -i" and "sudo -s"
before calling the plugin. Otherwise, spaces in the command args are not treated properly. The sudoers plugin will unescape non-spaces to make matching easier.
1 parent 4f9a93f commit 8255ed6

File tree

3 files changed

+45
-48
lines changed

3 files changed

+45
-48
lines changed

plugins/sudoers/sudoers.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -861,21 +861,38 @@ set_cmnd(void)
861861

862862
/* set user_args */
863863
if (NewArgc > 1) {
864-
char *to, **from;
864+
char *to, *from, **av;
865865
size_t size, n;
866866

867867
/* Alloc and build up user_args. */
868-
for (size = 0, from = NewArgv + 1; *from; from++)
869-
size += strlen(*from) + 1;
868+
for (size = 0, av = NewArgv + 1; *av; av++)
869+
size += strlen(*av) + 1;
870870
user_args = emalloc(size);
871-
for (to = user_args, from = NewArgv + 1; *from; from++) {
872-
n = strlcpy(to, *from, size - (to - user_args));
873-
if (n >= size - (to - user_args))
874-
errorx(1, _("internal error, set_cmnd() overflow"));
875-
to += n;
876-
*to++ = ' ';
871+
if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
872+
/*
873+
* When running a command via a shell, the sudo front-end
874+
* escapes potential meta chars. We unescape non-spaces
875+
* for sudoers matching and logging purposes.
876+
*/
877+
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
878+
while (*from) {
879+
if (from[0] == '\\' && !isspace((unsigned char)from[1]))
880+
from++;
881+
*to++ = *from++;
882+
}
883+
*to++ = ' ';
884+
}
885+
*--to = '\0';
886+
} else {
887+
for (to = user_args, av = NewArgv + 1; *av; av++) {
888+
n = strlcpy(to, *av, size - (to - user_args));
889+
if (n >= size - (to - user_args))
890+
errorx(1, _("internal error, set_cmnd() overflow"));
891+
to += n;
892+
*to++ = ' ';
893+
}
894+
*--to = '\0';
877895
}
878-
*--to = '\0';
879896
}
880897
}
881898
if (strlen(user_cmnd) >= PATH_MAX)

src/parse_args.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -385,17 +385,28 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
385385
memcpy(av + 1, argv, argc * sizeof(char *));
386386
} else {
387387
/* shell -c "command" */
388-
char *src, *dst, *end;
388+
char *cmnd, *src, *dst;
389389
size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
390-
strlen(argv[argc - 1]) + 1;
390+
strlen(argv[argc - 1]) + 1;
391+
392+
cmnd = dst = emalloc2(cmnd_size, 2);
393+
for (av = argv; *av != NULL; av++) {
394+
for (src = *av; *src != '\0'; src++) {
395+
/* quote potential meta characters */
396+
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-')
397+
*dst++ = '\\';
398+
*dst++ = *src;
399+
}
400+
*dst++ = ' ';
401+
}
402+
if (cmnd != dst)
403+
dst--; /* replace last space with a NUL */
404+
*dst = '\0';
405+
391406
ac = 3;
392407
av = emalloc2(ac + 1, sizeof(char *));
393408
av[1] = "-c";
394-
av[2] = dst = emalloc(cmnd_size);
395-
src = argv[0];
396-
for (end = src + cmnd_size - 1; src < end; src++, dst++)
397-
*dst = *src == '\0' ? ' ' : *src;
398-
*dst = '\0';
409+
av[2] = cmnd;
399410
}
400411
av[0] = (char *)user_details.shell; /* plugin may override shell */
401412
av[ac] = NULL;

src/sudo.c

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ static int iolog_open(struct plugin_container *plugin, char * const settings[],
121121
int argc, char * const argv[], char * const user_env[]);
122122
static void iolog_close(struct plugin_container *plugin, int exit_status,
123123
int error);
124-
static char *escape_cmnd(const char *src);
125124

126125
/* Policy plugin convenience functions. */
127126
static int policy_open(struct plugin_container *plugin, char * const settings[],
@@ -293,12 +292,6 @@ main(int argc, char *argv[], char *envp[])
293292
if (ISSET(command_details.flags, CD_SUDOEDIT)) {
294293
exitcode = sudo_edit(&command_details);
295294
} else {
296-
if (ISSET(sudo_mode, MODE_SHELL)) {
297-
/* Escape meta chars if running a shell with args. */
298-
if (argv_out[1] != NULL && strcmp(argv_out[1], "-c") == 0 &&
299-
argv_out[2] != NULL && argv_out[3] == NULL)
300-
argv_out[2] = escape_cmnd(argv_out[2]);
301-
}
302295
exitcode = run_command(&command_details);
303296
}
304297
/* The close method was called by sudo_edit/run_command. */
@@ -1054,30 +1047,6 @@ exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
10541047
return rval;
10551048
}
10561049

1057-
/*
1058-
* Escape any non-alpha numeric or blank characters to make sure
1059-
* they are not interpreted specially by the shell.
1060-
*/
1061-
static char *
1062-
escape_cmnd(const char *src)
1063-
{
1064-
char *cmnd, *dst;
1065-
1066-
/* Worst case scenario, we have to escape everything. */
1067-
cmnd = dst = emalloc((2 * strlen(src)) + 1);
1068-
while (*src != '\0') {
1069-
if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) &&
1070-
*src != '_' && *src != '-') {
1071-
/* quote potential meta character */
1072-
*dst++ = '\\';
1073-
}
1074-
*dst++ = *src++;
1075-
}
1076-
*dst++ = '\0';
1077-
1078-
return cmnd;
1079-
}
1080-
10811050
/*
10821051
* Run the command and wait for it to complete.
10831052
*/

0 commit comments

Comments
 (0)