#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
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <pwd.h>
#include <grp.h>
#include "sudo.h"
#include "lbuf.h"
#include <sudo_usage.h>
static void usage_excl __P((int))
__attribute__((__noreturn__));
extern int NewArgc;
extern char **NewArgv;
extern int user_closefrom;
extern char *runas_user;
extern char *runas_group;
extern char *optarg;
extern int optind;
#ifdef HAVE_BSD_AUTH_H
char *login_style;
#endif
int
parse_args(argc, argv)
int argc;
char **argv;
{
int mode = 0;
int flags = 0;
int valid_flags, ch;
if (strcmp(getprogname(), "sudoedit") == 0)
mode = MODE_EDIT;
#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
#define is_envar (optind < argc && argv[optind][0] != '/' && \
strchr(argv[optind], '=') != NULL)
valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
MODE_PRESERVE_GROUPS|MODE_SHELL;
for (;;) {
if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
switch (ch) {
case 'A':
SET(tgetpass_flags, TGP_ASKPASS);
break;
#ifdef HAVE_BSD_AUTH_H
case 'a':
login_style = optarg;
break;
#endif
case 'b':
SET(flags, MODE_BACKGROUND);
break;
case 'C':
if ((user_closefrom = atoi(optarg)) < 3) {
warningx("the argument to -C must be at least 3");
usage(1);
}
break;
#ifdef HAVE_LOGIN_CAP_H
case 'c':
login_class = optarg;
def_use_loginclass = TRUE;
break;
#endif
case 'E':
SET(flags, MODE_PRESERVE_ENV);
break;
case 'e':
if (mode && mode != MODE_EDIT)
usage_excl(1);
mode = MODE_EDIT;
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break;
case 'g':
runas_group = optarg;
break;
case 'H':
SET(flags, MODE_RESET_HOME);
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':
SET(flags, MODE_LOGIN_SHELL);
def_env_reset = TRUE;
break;
case 'k':
SET(flags, MODE_INVALIDATE);
break;
case 'K':
if (mode && mode != MODE_KILL)
usage_excl(1);
mode = MODE_KILL;
valid_flags = 0;
break;
case 'L':
if (mode && mode != MODE_LISTDEFS)
usage_excl(1);
mode = MODE_LISTDEFS;
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break;
case 'l':
if (mode) {
if (mode == MODE_LIST)
long_list = 1;
else
usage_excl(1);
}
mode = MODE_LIST;
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
break;
case 'n':
SET(flags, MODE_NONINTERACTIVE);
break;
case 'P':
SET(flags, MODE_PRESERVE_GROUPS);
break;
case 'p':
user_prompt = optarg;
def_passprompt_override = TRUE;
break;
#ifdef HAVE_SELINUX
case 'r':
user_role = optarg;
break;
case 't':
user_type = optarg;
break;
#endif
case 'S':
SET(tgetpass_flags, TGP_STDIN);
break;
case 's':
SET(flags, MODE_SHELL);
break;
case 'U':
if ((list_pw = sudo_getpwnam(optarg)) == NULL)
errorx(1, "unknown user: %s", optarg);
break;
case 'u':
runas_user = optarg;
break;
case 'v':
if (mode && mode != MODE_VALIDATE)
usage_excl(1);
mode = MODE_VALIDATE;
valid_flags = MODE_INVALIDATE|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) {
struct list_member *ev;
ev = emalloc(sizeof(*ev));
ev->value = argv[optind];
ev->next = sudo_user.env_vars;
sudo_user.env_vars = ev;
optind++;
} else {
break;
}
}
NewArgc = argc - optind;
NewArgv = argv + optind;
if (!mode) {
if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
mode = MODE_INVALIDATE;
CLR(flags, MODE_INVALIDATE);
valid_flags = 0;
} else {
mode = MODE_RUN;
}
}
if (NewArgc > 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) || sudo_user.env_vars != NULL)) {
if (ISSET(mode, MODE_PRESERVE_ENV))
warningx("the `-E' option is not valid in edit mode");
if (sudo_user.env_vars != 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_pw != 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 ((NewArgc == 0 && mode == MODE_EDIT) ||
(NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
usage(1);
if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
return(mode | flags);
}
static int
usage_out(buf)
const char *buf;
{
return fputs(buf, stderr);
}
void
usage(exit_val)
int exit_val;
{
struct lbuf lbuf;
char *uvec[6];
int i, ulen;
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;
}
ulen = (int)strlen(getprogname()) + 8;
lbuf_init(&lbuf, usage_out, ulen, NULL);
for (i = 0; uvec[i] != NULL; i++) {
lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
lbuf_print(&lbuf);
}
lbuf_destroy(&lbuf);
exit(exit_val);
}
static void
usage_excl(exit_val)
int exit_val;
{
warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
usage(exit_val);
}