603 lines
16 KiB
C
603 lines
16 KiB
C
/*
|
|
* Copyright (c) 1993-1996, 1998-2012 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Sponsored in part by the Defense Advanced Research Projects
|
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
|
|
#include <stdio.h>
|
|
#ifdef STDC_HEADERS
|
|
# include <stdlib.h>
|
|
# include <stddef.h>
|
|
#else
|
|
# ifdef HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
# endif
|
|
#endif /* STDC_HEADERS */
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif /* HAVE_STRING_H */
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif /* HAVE_STRINGS_H */
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif /* HAVE_UNISTD_H */
|
|
#include <ctype.h>
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
|
|
#include <sudo_usage.h>
|
|
#include "sudo.h"
|
|
#include "lbuf.h"
|
|
|
|
/* For getopt(3) */
|
|
extern char *optarg;
|
|
extern int optind;
|
|
|
|
int tgetpass_flags;
|
|
|
|
/*
|
|
* Local functions.
|
|
*/
|
|
static void help(void) __attribute__((__noreturn__));
|
|
static void usage_excl(int);
|
|
|
|
/*
|
|
* Mapping of command line flags to name/value settings.
|
|
*/
|
|
static struct sudo_settings {
|
|
const char *name;
|
|
const char *value;
|
|
} sudo_settings[] = {
|
|
#define ARG_BSDAUTH_TYPE 0
|
|
{ "bsdauth_type" },
|
|
#define ARG_LOGIN_CLASS 1
|
|
{ "login_class" },
|
|
#define ARG_DEBUG_FLAGS 2
|
|
{ "debug_flags" },
|
|
#define ARG_PRESERVE_ENVIRONMENT 3
|
|
{ "preserve_environment" },
|
|
#define ARG_RUNAS_GROUP 4
|
|
{ "runas_group" },
|
|
#define ARG_SET_HOME 5
|
|
{ "set_home" },
|
|
#define ARG_USER_SHELL 6
|
|
{ "run_shell" },
|
|
#define ARG_LOGIN_SHELL 7
|
|
{ "login_shell" },
|
|
#define ARG_IGNORE_TICKET 8
|
|
{ "ignore_ticket" },
|
|
#define ARG_PROMPT 9
|
|
{ "prompt" },
|
|
#define ARG_SELINUX_ROLE 10
|
|
{ "selinux_role" },
|
|
#define ARG_SELINUX_TYPE 11
|
|
{ "selinux_type" },
|
|
#define ARG_RUNAS_USER 12
|
|
{ "runas_user" },
|
|
#define ARG_PROGNAME 13
|
|
{ "progname" },
|
|
#define ARG_IMPLIED_SHELL 14
|
|
{ "implied_shell" },
|
|
#define ARG_PRESERVE_GROUPS 15
|
|
{ "preserve_groups" },
|
|
#define ARG_NONINTERACTIVE 16
|
|
{ "noninteractive" },
|
|
#define ARG_SUDOEDIT 17
|
|
{ "sudoedit" },
|
|
#define ARG_CLOSEFROM 18
|
|
{ "closefrom" },
|
|
#define ARG_NET_ADDRS 19
|
|
{ "network_addrs" },
|
|
#define NUM_SETTINGS 20
|
|
{ NULL }
|
|
};
|
|
|
|
/*
|
|
* Command line argument parsing.
|
|
* Sets nargc and nargv which corresponds to the argc/argv we'll use
|
|
* for the command to be run (if we are running one).
|
|
*/
|
|
int
|
|
parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
|
|
char ***env_addp)
|
|
{
|
|
int mode = 0; /* what mode is sudo to be run in? */
|
|
int flags = 0; /* mode flags */
|
|
int valid_flags, ch;
|
|
int i, j;
|
|
char *cp, **env_add, **settings;
|
|
const char *debug_flags;
|
|
int nenv = 0;
|
|
int env_size = 32;
|
|
debug_decl(parse_args, SUDO_DEBUG_ARGS)
|
|
|
|
env_add = emalloc2(env_size, sizeof(char *));
|
|
|
|
/* Pass progname to plugin so it can call setprogname() */
|
|
sudo_settings[ARG_PROGNAME].value = getprogname();
|
|
|
|
/* First, check to see if we were invoked as "sudoedit". */
|
|
if (strcmp(getprogname(), "sudoedit") == 0) {
|
|
mode = MODE_EDIT;
|
|
sudo_settings[ARG_SUDOEDIT].value = "true";
|
|
}
|
|
|
|
/* Load local IP addresses and masks. */
|
|
if (get_net_ifs(&cp) > 0)
|
|
sudo_settings[ARG_NET_ADDRS].value = cp;
|
|
|
|
/* Set debug file and flags from sudo.conf. */
|
|
debug_flags = sudo_conf_debug_flags();
|
|
if (debug_flags != NULL)
|
|
sudo_settings[ARG_DEBUG_FLAGS].value = debug_flags;
|
|
|
|
/* Returns true if the last option string was "--" */
|
|
#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
|
|
argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
|
|
|
|
/* Returns true if next option is an environment variable */
|
|
#define is_envar (optind < argc && argv[optind][0] != '/' && \
|
|
strchr(argv[optind], '=') != NULL)
|
|
|
|
/* Flags allowed when running a command */
|
|
valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
|
|
MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL;
|
|
/* XXX - should fill in settings at the end to avoid dupes */
|
|
for (;;) {
|
|
/*
|
|
* We disable arg permutation for GNU getopt().
|
|
* Some trickiness is required to allow environment variables
|
|
* to be interspersed with command line options.
|
|
*/
|
|
if ((ch = getopt(argc, argv, "+Aa:bC:c:D:Eeg:HhiKklnPp:r:Sst:U:u:Vv")) != -1) {
|
|
switch (ch) {
|
|
case 'A':
|
|
SET(tgetpass_flags, TGP_ASKPASS);
|
|
break;
|
|
#ifdef HAVE_BSD_AUTH_H
|
|
case 'a':
|
|
sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
|
|
break;
|
|
#endif
|
|
case 'b':
|
|
SET(flags, MODE_BACKGROUND);
|
|
break;
|
|
case 'C':
|
|
if (atoi(optarg) < 3) {
|
|
warningx(_("the argument to -C must be a number greater than or equal to 3"));
|
|
usage(1);
|
|
}
|
|
sudo_settings[ARG_CLOSEFROM].value = optarg;
|
|
break;
|
|
#ifdef HAVE_LOGIN_CAP_H
|
|
case 'c':
|
|
sudo_settings[ARG_LOGIN_CLASS].value = optarg;
|
|
break;
|
|
#endif
|
|
case 'D':
|
|
/* Ignored for backwards compatibility. */
|
|
break;
|
|
case 'E':
|
|
sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
|
|
break;
|
|
case 'e':
|
|
if (mode && mode != MODE_EDIT)
|
|
usage_excl(1);
|
|
mode = MODE_EDIT;
|
|
sudo_settings[ARG_SUDOEDIT].value = "true";
|
|
valid_flags = MODE_NONINTERACTIVE;
|
|
break;
|
|
case 'g':
|
|
runas_group = optarg;
|
|
sudo_settings[ARG_RUNAS_GROUP].value = optarg;
|
|
break;
|
|
case 'H':
|
|
sudo_settings[ARG_SET_HOME].value = "true";
|
|
break;
|
|
case 'h':
|
|
if (mode && mode != MODE_HELP) {
|
|
if (strcmp(getprogname(), "sudoedit") != 0)
|
|
usage_excl(1);
|
|
}
|
|
mode = MODE_HELP;
|
|
valid_flags = 0;
|
|
break;
|
|
case 'i':
|
|
sudo_settings[ARG_LOGIN_SHELL].value = "true";
|
|
SET(flags, MODE_LOGIN_SHELL);
|
|
break;
|
|
case 'k':
|
|
sudo_settings[ARG_IGNORE_TICKET].value = "true";
|
|
break;
|
|
case 'K':
|
|
sudo_settings[ARG_IGNORE_TICKET].value = "true";
|
|
if (mode && mode != MODE_KILL)
|
|
usage_excl(1);
|
|
mode = MODE_KILL;
|
|
valid_flags = 0;
|
|
break;
|
|
case 'l':
|
|
if (mode) {
|
|
if (mode == MODE_LIST)
|
|
SET(flags, MODE_LONG_LIST);
|
|
else
|
|
usage_excl(1);
|
|
}
|
|
mode = MODE_LIST;
|
|
valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
|
|
break;
|
|
case 'n':
|
|
SET(flags, MODE_NONINTERACTIVE);
|
|
sudo_settings[ARG_NONINTERACTIVE].value = "true";
|
|
break;
|
|
case 'P':
|
|
sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
|
|
break;
|
|
case 'p':
|
|
sudo_settings[ARG_PROMPT].value = optarg;
|
|
break;
|
|
#ifdef HAVE_SELINUX
|
|
case 'r':
|
|
sudo_settings[ARG_SELINUX_ROLE].value = optarg;
|
|
break;
|
|
case 't':
|
|
sudo_settings[ARG_SELINUX_TYPE].value = optarg;
|
|
break;
|
|
#endif
|
|
case 'S':
|
|
SET(tgetpass_flags, TGP_STDIN);
|
|
break;
|
|
case 's':
|
|
sudo_settings[ARG_USER_SHELL].value = "true";
|
|
SET(flags, MODE_SHELL);
|
|
break;
|
|
case 'U':
|
|
if ((getpwnam(optarg)) == NULL)
|
|
errorx(1, _("unknown user: %s"), optarg);
|
|
list_user = optarg;
|
|
break;
|
|
case 'u':
|
|
runas_user = optarg;
|
|
sudo_settings[ARG_RUNAS_USER].value = optarg;
|
|
break;
|
|
case 'v':
|
|
if (mode && mode != MODE_VALIDATE)
|
|
usage_excl(1);
|
|
mode = MODE_VALIDATE;
|
|
valid_flags = MODE_NONINTERACTIVE;
|
|
break;
|
|
case 'V':
|
|
if (mode && mode != MODE_VERSION)
|
|
usage_excl(1);
|
|
mode = MODE_VERSION;
|
|
valid_flags = 0;
|
|
break;
|
|
default:
|
|
usage(1);
|
|
}
|
|
} else if (!got_end_of_args && is_envar) {
|
|
if (nenv == env_size - 2) {
|
|
env_size *= 2;
|
|
env_add = erealloc3(env_add, env_size, sizeof(char *));
|
|
}
|
|
env_add[nenv++] = argv[optind];
|
|
|
|
/* Crank optind and resume getopt. */
|
|
optind++;
|
|
} else {
|
|
/* Not an option or an environment variable -- we're done. */
|
|
break;
|
|
}
|
|
}
|
|
env_add[nenv] = NULL;
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (!mode) {
|
|
/* Defer -k mode setting until we know whether it is a flag or not */
|
|
if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
|
|
if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) {
|
|
mode = MODE_INVALIDATE; /* -k by itself */
|
|
sudo_settings[ARG_IGNORE_TICKET].value = NULL;
|
|
valid_flags = 0;
|
|
}
|
|
}
|
|
if (!mode)
|
|
mode = MODE_RUN; /* running a command */
|
|
}
|
|
|
|
if (argc > 0 && mode == MODE_LIST)
|
|
mode = MODE_CHECK;
|
|
|
|
if (ISSET(flags, MODE_LOGIN_SHELL)) {
|
|
if (ISSET(flags, MODE_SHELL)) {
|
|
warningx(_("you may not specify both the `-i' and `-s' options"));
|
|
usage(1);
|
|
}
|
|
if (ISSET(flags, MODE_PRESERVE_ENV)) {
|
|
warningx(_("you may not specify both the `-i' and `-E' options"));
|
|
usage(1);
|
|
}
|
|
SET(flags, MODE_SHELL);
|
|
}
|
|
if ((flags & valid_flags) != flags)
|
|
usage(1);
|
|
if (mode == MODE_EDIT &&
|
|
(ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
|
|
if (ISSET(mode, MODE_PRESERVE_ENV))
|
|
warningx(_("the `-E' option is not valid in edit mode"));
|
|
if (env_add[0] != NULL)
|
|
warningx(_("you may not specify environment variables in edit mode"));
|
|
usage(1);
|
|
}
|
|
if ((runas_user != NULL || runas_group != NULL) &&
|
|
!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
|
|
usage(1);
|
|
}
|
|
if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
|
|
warningx(_("the `-U' option may only be used with the `-l' option"));
|
|
usage(1);
|
|
}
|
|
if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
|
|
warningx(_("the `-A' and `-S' options may not be used together"));
|
|
usage(1);
|
|
}
|
|
if ((argc == 0 && mode == MODE_EDIT) ||
|
|
(argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
|
|
usage(1);
|
|
if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
|
|
SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
|
|
sudo_settings[ARG_IMPLIED_SHELL].value = "true";
|
|
}
|
|
|
|
if (mode == MODE_HELP)
|
|
help();
|
|
|
|
/*
|
|
* For shell mode we need to rewrite argv
|
|
*/
|
|
if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
|
|
char **av, *cmnd = NULL;
|
|
int ac = 1;
|
|
|
|
if (argc != 0) {
|
|
/* shell -c "command" */
|
|
char *src, *dst;
|
|
size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
|
|
strlen(argv[argc - 1]) + 1;
|
|
|
|
cmnd = dst = emalloc2(cmnd_size, 2);
|
|
for (av = argv; *av != NULL; av++) {
|
|
for (src = *av; *src != '\0'; src++) {
|
|
/* quote potential meta characters */
|
|
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-')
|
|
*dst++ = '\\';
|
|
*dst++ = *src;
|
|
}
|
|
*dst++ = ' ';
|
|
}
|
|
if (cmnd != dst)
|
|
dst--; /* replace last space with a NUL */
|
|
*dst = '\0';
|
|
|
|
ac += 2; /* -c cmnd */
|
|
}
|
|
|
|
av = emalloc2(ac + 1, sizeof(char *));
|
|
av[0] = (char *)user_details.shell; /* plugin may override shell */
|
|
if (cmnd != NULL) {
|
|
av[1] = "-c";
|
|
av[2] = cmnd;
|
|
}
|
|
av[ac] = NULL;
|
|
|
|
argv = av;
|
|
argc = ac;
|
|
}
|
|
|
|
/*
|
|
* Format setting_pairs into settings array.
|
|
*/
|
|
settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
|
|
for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
|
|
if (sudo_settings[i].value) {
|
|
sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s=%s",
|
|
sudo_settings[i].name, sudo_settings[i].value);
|
|
settings[j] = fmt_string(sudo_settings[i].name,
|
|
sudo_settings[i].value);
|
|
if (settings[j] == NULL)
|
|
errorx(1, NULL);
|
|
j++;
|
|
}
|
|
}
|
|
settings[j] = NULL;
|
|
|
|
if (mode == MODE_EDIT) {
|
|
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
|
|
/* Must have the command in argv[0]. */
|
|
argc++;
|
|
argv--;
|
|
argv[0] = "sudoedit";
|
|
#else
|
|
errorx(1, _("sudoedit is not supported on this platform"));
|
|
#endif
|
|
}
|
|
|
|
*settingsp = settings;
|
|
*env_addp = env_add;
|
|
*nargc = argc;
|
|
*nargv = argv;
|
|
debug_return_int(mode | flags);
|
|
}
|
|
|
|
static int
|
|
usage_err(const char *buf)
|
|
{
|
|
return fputs(buf, stderr);
|
|
}
|
|
|
|
static int
|
|
usage_out(const char *buf)
|
|
{
|
|
return fputs(buf, stdout);
|
|
}
|
|
|
|
/*
|
|
* Give usage message and exit.
|
|
* The actual usage strings are in sudo_usage.h for configure substitution.
|
|
*/
|
|
void
|
|
usage(int fatal)
|
|
{
|
|
struct lbuf lbuf;
|
|
char *uvec[6];
|
|
int i, ulen;
|
|
|
|
/*
|
|
* Use usage vectors appropriate to the progname.
|
|
*/
|
|
if (strcmp(getprogname(), "sudoedit") == 0) {
|
|
uvec[0] = SUDO_USAGE5 + 3;
|
|
uvec[1] = NULL;
|
|
} else {
|
|
uvec[0] = SUDO_USAGE1;
|
|
uvec[1] = SUDO_USAGE2;
|
|
uvec[2] = SUDO_USAGE3;
|
|
uvec[3] = SUDO_USAGE4;
|
|
uvec[4] = SUDO_USAGE5;
|
|
uvec[5] = NULL;
|
|
}
|
|
|
|
/*
|
|
* Print usage and wrap lines as needed, depending on the
|
|
* tty width.
|
|
*/
|
|
ulen = (int)strlen(getprogname()) + 8;
|
|
lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL,
|
|
user_details.ts_cols);
|
|
for (i = 0; uvec[i] != NULL; i++) {
|
|
lbuf_append(&lbuf, "usage: %s%s", getprogname(), uvec[i]);
|
|
lbuf_print(&lbuf);
|
|
}
|
|
lbuf_destroy(&lbuf);
|
|
if (fatal)
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Tell which options are mutually exclusive and exit.
|
|
*/
|
|
static void
|
|
usage_excl(int fatal)
|
|
{
|
|
debug_decl(usage_excl, SUDO_DEBUG_ARGS)
|
|
|
|
warningx(_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
|
|
usage(fatal);
|
|
}
|
|
|
|
static void
|
|
help(void)
|
|
{
|
|
struct lbuf lbuf;
|
|
int indent = 16;
|
|
const char *pname = getprogname();
|
|
debug_decl(help, SUDO_DEBUG_ARGS)
|
|
|
|
lbuf_init(&lbuf, usage_out, indent, NULL, user_details.ts_cols);
|
|
if (strcmp(pname, "sudoedit") == 0)
|
|
lbuf_append(&lbuf, _("%s - edit files as another user\n\n"), pname);
|
|
else
|
|
lbuf_append(&lbuf, _("%s - execute a command as another user\n\n"), pname);
|
|
lbuf_print(&lbuf);
|
|
|
|
usage(0);
|
|
|
|
lbuf_append(&lbuf, _("\nOptions:\n"));
|
|
#ifdef HAVE_BSD_AUTH_H
|
|
lbuf_append(&lbuf, " -A %s",
|
|
_("use helper program for password prompting\n"));
|
|
#endif
|
|
lbuf_append(&lbuf, " -a type %s",
|
|
_("use specified BSD authentication type\n"));
|
|
lbuf_append(&lbuf, " -b %s",
|
|
_("run command in the background\n"));
|
|
lbuf_append(&lbuf, " -C fd %s",
|
|
_("close all file descriptors >= fd\n"));
|
|
#ifdef HAVE_LOGIN_CAP_H
|
|
lbuf_append(&lbuf, " -c class %s",
|
|
_("run command with specified login class\n"));
|
|
#endif
|
|
lbuf_append(&lbuf, " -E %s",
|
|
_("preserve user environment when executing command\n"));
|
|
lbuf_append(&lbuf, " -e %s",
|
|
_("edit files instead of running a command\n"));
|
|
lbuf_append(&lbuf, " -g group %s",
|
|
_("execute command as the specified group\n"));
|
|
lbuf_append(&lbuf, " -H %s",
|
|
_("set HOME variable to target user's home dir.\n"));
|
|
lbuf_append(&lbuf, " -h %s",
|
|
_("display help message and exit\n"));
|
|
lbuf_append(&lbuf, " -i [command] %s",
|
|
_("run a login shell as target user\n"));
|
|
lbuf_append(&lbuf, " -K %s",
|
|
_("remove timestamp file completely\n"));
|
|
lbuf_append(&lbuf, " -k %s",
|
|
_("invalidate timestamp file\n"));
|
|
lbuf_append(&lbuf, " -l[l] command %s",
|
|
_("list user's available commands\n"));
|
|
lbuf_append(&lbuf, " -n %s",
|
|
_("non-interactive mode, will not prompt user\n"));
|
|
lbuf_append(&lbuf, " -P %s",
|
|
_("preserve group vector instead of setting to target's\n"));
|
|
lbuf_append(&lbuf, " -p prompt %s",
|
|
_("use specified password prompt\n"));
|
|
#ifdef HAVE_SELINUX
|
|
lbuf_append(&lbuf, " -r role %s",
|
|
_("create SELinux security context with specified role\n"));
|
|
#endif
|
|
lbuf_append(&lbuf, " -S %s",
|
|
_("read password from standard input\n"));
|
|
lbuf_append(&lbuf,
|
|
" -s [command] %s", _("run a shell as target user\n"));
|
|
#ifdef HAVE_SELINUX
|
|
lbuf_append(&lbuf, " -t type %s",
|
|
_("create SELinux security context with specified role\n"));
|
|
#endif
|
|
lbuf_append(&lbuf, " -U user %s",
|
|
_("when listing, list specified user's privileges\n"));
|
|
lbuf_append(&lbuf, " -u user %s",
|
|
_("run command (or edit file) as specified user\n"));
|
|
lbuf_append(&lbuf, " -V %s",
|
|
_("display version information and exit\n"));
|
|
lbuf_append(&lbuf, " -v %s",
|
|
_("update user's timestamp without running a command\n"));
|
|
lbuf_append(&lbuf, " -- %s",
|
|
_("stop processing command line arguments\n"));
|
|
lbuf_print(&lbuf);
|
|
lbuf_destroy(&lbuf);
|
|
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 0);
|
|
exit(0);
|
|
}
|