File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / parse_args.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:55 2014 UTC (10 years ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 1993-1996, 1998-2013 Todd C. Miller <Todd.Miller@courtesan.com>
    3:  *
    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.
    7:  *
    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.
   15:  *
   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.
   19:  */
   20: 
   21: #include <config.h>
   22: 
   23: #include <sys/types.h>
   24: 
   25: #include <stdio.h>
   26: #ifdef STDC_HEADERS
   27: # include <stdlib.h>
   28: # include <stddef.h>
   29: #else
   30: # ifdef HAVE_STDLIB_H
   31: #  include <stdlib.h>
   32: # endif
   33: #endif /* STDC_HEADERS */
   34: #ifdef HAVE_STRING_H
   35: # include <string.h>
   36: #endif /* HAVE_STRING_H */
   37: #ifdef HAVE_STRINGS_H
   38: # include <strings.h>
   39: #endif /* HAVE_STRINGS_H */
   40: #ifdef HAVE_UNISTD_H
   41: # include <unistd.h>
   42: #endif /* HAVE_UNISTD_H */
   43: #ifdef HAVE_GETOPT_LONG
   44: # include <getopt.h>
   45: # else
   46: # include "compat/getopt.h"
   47: #endif /* HAVE_GETOPT_LONG */
   48: #include <ctype.h>
   49: #include <grp.h>
   50: #include <pwd.h>
   51: 
   52: #include <sudo_usage.h>
   53: #include "sudo.h"
   54: #include "lbuf.h"
   55: 
   56: int tgetpass_flags;
   57: 
   58: /*
   59:  * Local functions.
   60:  */
   61: static void help(void) __attribute__((__noreturn__));
   62: static void usage_excl(int);
   63: 
   64: /*
   65:  * Mapping of command line flags to name/value settings.
   66:  */
   67: static struct sudo_settings {
   68:     const char *name;
   69:     const char *value;
   70: } sudo_settings[] = {
   71: #define ARG_BSDAUTH_TYPE 0
   72:     { "bsdauth_type" },
   73: #define ARG_LOGIN_CLASS 1
   74:     { "login_class" },
   75: #define ARG_DEBUG_FLAGS 2
   76:     { "debug_flags" },
   77: #define ARG_PRESERVE_ENVIRONMENT 3
   78:     { "preserve_environment" },
   79: #define ARG_RUNAS_GROUP 4
   80:     { "runas_group" },
   81: #define ARG_SET_HOME 5
   82:     { "set_home" },
   83: #define ARG_USER_SHELL 6
   84:     { "run_shell" },
   85: #define ARG_LOGIN_SHELL 7
   86:     { "login_shell" },
   87: #define ARG_IGNORE_TICKET 8
   88:     { "ignore_ticket" },
   89: #define ARG_PROMPT 9
   90:     { "prompt" },
   91: #define ARG_SELINUX_ROLE 10
   92:     { "selinux_role" },
   93: #define ARG_SELINUX_TYPE 11
   94:     { "selinux_type" },
   95: #define ARG_RUNAS_USER 12
   96:     { "runas_user" },
   97: #define ARG_PROGNAME 13
   98:     { "progname" },
   99: #define ARG_IMPLIED_SHELL 14
  100:     { "implied_shell" },
  101: #define ARG_PRESERVE_GROUPS 15
  102:     { "preserve_groups" },
  103: #define ARG_NONINTERACTIVE 16
  104:     { "noninteractive" },
  105: #define ARG_SUDOEDIT 17
  106:     { "sudoedit" },
  107: #define ARG_CLOSEFROM 18
  108:     { "closefrom" },
  109: #define ARG_NET_ADDRS 19
  110:     { "network_addrs" },
  111: #define ARG_MAX_GROUPS 20
  112:     { "max_groups" },
  113: #define ARG_PLUGIN_DIR 21
  114:     { "plugin_dir" },
  115: #define ARG_REMOTE_HOST 22
  116:     { "remote_host" },
  117: #define NUM_SETTINGS 23
  118:     { NULL }
  119: };
  120: 
  121: /*
  122:  * Default flags allowed when running a command.
  123:  */
  124: #define DEFAULT_VALID_FLAGS	(MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL)
  125: 
  126: /* Option number for the --host long option due to ambiguity of the -h flag. */
  127: #define OPT_HOSTNAME	256
  128: 
  129: /*
  130:  * Available command line options, both short and long.
  131:  * Note that we must disable arg permutation to support setting environment
  132:  * variables and to better support the optional arg of the -h flag.
  133:  */
  134: static const char short_opts[] =  "+Aa:bC:c:D:Eeg:Hh::iKklnPp:r:Sst:U:u:Vv";
  135: static struct option long_opts[] = {
  136:     { "askpass",	no_argument,		NULL,	'A' },
  137:     { "auth-type",	required_argument,	NULL,	'a' },
  138:     { "background",	no_argument,		NULL,	'b' },
  139:     { "close-from",	required_argument,	NULL,	'C' },
  140:     { "login-class",	required_argument,	NULL,	'c' },
  141:     { "preserve-env",	no_argument,		NULL,	'E' },
  142:     { "edit",		no_argument,		NULL,	'e' },
  143:     { "group",		required_argument,	NULL,	'g' },
  144:     { "set-home",	no_argument,		NULL,	'H' },
  145:     { "help",		no_argument,		NULL,	'h' },
  146:     { "host",		required_argument,	NULL,	OPT_HOSTNAME },
  147:     { "login",		no_argument,		NULL,	'i' },
  148:     { "remove-timestamp", no_argument,		NULL,	'K' },
  149:     { "reset-timestamp", no_argument,		NULL,	'k' },
  150:     { "list",		no_argument,		NULL,	'l' },
  151:     { "non-interactive", no_argument,		NULL,	'n' },
  152:     { "preserve-groups", no_argument,		NULL,	'P' },
  153:     { "prompt",		required_argument,	NULL,	'p' },
  154:     { "role",		required_argument,	NULL,	'r' },
  155:     { "stdin",		no_argument,		NULL,	'S' },
  156:     { "shell",		no_argument,		NULL,	's' },
  157:     { "type",		required_argument,	NULL,	't' },
  158:     { "other-user",	required_argument,	NULL,	'U' },
  159:     { "user",		required_argument,	NULL,	'u' },
  160:     { "version",	no_argument,		NULL,	'V' },
  161:     { "validate",	no_argument,		NULL,	'v' },
  162:     { NULL,		no_argument,		NULL,	'\0' },
  163: };
  164: 
  165: /*
  166:  * Command line argument parsing.
  167:  * Sets nargc and nargv which corresponds to the argc/argv we'll use
  168:  * for the command to be run (if we are running one).
  169:  */
  170: int
  171: parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
  172:     char ***env_addp)
  173: {
  174:     int mode = 0;		/* what mode is sudo to be run in? */
  175:     int flags = 0;		/* mode flags */
  176:     int valid_flags = DEFAULT_VALID_FLAGS;
  177:     int ch, i, j;
  178:     char *cp, **env_add, **settings;
  179:     const char *runas_user = NULL;
  180:     const char *runas_group = NULL;
  181:     const char *debug_flags;
  182:     int nenv = 0;
  183:     int env_size = 32;
  184:     debug_decl(parse_args, SUDO_DEBUG_ARGS)
  185: 
  186:     env_add = emalloc2(env_size, sizeof(char *));
  187: 
  188:     /* Pass progname to plugin so it can call initprogname() */
  189:     sudo_settings[ARG_PROGNAME].value = getprogname();
  190: 
  191:     /* First, check to see if we were invoked as "sudoedit". */
  192:     if (strcmp(getprogname(), "sudoedit") == 0) {
  193: 	mode = MODE_EDIT;
  194: 	sudo_settings[ARG_SUDOEDIT].value = "true";
  195:     }
  196: 
  197:     /* Load local IP addresses and masks. */
  198:     if (get_net_ifs(&cp) > 0)
  199: 	sudo_settings[ARG_NET_ADDRS].value = cp;
  200: 
  201:     /* Set debug file and flags from sudo.conf. */
  202:     debug_flags = sudo_conf_debug_flags();
  203:     if (debug_flags != NULL)
  204: 	sudo_settings[ARG_DEBUG_FLAGS].value = debug_flags;
  205: 
  206:     /* Set max_groups from sudo.conf. */
  207:     i = sudo_conf_max_groups();
  208:     if (i != -1) {
  209: 	easprintf(&cp, "%d", i);
  210: 	sudo_settings[ARG_MAX_GROUPS].value = cp;
  211:     }
  212: 
  213:     /* Returns true if the last option string was "-h" */
  214: #define got_host_flag	(optind > 1 && argv[optind - 1][0] == '-' && \
  215: 	    argv[optind - 1][1] == 'h' && argv[optind - 1][2] == '\0')
  216: 
  217:     /* Returns true if the last option string was "--" */
  218: #define got_end_of_args	(optind > 1 && argv[optind - 1][0] == '-' && \
  219: 	    argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
  220: 
  221:     /* Returns true if next option is an environment variable */
  222: #define is_envar (optind < argc && argv[optind][0] != '/' && \
  223: 	    strchr(argv[optind], '=') != NULL)
  224: 
  225:     /* XXX - should fill in settings at the end to avoid dupes */
  226:     for (;;) {
  227: 	/*
  228: 	 * Some trickiness is required to allow environment variables
  229: 	 * to be interspersed with command line options.
  230: 	 */
  231: 	if ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
  232: 	    switch (ch) {
  233: 		case 'A':
  234: 		    SET(tgetpass_flags, TGP_ASKPASS);
  235: 		    break;
  236: #ifdef HAVE_BSD_AUTH_H
  237: 		case 'a':
  238: 		    sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
  239: 		    break;
  240: #endif
  241: 		case 'b':
  242: 		    SET(flags, MODE_BACKGROUND);
  243: 		    break;
  244: 		case 'C':
  245: 		    if (strtonum(optarg, 3, INT_MAX, NULL) == 0) {
  246: 			warningx(_("the argument to -C must be a number greater than or equal to 3"));
  247: 			usage(1);
  248: 		    }
  249: 		    sudo_settings[ARG_CLOSEFROM].value = optarg;
  250: 		    break;
  251: #ifdef HAVE_LOGIN_CAP_H
  252: 		case 'c':
  253: 		    sudo_settings[ARG_LOGIN_CLASS].value = optarg;
  254: 		    break;
  255: #endif
  256: 		case 'D':
  257: 		    /* Ignored for backwards compatibility. */
  258: 		    break;
  259: 		case 'E':
  260: 		    sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
  261: 		    break;
  262: 		case 'e':
  263: 		    if (mode && mode != MODE_EDIT)
  264: 			usage_excl(1);
  265: 		    mode = MODE_EDIT;
  266: 		    sudo_settings[ARG_SUDOEDIT].value = "true";
  267: 		    valid_flags = MODE_NONINTERACTIVE;
  268: 		    break;
  269: 		case 'g':
  270: 		    runas_group = optarg;
  271: 		    sudo_settings[ARG_RUNAS_GROUP].value = optarg;
  272: 		    break;
  273: 		case 'H':
  274: 		    sudo_settings[ARG_SET_HOME].value = "true";
  275: 		    break;
  276: 		case 'h':
  277: 		    if (optarg == NULL) {
  278: 			/*
  279: 			 * Optional args support -hhostname, not -h hostname.
  280: 			 * If we see a non-option after the -h flag, treat as
  281: 			 * remote host and bump optind to skip over it.
  282: 			 */
  283: 			if (got_host_flag && !is_envar &&
  284: 			    argv[optind] != NULL && argv[optind][0] != '-') {
  285: 			    sudo_settings[ARG_REMOTE_HOST].value = argv[optind++];
  286: 			    continue;
  287: 			}
  288: 			if (mode && mode != MODE_HELP) {
  289: 			    if (strcmp(getprogname(), "sudoedit") != 0)
  290: 				usage_excl(1);
  291: 			}
  292: 			mode = MODE_HELP;
  293: 			valid_flags = 0;
  294: 			break;
  295: 		    }
  296: 		    /* FALLTHROUGH */
  297: 		case OPT_HOSTNAME:
  298: 		    sudo_settings[ARG_REMOTE_HOST].value = optarg;
  299: 		    break;
  300: 		case 'i':
  301: 		    sudo_settings[ARG_LOGIN_SHELL].value = "true";
  302: 		    SET(flags, MODE_LOGIN_SHELL);
  303: 		    break;
  304: 		case 'k':
  305: 		    sudo_settings[ARG_IGNORE_TICKET].value = "true";
  306: 		    break;
  307: 		case 'K':
  308: 		    sudo_settings[ARG_IGNORE_TICKET].value = "true";
  309: 		    if (mode && mode != MODE_KILL)
  310: 			usage_excl(1);
  311: 		    mode = MODE_KILL;
  312: 		    valid_flags = 0;
  313: 		    break;
  314: 		case 'l':
  315: 		    if (mode) {
  316: 			if (mode == MODE_LIST)
  317: 			    SET(flags, MODE_LONG_LIST);
  318: 			else
  319: 			    usage_excl(1);
  320: 		    }
  321: 		    mode = MODE_LIST;
  322: 		    valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
  323: 		    break;
  324: 		case 'n':
  325: 		    SET(flags, MODE_NONINTERACTIVE);
  326: 		    sudo_settings[ARG_NONINTERACTIVE].value = "true";
  327: 		    break;
  328: 		case 'P':
  329: 		    sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
  330: 		    break;
  331: 		case 'p':
  332: 		    sudo_settings[ARG_PROMPT].value = optarg;
  333: 		    break;
  334: #ifdef HAVE_SELINUX
  335: 		case 'r':
  336: 		    sudo_settings[ARG_SELINUX_ROLE].value = optarg;
  337: 		    break;
  338: 		case 't':
  339: 		    sudo_settings[ARG_SELINUX_TYPE].value = optarg;
  340: 		    break;
  341: #endif
  342: 		case 'S':
  343: 		    SET(tgetpass_flags, TGP_STDIN);
  344: 		    break;
  345: 		case 's':
  346: 		    sudo_settings[ARG_USER_SHELL].value = "true";
  347: 		    SET(flags, MODE_SHELL);
  348: 		    break;
  349: 		case 'U':
  350: 		    list_user = optarg;
  351: 		    break;
  352: 		case 'u':
  353: 		    runas_user = optarg;
  354: 		    sudo_settings[ARG_RUNAS_USER].value = optarg;
  355: 		    break;
  356: 		case 'v':
  357: 		    if (mode && mode != MODE_VALIDATE)
  358: 			usage_excl(1);
  359: 		    mode = MODE_VALIDATE;
  360: 		    valid_flags = MODE_NONINTERACTIVE;
  361: 		    break;
  362: 		case 'V':
  363: 		    if (mode && mode != MODE_VERSION)
  364: 			usage_excl(1);
  365: 		    mode = MODE_VERSION;
  366: 		    valid_flags = 0;
  367: 		    break;
  368: 		default:
  369: 		    usage(1);
  370: 	    }
  371: 	} else if (!got_end_of_args && is_envar) {
  372: 	    if (nenv == env_size - 2) {
  373: 		env_size *= 2;
  374: 		env_add = erealloc3(env_add, env_size, sizeof(char *));
  375: 	    }
  376: 	    env_add[nenv++] = argv[optind];
  377: 
  378: 	    /* Crank optind and resume getopt. */
  379: 	    optind++;
  380: 	} else {
  381: 	    /* Not an option or an environment variable -- we're done. */
  382: 	    break;
  383: 	}
  384:     }
  385:     env_add[nenv] = NULL;
  386: 
  387:     argc -= optind;
  388:     argv += optind;
  389: 
  390:     if (!mode) {
  391: 	/* Defer -k mode setting until we know whether it is a flag or not */
  392: 	if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
  393: 	    if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) {
  394: 		mode = MODE_INVALIDATE;	/* -k by itself */
  395: 		sudo_settings[ARG_IGNORE_TICKET].value = NULL;
  396: 		valid_flags = 0;
  397: 	    }
  398: 	}
  399: 	if (!mode)
  400: 	    mode = MODE_RUN;		/* running a command */
  401:     }
  402: 
  403:     if (argc > 0 && mode == MODE_LIST)
  404: 	mode = MODE_CHECK;
  405: 
  406:     if (ISSET(flags, MODE_LOGIN_SHELL)) {
  407: 	if (ISSET(flags, MODE_SHELL)) {
  408: 	    warningx(U_("you may not specify both the `-i' and `-s' options"));
  409: 	    usage(1);
  410: 	}
  411: 	if (ISSET(flags, MODE_PRESERVE_ENV)) {
  412: 	    warningx(U_("you may not specify both the `-i' and `-E' options"));
  413: 	    usage(1);
  414: 	}
  415: 	SET(flags, MODE_SHELL);
  416:     }
  417:     if ((flags & valid_flags) != flags)
  418: 	usage(1);
  419:     if (mode == MODE_EDIT &&
  420:        (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
  421: 	if (ISSET(mode, MODE_PRESERVE_ENV))
  422: 	    warningx(U_("the `-E' option is not valid in edit mode"));
  423: 	if (env_add[0] != NULL)
  424: 	    warningx(U_("you may not specify environment variables in edit mode"));
  425: 	usage(1);
  426:     }
  427:     if ((runas_user != NULL || runas_group != NULL) &&
  428: 	!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
  429: 	usage(1);
  430:     }
  431:     if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
  432: 	warningx(U_("the `-U' option may only be used with the `-l' option"));
  433: 	usage(1);
  434:     }
  435:     if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
  436: 	warningx(U_("the `-A' and `-S' options may not be used together"));
  437: 	usage(1);
  438:     }
  439:     if ((argc == 0 && mode == MODE_EDIT) ||
  440: 	(argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
  441: 	usage(1);
  442:     if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
  443: 	SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
  444: 	sudo_settings[ARG_IMPLIED_SHELL].value = "true";
  445:     }
  446: 
  447:     if (mode == MODE_HELP)
  448: 	help();
  449: 
  450:     /*
  451:      * For shell mode we need to rewrite argv
  452:      */
  453:     if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
  454: 	char **av, *cmnd = NULL;
  455: 	int ac = 1;
  456: 
  457: 	if (argc != 0) {
  458: 	    /* shell -c "command" */
  459: 	    char *src, *dst;
  460: 	    size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
  461: 		strlen(argv[argc - 1]) + 1;
  462: 
  463: 	    cmnd = dst = emalloc2(cmnd_size, 2);
  464: 	    for (av = argv; *av != NULL; av++) {
  465: 		for (src = *av; *src != '\0'; src++) {
  466: 		    /* quote potential meta characters */
  467: 		    if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
  468: 			*dst++ = '\\';
  469: 		    *dst++ = *src;
  470: 		}
  471: 		*dst++ = ' ';
  472: 	    }
  473: 	    if (cmnd != dst)
  474: 		dst--;  /* replace last space with a NUL */
  475: 	    *dst = '\0';
  476: 
  477: 	    ac += 2; /* -c cmnd */
  478: 	}
  479: 
  480: 	av = emalloc2(ac + 1, sizeof(char *));
  481: 	av[0] = (char *)user_details.shell; /* plugin may override shell */
  482: 	if (cmnd != NULL) {
  483: 	    av[1] = "-c";
  484: 	    av[2] = cmnd;
  485: 	}
  486: 	av[ac] = NULL;
  487: 
  488: 	argv = av;
  489: 	argc = ac;
  490:     }
  491: 
  492:     /*
  493:      * Format setting_pairs into settings array.
  494:      */
  495: #ifdef _PATH_SUDO_PLUGIN_DIR
  496:     sudo_settings[ARG_PLUGIN_DIR].value = sudo_conf_plugin_dir_path();
  497: #endif
  498:     settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
  499:     for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
  500: 	if (sudo_settings[i].value) {
  501: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s=%s",
  502: 		sudo_settings[i].name, sudo_settings[i].value);
  503: 	    settings[j] = fmt_string(sudo_settings[i].name,
  504: 		sudo_settings[i].value);
  505: 	    if (settings[j] == NULL)
  506: 		fatal(NULL);
  507: 	    j++;
  508: 	}
  509:     }
  510:     settings[j] = NULL;
  511: 
  512:     if (mode == MODE_EDIT) {
  513: #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
  514: 	/* Must have the command in argv[0]. */
  515: 	argc++;
  516: 	argv--;
  517: 	argv[0] = "sudoedit";
  518: #else
  519: 	fatalx(U_("sudoedit is not supported on this platform"));
  520: #endif
  521:     }
  522: 
  523:     *settingsp = settings;
  524:     *env_addp = env_add;
  525:     *nargc = argc;
  526:     *nargv = argv;
  527:     debug_return_int(mode | flags);
  528: }
  529: 
  530: static int
  531: usage_err(const char *buf)
  532: {
  533:     return fputs(buf, stderr);
  534: }
  535: 
  536: static int
  537: usage_out(const char *buf)
  538: {
  539:     return fputs(buf, stdout);
  540: }
  541: 
  542: /*
  543:  * Give usage message and exit.
  544:  * The actual usage strings are in sudo_usage.h for configure substitution.
  545:  */
  546: void
  547: usage(int fatal)
  548: {
  549:     struct lbuf lbuf;
  550:     char *uvec[6];
  551:     int i, ulen;
  552: 
  553:     /*
  554:      * Use usage vectors appropriate to the progname.
  555:      */
  556:     if (strcmp(getprogname(), "sudoedit") == 0) {
  557: 	uvec[0] = SUDO_USAGE5 + 3;
  558: 	uvec[1] = NULL;
  559:     } else {
  560: 	uvec[0] = SUDO_USAGE1;
  561: 	uvec[1] = SUDO_USAGE2;
  562: 	uvec[2] = SUDO_USAGE3;
  563: 	uvec[3] = SUDO_USAGE4;
  564: 	uvec[4] = SUDO_USAGE5;
  565: 	uvec[5] = NULL;
  566:     }
  567: 
  568:     /*
  569:      * Print usage and wrap lines as needed, depending on the
  570:      * tty width.
  571:      */
  572:     ulen = (int)strlen(getprogname()) + 8;
  573:     lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL,
  574: 	user_details.ts_cols);
  575:     for (i = 0; uvec[i] != NULL; i++) {
  576: 	lbuf_append(&lbuf, "usage: %s%s", getprogname(), uvec[i]);
  577: 	lbuf_print(&lbuf);
  578:     }
  579:     lbuf_destroy(&lbuf);
  580:     if (fatal)
  581: 	exit(1);
  582: }
  583: 
  584: /*
  585:  * Tell which options are mutually exclusive and exit.
  586:  */
  587: static void
  588: usage_excl(int fatal)
  589: {
  590:     debug_decl(usage_excl, SUDO_DEBUG_ARGS)
  591: 
  592:     warningx(U_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
  593:     usage(fatal);
  594: }
  595: 
  596: static void
  597: help(void)
  598: {
  599:     struct lbuf lbuf;
  600:     const int indent = 30;
  601:     const char *pname = getprogname();
  602:     debug_decl(help, SUDO_DEBUG_ARGS)
  603: 
  604:     lbuf_init(&lbuf, usage_out, indent, NULL, user_details.ts_cols);
  605:     if (strcmp(pname, "sudoedit") == 0)
  606: 	lbuf_append(&lbuf, _("%s - edit files as another user\n\n"), pname);
  607:     else
  608: 	lbuf_append(&lbuf, _("%s - execute a command as another user\n\n"), pname);
  609:     lbuf_print(&lbuf);
  610: 
  611:     usage(0);
  612: 
  613:     lbuf_append(&lbuf, _("\nOptions:\n"));
  614:     lbuf_append(&lbuf, "  -A, --askpass               %s\n",
  615: 	_("use a helper program for password prompting"));
  616: #ifdef HAVE_BSD_AUTH_H
  617:     lbuf_append(&lbuf, "  -a, --auth-type=type   %s\n",
  618: 	_("use specified BSD authentication type"));
  619: #endif
  620:     lbuf_append(&lbuf, "  -b, --background            %s\n",
  621: 	_("run command in the background"));
  622:     lbuf_append(&lbuf, "  -C, --close-from=num        %s\n",
  623: 	_("close all file descriptors >= num"));
  624: #ifdef HAVE_LOGIN_CAP_H
  625:     lbuf_append(&lbuf, "  -c, --login-class=class     %s\n",
  626: 	_("run command with the specified BSD login class"));
  627: #endif
  628:     lbuf_append(&lbuf, "  -E, --preserve-env          %s\n",
  629: 	_("preserve user environment when running command"));
  630:     lbuf_append(&lbuf, "  -e, --edit                  %s\n",
  631: 	_("edit files instead of running a command"));
  632:     lbuf_append(&lbuf, "  -g, --group=group           %s\n",
  633: 	_("run command as the specified group name or ID"));
  634:     lbuf_append(&lbuf, "  -H, --set-home              %s\n",
  635: 	_("set HOME variable to target user's home dir"));
  636:     lbuf_append(&lbuf, "  -h, --help                  %s\n",
  637: 	_("display help message and exit"));
  638:     lbuf_append(&lbuf, "  -h, --host=host             %s\n",
  639: 	_("run command on host (if supported by plugin)"));
  640:     lbuf_append(&lbuf, "  -i, --login                 %s\n",
  641: 	_("run login shell as the target user; a command may also be specified"));
  642:     lbuf_append(&lbuf, "  -K, --remove-timestamp      %s\n",
  643: 	_("remove timestamp file completely"));
  644:     lbuf_append(&lbuf, "  -k, --reset-timestamp       %s\n",
  645: 	_("invalidate timestamp file"));
  646:     lbuf_append(&lbuf, "  -l, --list                  %s\n",
  647: 	_("list user's privileges or check a specific command; use twice for longer format"));
  648:     lbuf_append(&lbuf, "  -n, --non-interactive       %s\n",
  649: 	_("non-interactive mode, no prompts are used"));
  650:     lbuf_append(&lbuf, "  -P, --preserve-groups       %s\n",
  651: 	_("preserve group vector instead of setting to target's"));
  652:     lbuf_append(&lbuf, "  -p, --prompt=prompt         %s\n",
  653: 	_("use the specified password prompt"));
  654: #ifdef HAVE_SELINUX
  655:     lbuf_append(&lbuf, "  -r, --role=role             %s\n",
  656: 	_("create SELinux security context with specified role"));
  657: #endif
  658:     lbuf_append(&lbuf, "  -S, --stdin                 %s\n",
  659: 	_("read password from standard input"));
  660:     lbuf_append(&lbuf, "  -s, --shell                 %s\n",
  661: 	_("run shell as the target user; a command may also be specified"));
  662: #ifdef HAVE_SELINUX
  663:     lbuf_append(&lbuf, "  -t, --type=type             %s\n",
  664: 	_("create SELinux security context with specified type"));
  665: #endif
  666:     lbuf_append(&lbuf, "  -U, --other-user=user       %s\n",
  667: 	_("in list mode, display privileges for user"));
  668:     lbuf_append(&lbuf, "  -u, --user=user             %s\n",
  669: 	_("run command (or edit file) as specified user name or ID"));
  670:     lbuf_append(&lbuf, "  -V, --version               %s\n",
  671: 	_("display version information and exit"));
  672:     lbuf_append(&lbuf, "  -v, --validate              %s\n",
  673: 	_("update user's timestamp without running a command"));
  674:     lbuf_append(&lbuf, "  --                          %s\n",
  675: 	_("stop processing command line arguments"));
  676:     lbuf_print(&lbuf);
  677:     lbuf_destroy(&lbuf);
  678:     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 0);
  679:     exit(0);
  680: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>