Annotation of embedaddon/sudo/src/parse_args.c, revision 1.1.1.6

1.1       misho       1: /*
1.1.1.4   misho       2:  * Copyright (c) 1993-1996, 1998-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       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 */
1.1.1.5   misho      43: #ifdef HAVE_GETOPT_LONG
                     44: # include <getopt.h>
                     45: # else
                     46: # include "compat/getopt.h"
                     47: #endif /* HAVE_GETOPT_LONG */
1.1       misho      48: #include <ctype.h>
                     49: #include <grp.h>
                     50: #include <pwd.h>
                     51: 
1.1.1.5   misho      52: #include <sudo_usage.h>
1.1       misho      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" },
1.1.1.2   misho      75: #define ARG_DEBUG_FLAGS 2
                     76:     { "debug_flags" },
1.1       misho      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" },
1.1.1.4   misho     111: #define ARG_MAX_GROUPS 20
                    112:     { "max_groups" },
                    113: #define ARG_PLUGIN_DIR 21
                    114:     { "plugin_dir" },
1.1.1.5   misho     115: #define ARG_REMOTE_HOST 22
                    116:     { "remote_host" },
                    117: #define NUM_SETTINGS 23
1.1       misho     118:     { NULL }
                    119: };
                    120: 
                    121: /*
1.1.1.5   misho     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: /*
1.1       misho     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 */
1.1.1.5   misho     176:     int valid_flags = DEFAULT_VALID_FLAGS;
                    177:     int ch, i, j;
1.1       misho     178:     char *cp, **env_add, **settings;
1.1.1.5   misho     179:     const char *runas_user = NULL;
                    180:     const char *runas_group = NULL;
1.1.1.2   misho     181:     const char *debug_flags;
1.1       misho     182:     int nenv = 0;
                    183:     int env_size = 32;
1.1.1.2   misho     184:     debug_decl(parse_args, SUDO_DEBUG_ARGS)
1.1       misho     185: 
                    186:     env_add = emalloc2(env_size, sizeof(char *));
                    187: 
1.1.1.6 ! misho     188:     /* Pass progname to plugin so it can call initprogname() */
1.1       misho     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: 
1.1.1.2   misho     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: 
1.1.1.4   misho     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: 
1.1.1.5   misho     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: 
1.1       misho     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:         */
1.1.1.5   misho     231:        if ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
1.1       misho     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':
1.1.1.6 ! misho     245:                    if (strtonum(optarg, 3, INT_MAX, NULL) == 0) {
1.1       misho     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':
1.1.1.2   misho     257:                    /* Ignored for backwards compatibility. */
1.1       misho     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':
1.1.1.5   misho     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;
1.1       misho     295:                    }
1.1.1.5   misho     296:                    /* FALLTHROUGH */
                    297:                case OPT_HOSTNAME:
                    298:                    sudo_settings[ARG_REMOTE_HOST].value = optarg;
1.1       misho     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) {
1.1.1.2   misho     393:            if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) {
1.1       misho     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)) {
1.1.1.6 ! misho     408:            warningx(U_("you may not specify both the `-i' and `-s' options"));
1.1       misho     409:            usage(1);
                    410:        }
                    411:        if (ISSET(flags, MODE_PRESERVE_ENV)) {
1.1.1.6 ! misho     412:            warningx(U_("you may not specify both the `-i' and `-E' options"));
1.1       misho     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))
1.1.1.6 ! misho     422:            warningx(U_("the `-E' option is not valid in edit mode"));
1.1       misho     423:        if (env_add[0] != NULL)
1.1.1.6 ! misho     424:            warningx(U_("you may not specify environment variables in edit mode"));
1.1       misho     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) {
1.1.1.6 ! misho     432:        warningx(U_("the `-U' option may only be used with the `-l' option"));
1.1       misho     433:        usage(1);
                    434:     }
                    435:     if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
1.1.1.6 ! misho     436:        warningx(U_("the `-A' and `-S' options may not be used together"));
1.1       misho     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)) {
1.1.1.3   misho     454:        char **av, *cmnd = NULL;
                    455:        int ac = 1;
1.1       misho     456: 
1.1.1.3   misho     457:        if (argc != 0) {
1.1       misho     458:            /* shell -c "command" */
1.1.1.3   misho     459:            char *src, *dst;
1.1       misho     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 */
1.1.1.5   misho     467:                    if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
1.1       misho     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: 
1.1.1.3   misho     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) {
1.1       misho     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:      */
1.1.1.4   misho     495: #ifdef _PATH_SUDO_PLUGIN_DIR
1.1.1.5   misho     496:     sudo_settings[ARG_PLUGIN_DIR].value = sudo_conf_plugin_dir_path();
1.1.1.4   misho     497: #endif
1.1       misho     498:     settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
                    499:     for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
                    500:        if (sudo_settings[i].value) {
1.1.1.2   misho     501:            sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s=%s",
                    502:                sudo_settings[i].name, sudo_settings[i].value);
1.1       misho     503:            settings[j] = fmt_string(sudo_settings[i].name,
                    504:                sudo_settings[i].value);
                    505:            if (settings[j] == NULL)
1.1.1.5   misho     506:                fatal(NULL);
1.1       misho     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
1.1.1.6 ! misho     519:        fatalx(U_("sudoedit is not supported on this platform"));
1.1       misho     520: #endif
                    521:     }
                    522: 
                    523:     *settingsp = settings;
                    524:     *env_addp = env_add;
                    525:     *nargc = argc;
                    526:     *nargv = argv;
1.1.1.2   misho     527:     debug_return_int(mode | flags);
1.1       misho     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: {
1.1.1.2   misho     590:     debug_decl(usage_excl, SUDO_DEBUG_ARGS)
                    591: 
1.1.1.6 ! misho     592:     warningx(U_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
1.1       misho     593:     usage(fatal);
                    594: }
                    595: 
                    596: static void
                    597: help(void)
                    598: {
                    599:     struct lbuf lbuf;
1.1.1.5   misho     600:     const int indent = 30;
1.1       misho     601:     const char *pname = getprogname();
1.1.1.2   misho     602:     debug_decl(help, SUDO_DEBUG_ARGS)
1.1       misho     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"));
1.1.1.5   misho     614:     lbuf_append(&lbuf, "  -A, --askpass               %s\n",
                    615:        _("use a helper program for password prompting"));
1.1.1.4   misho     616: #ifdef HAVE_BSD_AUTH_H
1.1.1.5   misho     617:     lbuf_append(&lbuf, "  -a, --auth-type=type   %s\n",
                    618:        _("use specified BSD authentication type"));
1.1.1.4   misho     619: #endif
1.1.1.5   misho     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"));
1.1       misho     624: #ifdef HAVE_LOGIN_CAP_H
1.1.1.5   misho     625:     lbuf_append(&lbuf, "  -c, --login-class=class     %s\n",
                    626:        _("run command with the specified BSD login class"));
1.1       misho     627: #endif
1.1.1.5   misho     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"));
1.1       misho     654: #ifdef HAVE_SELINUX
1.1.1.5   misho     655:     lbuf_append(&lbuf, "  -r, --role=role             %s\n",
                    656:        _("create SELinux security context with specified role"));
1.1       misho     657: #endif
1.1.1.5   misho     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"));
1.1       misho     662: #ifdef HAVE_SELINUX
1.1.1.5   misho     663:     lbuf_append(&lbuf, "  -t, --type=type             %s\n",
                    664:        _("create SELinux security context with specified type"));
1.1       misho     665: #endif
1.1.1.5   misho     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"));
1.1       misho     676:     lbuf_print(&lbuf);
                    677:     lbuf_destroy(&lbuf);
1.1.1.2   misho     678:     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 0);
1.1       misho     679:     exit(0);
                    680: }

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