Don't allow duplicate values for command line options that take an argument.

Previously, if multiple instances of the same command line option were
specified, the last one would be used.  This meant that, for example,
"sudo -u someuser -u otheruser id" would run the command as "otheruser".
This has the potential to cause problems for programs that run sudo with
a user-specified command that do not use the "--" option to indicate
that no more options should be processed.  While this is a bug in
the calling program, there is little downside to erroring out when
multiple options of the same type are specified on the command line.
Bug #924
This commit is contained in:
Todd C. Miller
2020-05-06 19:33:24 -06:00
parent 24ad424a57
commit 4266279c0c
4 changed files with 47 additions and 9 deletions

View File

@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 1993-1996, 1998-2017 Todd C. Miller <Todd.Miller@sudo.ws>
* Copyright (c) 1993-1996, 1998-2020 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -249,8 +249,6 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
int valid_flags = DEFAULT_VALID_FLAGS;
int ch, i;
char *cp;
const char *runas_user = NULL;
const char *runas_group = NULL;
const char *progname;
int proglen;
debug_decl(parse_args, SUDO_DEBUG_ARGS);
@@ -314,6 +312,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
if (sudo_settings[ARG_BSDAUTH_TYPE].value != NULL)
usage();
sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
break;
#endif
@@ -329,6 +329,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
sudo_warnx(U_("the argument to -C must be a number greater than or equal to 3"));
usage();
}
if (sudo_settings[ARG_CLOSEFROM].value != NULL)
usage();
sudo_settings[ARG_CLOSEFROM].value = optarg;
break;
#ifdef HAVE_LOGIN_CAP_H
@@ -336,6 +338,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
if (sudo_settings[ARG_LOGIN_CLASS].value != NULL)
usage();
sudo_settings[ARG_LOGIN_CLASS].value = optarg;
break;
#endif
@@ -352,6 +356,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
SET(flags, MODE_PRESERVE_ENV);
} else {
if (extra_env.env_len != 0)
usage();
parse_env_list(&extra_env, optarg);
}
break;
@@ -366,7 +372,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
runas_group = optarg;
if (sudo_settings[ARG_RUNAS_GROUP].value != NULL)
usage();
sudo_settings[ARG_RUNAS_GROUP].value = optarg;
break;
case 'H':
@@ -381,6 +388,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
*/
if (got_host_flag && !is_envar &&
argv[optind] != NULL && argv[optind][0] != '-') {
if (sudo_settings[ARG_REMOTE_HOST].value != NULL)
usage();
sudo_settings[ARG_REMOTE_HOST].value = argv[optind++];
continue;
}
@@ -397,6 +406,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
if (sudo_settings[ARG_REMOTE_HOST].value != NULL)
usage();
sudo_settings[ARG_REMOTE_HOST].value = optarg;
break;
case 'i':
@@ -433,6 +444,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
case 'p':
/* An empty prompt is allowed. */
assert(optarg != NULL);
if (sudo_settings[ARG_PROMPT].value != NULL)
usage();
sudo_settings[ARG_PROMPT].value = optarg;
break;
#ifdef HAVE_SELINUX
@@ -440,18 +453,24 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
if (sudo_settings[ARG_SELINUX_ROLE].value != NULL)
usage();
sudo_settings[ARG_SELINUX_ROLE].value = optarg;
break;
case 't':
assert(optarg != NULL);
if (*optarg == '\0')
usage();
if (sudo_settings[ARG_SELINUX_TYPE].value != NULL)
usage();
sudo_settings[ARG_SELINUX_TYPE].value = optarg;
break;
#endif
case 'T':
/* Plugin determines whether empty timeout is allowed. */
assert(optarg != NULL);
if (sudo_settings[ARG_TIMEOUT].value != NULL)
usage();
sudo_settings[ARG_TIMEOUT].value = optarg;
break;
case 'S':
@@ -463,7 +482,7 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
break;
case 'U':
assert(optarg != NULL);
if (*optarg == '\0')
if (list_user != NULL || *optarg == '\0')
usage();
list_user = optarg;
break;
@@ -471,7 +490,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
assert(optarg != NULL);
if (*optarg == '\0')
usage();
runas_user = optarg;
if (sudo_settings[ARG_RUNAS_USER].value != NULL)
usage();
sudo_settings[ARG_RUNAS_USER].value = optarg;
break;
case 'v':
@@ -540,7 +560,8 @@ parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
sudo_warnx(U_("you may not specify environment variables in edit mode"));
usage();
}
if ((runas_user != NULL || runas_group != NULL) &&
if ((sudo_settings[ARG_RUNAS_USER].value != NULL ||
sudo_settings[ARG_RUNAS_GROUP].value != NULL) &&
!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
usage();
}