2 * Copyright (c) 1993-1996, 1998-2010 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 * Sponsored in part by the Defense Advanced Research Projects
17 * Agency (DARPA) and Air Force Research Laboratory, Air Force
18 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
23 #include <sys/types.h>
24 #include <sys/param.h>
34 #endif /* STDC_HEADERS */
37 #endif /* HAVE_STRING_H */
40 #endif /* HAVE_STRINGS_H */
43 #endif /* HAVE_UNISTD_H */
49 #include <sudo_usage.h>
54 static void usage_excl __P((int));
60 extern char **NewArgv;
61 extern int user_closefrom;
62 extern char *runas_user;
63 extern char *runas_group;
69 #ifdef HAVE_BSD_AUTH_H
71 #endif /* HAVE_BSD_AUTH_H */
74 * Command line argument parsing.
75 * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use
76 * for the command to be run (if we are running one).
79 parse_args(argc, argv)
83 int mode = 0; /* what mode is sudo to be run in? */
84 int flags = 0; /* mode flags */
87 /* First, check to see if we were invoked as "sudoedit". */
88 if (strcmp(getprogname(), "sudoedit") == 0)
91 /* Returns true if the last option string was "--" */
92 #define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
93 argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
95 /* Returns true if next option is an environment variable */
96 #define is_envar (optind < argc && argv[optind][0] != '/' && \
97 strchr(argv[optind], '=') != NULL)
99 /* Flags allowed when running a command */
100 valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
101 MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
102 MODE_PRESERVE_GROUPS|MODE_SHELL;
105 * We disable arg permutation for GNU getopt().
106 * Some trickiness is required to allow environment variables
107 * to be interspersed with command line options.
109 if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
112 SET(tgetpass_flags, TGP_ASKPASS);
114 #ifdef HAVE_BSD_AUTH_H
116 login_style = optarg;
120 SET(flags, MODE_BACKGROUND);
123 if ((user_closefrom = atoi(optarg)) < 3) {
124 warningx("the argument to -C must be a number greater than or equal to 3");
128 #ifdef HAVE_LOGIN_CAP_H
130 login_class = optarg;
131 def_use_loginclass = TRUE;
135 SET(flags, MODE_PRESERVE_ENV);
138 if (mode && mode != MODE_EDIT)
141 valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
144 runas_group = optarg;
147 SET(flags, MODE_RESET_HOME);
150 if (mode && mode != MODE_HELP) {
151 if (strcmp(getprogname(), "sudoedit") != 0)
158 SET(flags, MODE_LOGIN_SHELL);
159 def_env_reset = TRUE;
162 SET(flags, MODE_INVALIDATE);
165 if (mode && mode != MODE_KILL)
171 if (mode && mode != MODE_LISTDEFS)
173 mode = MODE_LISTDEFS;
174 valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
178 if (mode == MODE_LIST)
184 valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
187 SET(flags, MODE_NONINTERACTIVE);
190 SET(flags, MODE_PRESERVE_GROUPS);
193 user_prompt = optarg;
194 def_passprompt_override = TRUE;
205 SET(tgetpass_flags, TGP_STDIN);
208 SET(flags, MODE_SHELL);
211 if ((list_pw = sudo_getpwnam(optarg)) == NULL)
212 errorx(1, "unknown user: %s", optarg);
218 if (mode && mode != MODE_VALIDATE)
220 mode = MODE_VALIDATE;
221 valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
224 if (mode && mode != MODE_VERSION)
232 } else if (!got_end_of_args && is_envar) {
233 struct list_member *ev;
235 /* Store environment variable. */
236 ev = emalloc(sizeof(*ev));
237 ev->value = argv[optind];
238 ev->next = sudo_user.env_vars;
239 sudo_user.env_vars = ev;
241 /* Crank optind and resume getopt. */
244 /* Not an option or an environment variable -- we're done. */
249 NewArgc = argc - optind;
250 NewArgv = argv + optind;
253 /* Defer -k mode setting until we know whether it is a flag or not */
254 if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
255 mode = MODE_INVALIDATE; /* -k by itself */
256 CLR(flags, MODE_INVALIDATE);
259 mode = MODE_RUN; /* running a command */
263 if (NewArgc > 0 && mode == MODE_LIST)
266 if (ISSET(flags, MODE_LOGIN_SHELL)) {
267 if (ISSET(flags, MODE_SHELL)) {
268 warningx("you may not specify both the `-i' and `-s' options");
271 if (ISSET(flags, MODE_PRESERVE_ENV)) {
272 warningx("you may not specify both the `-i' and `-E' options");
275 SET(flags, MODE_SHELL);
277 if ((flags & valid_flags) != flags)
279 if (mode == MODE_EDIT &&
280 (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
281 if (ISSET(mode, MODE_PRESERVE_ENV))
282 warningx("the `-E' option is not valid in edit mode");
283 if (sudo_user.env_vars != NULL)
284 warningx("you may not specify environment variables in edit mode");
287 if ((runas_user != NULL || runas_group != NULL) &&
288 !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
291 if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
292 warningx("the `-U' option may only be used with the `-l' option");
295 if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
296 warningx("the `-A' and `-S' options may not be used together");
299 if ((NewArgc == 0 && mode == MODE_EDIT) ||
300 (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
302 if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
303 SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
312 return fputs(buf, stderr);
319 return fputs(buf, stdout);
323 * Give usage message and exit.
324 * The actual usage strings are in sudo_usage.h for configure substitution.
335 * Use usage vectors appropriate to the progname.
337 if (strcmp(getprogname(), "sudoedit") == 0) {
338 uvec[0] = SUDO_USAGE5 + 3;
341 uvec[0] = SUDO_USAGE1;
342 uvec[1] = SUDO_USAGE2;
343 uvec[2] = SUDO_USAGE3;
344 uvec[3] = SUDO_USAGE4;
345 uvec[4] = SUDO_USAGE5;
350 * Print usage and wrap lines as needed, depending on the
353 ulen = (int)strlen(getprogname()) + 8;
354 lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL);
355 for (i = 0; uvec[i] != NULL; i++) {
356 lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
365 * Tell which options are mutually exclusive and exit.
371 warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
380 const char *pname = getprogname();
382 lbuf_init(&lbuf, usage_out, indent, NULL);
383 if (strcmp(pname, "sudoedit") == 0)
384 lbuf_append(&lbuf, pname, " - edit files as another user\n\n", NULL);
386 lbuf_append(&lbuf, pname, " - execute a command as another user\n\n", NULL);
391 lbuf_append(&lbuf, "\nOptions:\n", NULL);
392 #ifdef HAVE_BSD_AUTH_H
394 " -A use helper program for password prompting\n", NULL);
397 " -a type use specified BSD authentication type\n", NULL);
399 " -b run command in the background\n", NULL);
401 " -C fd close all file descriptors >= fd\n", NULL);
402 #ifdef HAVE_LOGIN_CAP_H
404 " -c class run command with specified login class\n", NULL);
407 " -E preserve user environment when executing command\n",
410 " -e edit files instead of running a command\n", NULL);
412 " -g group execute command as the specified group\n", NULL);
414 " -H set HOME variable to target user's home dir.\n",
417 " -h display help message and exit\n", NULL);
419 " -i [command] run a login shell as target user\n", NULL);
421 " -K remove timestamp file completely\n", NULL);
423 " -k invalidate timestamp file\n", NULL);
425 " -L list supported sudoers Defaults values\n", NULL);
427 " -l[l] command list user's available commands\n", NULL);
429 " -n non-interactive mode, will not prompt user\n", NULL);
431 " -P preserve group vector instead of setting to target's\n",
434 " -p prompt use specified password prompt\n", NULL);
437 " -r role create SELinux security context with specified role\n",
441 " -S read password from standard input\n", NULL);
443 " -s [command] run a shell as target user\n", NULL);
446 " -t type create SELinux security context with specified role\n",
450 " -U user when listing, list specified user's privileges\n",
453 " -u user run command (or edit file) as specified user\n", NULL);
455 " -V display version information and exit\n", NULL);
457 " -v update user's timestamp without running a command\n",
460 " -- stop processing command line arguments\n", NULL);