Annotation of embedaddon/sudo/plugins/sudoers/policy.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (c) 2010-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: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/types.h>
                     20: #include <sys/stat.h>
                     21: #include <netinet/in.h>
                     22: #include <stdio.h>
                     23: #ifdef STDC_HEADERS
                     24: # include <stdlib.h>
                     25: # include <stddef.h>
                     26: #else
                     27: # ifdef HAVE_STDLIB_H
                     28: #  include <stdlib.h>
                     29: # endif
                     30: #endif /* STDC_HEADERS */
                     31: #ifdef HAVE_STRING_H
                     32: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     33: #  include <memory.h>
                     34: # endif
                     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: #include <errno.h>
                     44: #include <grp.h>
                     45: #include <pwd.h>
                     46: 
                     47: #include "sudoers.h"
                     48: #include "sudoers_version.h"
                     49: #include "interfaces.h"
                     50: 
                     51: /*
                     52:  * Info passed in from the sudo front-end.
                     53:  */
                     54: struct sudoers_policy_open_info {
                     55:     char * const *settings;
                     56:     char * const *user_info;
                     57:     char * const *plugin_args;
                     58: };
                     59: 
                     60: /*
                     61:  * Command execution args to be filled in: argv, envp and command info.
                     62:  */
                     63: struct sudoers_exec_args {
                     64:     char ***argv;
                     65:     char ***envp;
                     66:     char ***info;
                     67: };
                     68: 
                     69: static int sudo_version;
                     70: static const char *interfaces_string;
                     71: sudo_conv_t sudo_conv;
                     72: const char *path_ldap_conf = _PATH_LDAP_CONF;
                     73: const char *path_ldap_secret = _PATH_LDAP_SECRET;
                     74: 
                     75: extern __dso_public struct policy_plugin sudoers_policy;
                     76: 
                     77: #ifdef HAVE_BSD_AUTH_H
                     78: extern char *login_style;
                     79: #endif /* HAVE_BSD_AUTH_H */
                     80: 
                     81: /*
                     82:  * Deserialize args, settings and user_info arrays.
                     83:  * Fills in struct sudo_user and other common sudoers state.
                     84:  */
                     85: int
                     86: sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group)
                     87: {
                     88:     struct sudoers_policy_open_info *info = v;
                     89:     char * const *cur;
1.1.1.2 ! misho      90:     const char *p, *errstr, *groups = NULL;
1.1       misho      91:     const char *debug_flags = NULL;
1.1.1.2 ! misho      92:     const char *remhost = NULL;
1.1       misho      93:     int flags = 0;
1.1.1.2 ! misho      94:     long lval;
        !            95:     char *ep;
1.1       misho      96:     debug_decl(sudoers_policy_deserialize_info, SUDO_DEBUG_PLUGIN)
                     97: 
                     98: #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
                     99: 
                    100:     /* Parse sudo.conf plugin args. */
                    101:     if (info->plugin_args != NULL) {
                    102:        for (cur = info->plugin_args; *cur != NULL; cur++) {
                    103:            if (MATCHES(*cur, "sudoers_file=")) {
                    104:                sudoers_file = *cur + sizeof("sudoers_file=") - 1;
                    105:                continue;
                    106:            }
                    107:            if (MATCHES(*cur, "sudoers_uid=")) {
1.1.1.2 ! misho     108:                p = *cur + sizeof("sudoers_uid=") - 1;
        !           109:                sudoers_uid = (uid_t) atoid(p, NULL, NULL, &errstr);
        !           110:                if (errstr != NULL)
        !           111:                    fatalx(_("%s: %s"), *cur, _(errstr));
1.1       misho     112:                continue;
                    113:            }
                    114:            if (MATCHES(*cur, "sudoers_gid=")) {
1.1.1.2 ! misho     115:                p = *cur + sizeof("sudoers_gid=") - 1;
        !           116:                sudoers_gid = (gid_t) atoid(p, NULL, NULL, &errstr);
        !           117:                if (errstr != NULL)
        !           118:                    fatalx(_("%s: %s"), *cur, _(errstr));
1.1       misho     119:                continue;
                    120:            }
                    121:            if (MATCHES(*cur, "sudoers_mode=")) {
1.1.1.2 ! misho     122:                errno = 0;
        !           123:                p = *cur + sizeof("sudoers_mode=") - 1;
        !           124:                lval = strtol(p, &ep, 8);
        !           125:                if (*p == '\0' || *ep != '\0')
        !           126:                    fatalx(_("%s: %s"), *cur, _("invalid value"));
        !           127:                if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
        !           128:                    || (lval > 0777 || lval < 0))
        !           129:                    fatalx(_("%s: %s"), *cur, _("value out of range"));
        !           130:                sudoers_mode = (mode_t) lval;
1.1       misho     131:                continue;
                    132:            }
                    133:            if (MATCHES(*cur, "ldap_conf=")) {
                    134:                path_ldap_conf = *cur + sizeof("ldap_conf=") - 1;
                    135:                continue;
                    136:            }
                    137:            if (MATCHES(*cur, "ldap_secret=")) {
                    138:                path_ldap_secret = *cur + sizeof("ldap_secret=") - 1;
                    139:                continue;
                    140:            }
                    141:        }
                    142:     }
                    143: 
                    144:     /* Parse command line settings. */
                    145:     user_closefrom = -1;
                    146:     for (cur = info->settings; *cur != NULL; cur++) {
                    147:        if (MATCHES(*cur, "closefrom=")) {
1.1.1.2 ! misho     148:            errno = 0;
        !           149:            p = *cur + sizeof("closefrom=") - 1;
        !           150:            lval = strtol(p, &ep, 10);
        !           151:            if (*p == '\0' || *ep != '\0')
        !           152:                fatalx(_("%s: %s"), *cur, _("invalid value"));
        !           153:            if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
        !           154:                || (lval > INT_MAX || lval < 3))
        !           155:                fatalx(_("%s: %s"), *cur, _("value out of range"));
        !           156:            user_closefrom = (int) lval;
1.1       misho     157:            continue;
                    158:        }
                    159:        if (MATCHES(*cur, "debug_flags=")) {
                    160:            debug_flags = *cur + sizeof("debug_flags=") - 1;
                    161:            continue;
                    162:        }
                    163:        if (MATCHES(*cur, "runas_user=")) {
                    164:            *runas_user = *cur + sizeof("runas_user=") - 1;
                    165:            sudo_user.flags |= RUNAS_USER_SPECIFIED;
                    166:            continue;
                    167:        }
                    168:        if (MATCHES(*cur, "runas_group=")) {
                    169:            *runas_group = *cur + sizeof("runas_group=") - 1;
                    170:            sudo_user.flags |= RUNAS_GROUP_SPECIFIED;
                    171:            continue;
                    172:        }
                    173:        if (MATCHES(*cur, "prompt=")) {
                    174:            user_prompt = *cur + sizeof("prompt=") - 1;
                    175:            def_passprompt_override = true;
                    176:            continue;
                    177:        }
                    178:        if (MATCHES(*cur, "set_home=")) {
                    179:            if (atobool(*cur + sizeof("set_home=") - 1) == true)
                    180:                SET(flags, MODE_RESET_HOME);
                    181:            continue;
                    182:        }
                    183:        if (MATCHES(*cur, "preserve_environment=")) {
                    184:            if (atobool(*cur + sizeof("preserve_environment=") - 1) == true)
                    185:                SET(flags, MODE_PRESERVE_ENV);
                    186:            continue;
                    187:        }
                    188:        if (MATCHES(*cur, "run_shell=")) {
                    189:            if (atobool(*cur + sizeof("run_shell=") - 1) == true)
                    190:                SET(flags, MODE_SHELL);
                    191:            continue;
                    192:        }
                    193:        if (MATCHES(*cur, "login_shell=")) {
                    194:            if (atobool(*cur + sizeof("login_shell=") - 1) == true) {
                    195:                SET(flags, MODE_LOGIN_SHELL);
                    196:                def_env_reset = true;
                    197:            }
                    198:            continue;
                    199:        }
                    200:        if (MATCHES(*cur, "implied_shell=")) {
                    201:            if (atobool(*cur + sizeof("implied_shell=") - 1) == true)
                    202:                SET(flags, MODE_IMPLIED_SHELL);
                    203:            continue;
                    204:        }
                    205:        if (MATCHES(*cur, "preserve_groups=")) {
                    206:            if (atobool(*cur + sizeof("preserve_groups=") - 1) == true)
                    207:                SET(flags, MODE_PRESERVE_GROUPS);
                    208:            continue;
                    209:        }
                    210:        if (MATCHES(*cur, "ignore_ticket=")) {
                    211:            if (atobool(*cur + sizeof("ignore_ticket=") - 1) == true)
                    212:                SET(flags, MODE_IGNORE_TICKET);
                    213:            continue;
                    214:        }
                    215:        if (MATCHES(*cur, "noninteractive=")) {
                    216:            if (atobool(*cur + sizeof("noninteractive=") - 1) == true)
                    217:                SET(flags, MODE_NONINTERACTIVE);
                    218:            continue;
                    219:        }
                    220:        if (MATCHES(*cur, "sudoedit=")) {
                    221:            if (atobool(*cur + sizeof("sudoedit=") - 1) == true)
                    222:                SET(flags, MODE_EDIT);
                    223:            continue;
                    224:        }
                    225:        if (MATCHES(*cur, "login_class=")) {
                    226:            login_class = *cur + sizeof("login_class=") - 1;
                    227:            def_use_loginclass = true;
                    228:            continue;
                    229:        }
                    230: #ifdef HAVE_PRIV_SET
                    231:        if (MATCHES(*cur, "runas_privs=")) {
                    232:            def_privs = *cur + sizeof("runas_privs=") - 1;
                    233:            continue;
                    234:        }
                    235:        if (MATCHES(*cur, "runas_limitprivs=")) {
                    236:            def_limitprivs = *cur + sizeof("runas_limitprivs=") - 1;
                    237:            continue;
                    238:        }
                    239: #endif /* HAVE_PRIV_SET */
                    240: #ifdef HAVE_SELINUX
                    241:        if (MATCHES(*cur, "selinux_role=")) {
                    242:            user_role = *cur + sizeof("selinux_role=") - 1;
                    243:            continue;
                    244:        }
                    245:        if (MATCHES(*cur, "selinux_type=")) {
                    246:            user_type = *cur + sizeof("selinux_type=") - 1;
                    247:            continue;
                    248:        }
                    249: #endif /* HAVE_SELINUX */
                    250: #ifdef HAVE_BSD_AUTH_H
                    251:        if (MATCHES(*cur, "bsdauth_type=")) {
                    252:            login_style = *cur + sizeof("bsdauth_type=") - 1;
                    253:            continue;
                    254:        }
                    255: #endif /* HAVE_BSD_AUTH_H */
                    256: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
                    257:        if (MATCHES(*cur, "progname=")) {
                    258:            setprogname(*cur + sizeof("progname=") - 1);
                    259:            continue;
                    260:        }
                    261: #endif
                    262:        if (MATCHES(*cur, "network_addrs=")) {
                    263:            interfaces_string = *cur + sizeof("network_addrs=") - 1;
                    264:            set_interfaces(interfaces_string);
                    265:            continue;
                    266:        }
                    267:        if (MATCHES(*cur, "max_groups=")) {
1.1.1.2 ! misho     268:            errno = 0;
        !           269:            p = *cur + sizeof("max_groups=") - 1;
        !           270:            lval = strtol(p, &ep, 10);
        !           271:            if (*p == '\0' || *ep != '\0')
        !           272:                fatalx(_("%s: %s"), *cur, _("invalid value"));
        !           273:            if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
        !           274:                || (lval > INT_MAX || lval <= 0))
        !           275:                fatalx(_("%s: %s"), *cur, _("value out of range"));
        !           276:            sudo_user.max_groups = (int) lval;
        !           277:            continue;
        !           278:        }
        !           279:        if (MATCHES(*cur, "remote_host=")) {
        !           280:            remhost = *cur + sizeof("remote_host=") - 1;
1.1       misho     281:            continue;
                    282:        }
                    283:     }
                    284: 
                    285:     for (cur = info->user_info; *cur != NULL; cur++) {
                    286:        if (MATCHES(*cur, "user=")) {
                    287:            user_name = estrdup(*cur + sizeof("user=") - 1);
                    288:            continue;
                    289:        }
                    290:        if (MATCHES(*cur, "uid=")) {
1.1.1.2 ! misho     291:            p = *cur + sizeof("uid=") - 1;
        !           292:            user_uid = (uid_t) atoid(p, NULL, NULL, &errstr);
        !           293:            if (errstr != NULL)
        !           294:                fatalx(_("%s: %s"), *cur, _(errstr));
1.1       misho     295:            continue;
                    296:        }
                    297:        if (MATCHES(*cur, "gid=")) {
                    298:            p = *cur + sizeof("gid=") - 1;
1.1.1.2 ! misho     299:            user_gid = (gid_t) atoid(p, NULL, NULL, &errstr);
        !           300:            if (errstr != NULL)
        !           301:                fatalx(_("%s: %s"), *cur, _(errstr));
1.1       misho     302:            continue;
                    303:        }
                    304:        if (MATCHES(*cur, "groups=")) {
                    305:            groups = *cur + sizeof("groups=") - 1;
                    306:            continue;
                    307:        }
                    308:        if (MATCHES(*cur, "cwd=")) {
                    309:            user_cwd = estrdup(*cur + sizeof("cwd=") - 1);
                    310:            continue;
                    311:        }
                    312:        if (MATCHES(*cur, "tty=")) {
                    313:            user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1);
                    314:            if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                    315:                user_tty += sizeof(_PATH_DEV) - 1;
                    316:            continue;
                    317:        }
                    318:        if (MATCHES(*cur, "host=")) {
                    319:            user_host = user_shost = estrdup(*cur + sizeof("host=") - 1);
                    320:            if ((p = strchr(user_host, '.')))
                    321:                user_shost = estrndup(user_host, (size_t)(p - user_host));
                    322:            continue;
                    323:        }
                    324:        if (MATCHES(*cur, "lines=")) {
1.1.1.2 ! misho     325:            errno = 0;
        !           326:            p = *cur + sizeof("lines=") - 1;
        !           327:            lval = strtol(p, &ep, 10);
        !           328:            if (*p == '\0' || *ep != '\0')
        !           329:                fatalx(_("%s: %s"), *cur, _("invalid value"));
        !           330:            if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
        !           331:                || (lval > INT_MAX || lval <= 0))
        !           332:                fatalx(_("%s: %s"), *cur, _("value out of range"));
        !           333:            sudo_user.lines = (int) lval;
1.1       misho     334:            continue;
                    335:        }
                    336:        if (MATCHES(*cur, "cols=")) {
1.1.1.2 ! misho     337:            errno = 0;
        !           338:            p = *cur + sizeof("cols=") - 1;
        !           339:            lval = strtol(p, &ep, 10);
        !           340:            if (*p == '\0' || *ep != '\0')
        !           341:                fatalx(_("%s: %s"), *cur, _("invalid value"));
        !           342:            if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
        !           343:                || (lval > INT_MAX || lval <= 0))
        !           344:                fatalx(_("%s: %s"), *cur, _("value out of range"));
        !           345:            sudo_user.cols = (int) lval;
1.1       misho     346:            continue;
                    347:        }
                    348:        if (MATCHES(*cur, "sid=")) {
1.1.1.2 ! misho     349:            p = *cur + sizeof("sid=") - 1;
        !           350:            sudo_user.sid = (pid_t) atoid(p, NULL, NULL, &errstr);
        !           351:            if (errstr != NULL)
        !           352:                fatalx(_("%s: %s"), *cur, _(errstr));
1.1       misho     353:            continue;
                    354:        }
                    355:     }
1.1.1.2 ! misho     356:     user_runhost = user_srunhost = estrdup(remhost ? remhost : user_host);
        !           357:     if ((p = strchr(user_runhost, '.')))
        !           358:        user_srunhost = estrndup(user_runhost, (size_t)(p - user_runhost));
1.1       misho     359:     if (user_cwd == NULL)
                    360:        user_cwd = "unknown";
                    361:     if (user_tty == NULL)
                    362:        user_tty = "unknown"; /* user_ttypath remains NULL */
                    363: 
                    364:     if (groups != NULL && groups[0] != '\0') {
1.1.1.2 ! misho     365:        /* parse_gid_list() will call fatalx() on error. */
        !           366:        user_ngids = parse_gid_list(groups, &user_gid, &user_gids);
1.1       misho     367:     }
                    368: 
                    369:     /* Stash initial umask for later use. */
                    370:     user_umask = umask(SUDO_UMASK);
                    371:     umask(user_umask);
                    372: 
                    373:     /* Setup debugging if indicated. */
                    374:     if (debug_flags != NULL) {
                    375:        sudo_debug_init(NULL, debug_flags);
                    376:        for (cur = info->settings; *cur != NULL; cur++)
                    377:            sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur);
                    378:        for (cur = info->user_info; *cur != NULL; cur++)
                    379:            sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur);
                    380:     }
                    381: 
                    382: #undef MATCHES
                    383:     debug_return_int(flags);
                    384: }
                    385: 
                    386: /*
                    387:  * Setup the execution environment.
                    388:  * Builds up the command_info list and sets argv and envp.
                    389:  * Returns 1 on success and -1 on error.
                    390:  */
                    391: int
                    392: sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
                    393:     char *iolog_path, void *v)
                    394: {
                    395:     struct sudoers_exec_args *exec_args = v;
                    396:     char **command_info;
                    397:     int info_len = 0;
                    398:     debug_decl(sudoers_policy_exec_setup, SUDO_DEBUG_PLUGIN)
                    399: 
                    400:     /* Increase the length of command_info as needed, it is *not* checked. */
                    401:     command_info = ecalloc(32, sizeof(char **));
                    402: 
                    403:     command_info[info_len++] = fmt_string("command", safe_cmnd);
                    404:     if (def_log_input || def_log_output) {
                    405:        if (iolog_path)
                    406:            command_info[info_len++] = iolog_path;
                    407:        if (def_log_input) {
                    408:            command_info[info_len++] = estrdup("iolog_stdin=true");
                    409:            command_info[info_len++] = estrdup("iolog_ttyin=true");
                    410:        }
                    411:        if (def_log_output) {
                    412:            command_info[info_len++] = estrdup("iolog_stdout=true");
                    413:            command_info[info_len++] = estrdup("iolog_stderr=true");
                    414:            command_info[info_len++] = estrdup("iolog_ttyout=true");
                    415:        }
                    416:        if (def_compress_io) {
                    417:            command_info[info_len++] = estrdup("iolog_compress=true");
                    418:        }
                    419:        if (def_maxseq) {
                    420:            easprintf(&command_info[info_len++], "maxseq=%u", def_maxseq);
                    421:        }
                    422:     }
                    423:     if (ISSET(sudo_mode, MODE_EDIT))
                    424:        command_info[info_len++] = estrdup("sudoedit=true");
                    425:     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
                    426:        /* Set cwd to run user's homedir. */
                    427:        command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);
                    428:     }
                    429:     if (def_stay_setuid) {
                    430:        easprintf(&command_info[info_len++], "runas_uid=%u",
                    431:            (unsigned int)user_uid);
                    432:        easprintf(&command_info[info_len++], "runas_gid=%u",
                    433:            (unsigned int)user_gid);
                    434:        easprintf(&command_info[info_len++], "runas_euid=%u",
                    435:            (unsigned int)runas_pw->pw_uid);
                    436:        easprintf(&command_info[info_len++], "runas_egid=%u",
                    437:            runas_gr ? (unsigned int)runas_gr->gr_gid :
                    438:            (unsigned int)runas_pw->pw_gid);
                    439:     } else {
                    440:        easprintf(&command_info[info_len++], "runas_uid=%u",
                    441:            (unsigned int)runas_pw->pw_uid);
                    442:        easprintf(&command_info[info_len++], "runas_gid=%u",
                    443:            runas_gr ? (unsigned int)runas_gr->gr_gid :
                    444:            (unsigned int)runas_pw->pw_gid);
                    445:     }
                    446:     if (def_preserve_groups) {
                    447:        command_info[info_len++] = "preserve_groups=true";
                    448:     } else {
                    449:        int i, len;
                    450:        gid_t egid;
                    451:        size_t glsize;
                    452:        char *cp, *gid_list;
                    453:        struct group_list *grlist = sudo_get_grlist(runas_pw);
                    454: 
                    455:        /* We reserve an extra spot in the list for the effective gid. */
                    456:        glsize = sizeof("runas_groups=") - 1 +
                    457:            ((grlist->ngids + 1) * (MAX_UID_T_LEN + 1));
                    458:        gid_list = emalloc(glsize);
                    459:        memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
                    460:        cp = gid_list + sizeof("runas_groups=") - 1;
                    461: 
                    462:        /* On BSD systems the effective gid is the first group in the list. */
                    463:        egid = runas_gr ? (unsigned int)runas_gr->gr_gid :
                    464:            (unsigned int)runas_pw->pw_gid;
                    465:        len = snprintf(cp, glsize - (cp - gid_list), "%u", egid);
                    466:        if (len < 0 || len >= glsize - (cp - gid_list))
                    467:            fatalx(_("internal error, %s overflow"), "runas_groups");
                    468:        cp += len;
                    469:        for (i = 0; i < grlist->ngids; i++) {
                    470:            if (grlist->gids[i] != egid) {
                    471:                len = snprintf(cp, glsize - (cp - gid_list), ",%u",
                    472:                     (unsigned int) grlist->gids[i]);
                    473:                if (len < 0 || len >= glsize - (cp - gid_list))
                    474:                    fatalx(_("internal error, %s overflow"), "runas_groups");
                    475:                cp += len;
                    476:            }
                    477:        }
                    478:        command_info[info_len++] = gid_list;
                    479:        sudo_grlist_delref(grlist);
                    480:     }
                    481:     if (def_closefrom >= 0)
                    482:        easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);
                    483:     if (def_noexec)
                    484:        command_info[info_len++] = estrdup("noexec=true");
                    485:     if (def_exec_background)
                    486:        command_info[info_len++] = estrdup("exec_background=true");
                    487:     if (def_set_utmp)
                    488:        command_info[info_len++] = estrdup("set_utmp=true");
                    489:     if (def_use_pty)
                    490:        command_info[info_len++] = estrdup("use_pty=true");
                    491:     if (def_utmp_runas)
                    492:        command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
                    493:     if (cmnd_umask != 0777)
                    494:        easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask);
                    495: #ifdef HAVE_LOGIN_CAP_H
                    496:     if (def_use_loginclass)
                    497:        command_info[info_len++] = fmt_string("login_class", login_class);
                    498: #endif /* HAVE_LOGIN_CAP_H */
                    499: #ifdef HAVE_SELINUX
                    500:     if (user_role != NULL)
                    501:        command_info[info_len++] = fmt_string("selinux_role", user_role);
                    502:     if (user_type != NULL)
                    503:        command_info[info_len++] = fmt_string("selinux_type", user_type);
                    504: #endif /* HAVE_SELINUX */
                    505: #ifdef HAVE_PRIV_SET
                    506:     if (runas_privs != NULL)
                    507:        command_info[info_len++] = fmt_string("runas_privs", runas_privs);
                    508:     if (runas_limitprivs != NULL)
                    509:        command_info[info_len++] = fmt_string("runas_limitprivs", runas_limitprivs);
                    510: #endif /* HAVE_SELINUX */
                    511: 
                    512:     /* Fill in exec environment info */
                    513:     *(exec_args->argv) = argv;
                    514:     *(exec_args->envp) = envp;
                    515:     *(exec_args->info) = command_info;
                    516: 
                    517:     debug_return_bool(true);
                    518: }
                    519: 
                    520: static int
                    521: sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
                    522:     sudo_printf_t plugin_printf, char * const settings[],
                    523:     char * const user_info[], char * const envp[], char * const args[])
                    524: {
                    525:     struct sudoers_policy_open_info info;
                    526:     debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN)
                    527: 
                    528:     sudo_version = version;
                    529:     sudo_conv = conversation;
                    530:     sudo_printf = plugin_printf;
                    531: 
                    532:     /* Plugin args are only specified for API version 1.2 and higher. */
                    533:     if (sudo_version < SUDO_API_MKVERSION(1, 2))
                    534:        args = NULL;
                    535: 
                    536:     if (fatal_setjmp() != 0) {
                    537:        /* called via fatal(), fatalx() or log_fatal() */
                    538:        rewind_perms();
                    539:        fatal_disable_setjmp();
                    540:        debug_return_bool(-1);
                    541:     }
                    542: 
                    543:     /* Call the sudoers init function. */
                    544:     info.settings = settings;
                    545:     info.user_info = user_info;
                    546:     info.plugin_args = args;
                    547:     debug_return_bool(sudoers_policy_init(&info, envp));
                    548: }
                    549: 
                    550: static void
                    551: sudoers_policy_close(int exit_status, int error_code)
                    552: {
                    553:     debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN)
                    554: 
                    555:     if (fatal_setjmp() != 0) {
                    556:        /* called via fatal(), fatalx() or log_fatal() */
                    557:        fatal_disable_setjmp();
                    558:        debug_return;
                    559:     }
                    560: 
                    561:     /* We do not currently log the exit status. */
                    562:     if (error_code) {
                    563:        errno = error_code;
                    564:        warning(_("unable to execute %s"), safe_cmnd);
                    565:     }
                    566: 
                    567:     /* Close the session we opened in sudoers_policy_init_session(). */
                    568:     if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
                    569:        (void)sudo_auth_end_session(runas_pw);
                    570: 
                    571:     /* Free remaining references to password and group entries. */
                    572:     /* XXX - move cleanup to function in sudoers.c */
                    573:     sudo_pw_delref(sudo_user.pw);
                    574:     sudo_user.pw = NULL;
                    575:     sudo_pw_delref(runas_pw);
                    576:     runas_pw = NULL;
                    577:     if (runas_gr != NULL) {
                    578:        sudo_gr_delref(runas_gr);
                    579:        runas_gr = NULL;
                    580:     }
                    581:     if (user_group_list != NULL) {
                    582:        sudo_grlist_delref(user_group_list);
                    583:        user_group_list = NULL;
                    584:     }
                    585:     efree(user_gids);
                    586:     user_gids = NULL;
                    587: 
                    588:     debug_return;
                    589: }
                    590: 
                    591: /*
                    592:  * The init_session function is called before executing the command
                    593:  * and before uid/gid changes occur.
                    594:  * Returns 1 on success, 0 on failure and -1 on error.
                    595:  */
                    596: static int
                    597: sudoers_policy_init_session(struct passwd *pwd, char **user_env[])
                    598: {
                    599:     debug_decl(sudoers_policy_init_session, SUDO_DEBUG_PLUGIN)
                    600: 
                    601:     /* user_env is only specified for API version 1.2 and higher. */
                    602:     if (sudo_version < SUDO_API_MKVERSION(1, 2))
                    603:        user_env = NULL;
                    604: 
                    605:     if (fatal_setjmp() != 0) {
                    606:        /* called via fatal(), fatalx() or log_fatal() */
                    607:        fatal_disable_setjmp();
                    608:        debug_return_bool(-1);
                    609:     }
                    610: 
                    611:     debug_return_bool(sudo_auth_begin_session(pwd, user_env));
                    612: }
                    613: 
                    614: static int
                    615: sudoers_policy_check(int argc, char * const argv[], char *env_add[],
                    616:     char **command_infop[], char **argv_out[], char **user_env_out[])
                    617: {
                    618:     struct sudoers_exec_args exec_args;
                    619:     int rval;
                    620:     debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN)
                    621: 
                    622:     if (!ISSET(sudo_mode, MODE_EDIT))
                    623:        SET(sudo_mode, MODE_RUN);
                    624: 
                    625:     exec_args.argv = argv_out;
                    626:     exec_args.envp = user_env_out;
                    627:     exec_args.info = command_infop;
                    628: 
                    629:     rval = sudoers_policy_main(argc, argv, 0, env_add, &exec_args);
                    630:     if (rval == true && sudo_version >= SUDO_API_MKVERSION(1, 3)) {
                    631:        /* Unset close function if we don't need it to avoid extra process. */
                    632:        if (!def_log_input && !def_log_output && !def_use_pty &&
                    633:            !sudo_auth_needs_end_session())
                    634:            sudoers_policy.close = NULL;
                    635:     }
                    636:     debug_return_bool(rval);
                    637: }
                    638: 
                    639: static int
                    640: sudoers_policy_validate(void)
                    641: {
                    642:     debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN)
                    643: 
                    644:     user_cmnd = "validate";
                    645:     SET(sudo_mode, MODE_VALIDATE);
                    646: 
                    647:     debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL));
                    648: }
                    649: 
                    650: static void
                    651: sudoers_policy_invalidate(int remove)
                    652: {
                    653:     debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN)
                    654: 
                    655:     user_cmnd = "kill";
                    656:     if (fatal_setjmp() == 0) {
                    657:        remove_timestamp(remove);
                    658:        sudoers_cleanup();
                    659:     }
                    660:     fatal_disable_setjmp();
                    661: 
                    662:     debug_return;
                    663: }
                    664: 
                    665: static int
                    666: sudoers_policy_list(int argc, char * const argv[], int verbose,
                    667:     const char *list_user)
                    668: {
                    669:     int rval;
                    670:     debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN)
                    671: 
                    672:     user_cmnd = "list";
                    673:     if (argc)
                    674:        SET(sudo_mode, MODE_CHECK);
                    675:     else
                    676:        SET(sudo_mode, MODE_LIST);
                    677:     if (verbose)
                    678:        long_list = 1;
                    679:     if (list_user) {
                    680:        list_pw = sudo_getpwnam(list_user);
                    681:        if (list_pw == NULL) {
                    682:            warningx(_("unknown user: %s"), list_user);
                    683:            debug_return_bool(-1);
                    684:        }
                    685:     }
                    686:     rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL);
                    687:     if (list_user) {
                    688:        sudo_pw_delref(list_pw);
                    689:        list_pw = NULL;
                    690:     }
                    691: 
                    692:     debug_return_bool(rval);
                    693: }
                    694: 
                    695: static int
                    696: sudoers_policy_version(int verbose)
                    697: {
                    698:     debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN)
                    699: 
                    700:     if (fatal_setjmp() != 0) {
                    701:        /* error recovery via fatal(), fatalx() or log_fatal() */
                    702:        fatal_disable_setjmp();
                    703:        debug_return_bool(-1);
                    704:     }
                    705: 
                    706:     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"),
                    707:        PACKAGE_VERSION);
                    708:     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"),
                    709:        SUDOERS_GRAMMAR_VERSION);
                    710: 
                    711:     if (verbose) {
                    712:        sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file);
                    713: #ifdef HAVE_LDAP
                    714: # ifdef _PATH_NSSWITCH_CONF
                    715:        sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF);
                    716: # endif
                    717:        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), path_ldap_conf);
                    718:        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), path_ldap_secret);
                    719: #endif
                    720:        dump_auth_methods();
                    721:        dump_defaults();
                    722:        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
                    723:        if (interfaces_string != NULL) {
                    724:            dump_interfaces(interfaces_string);
                    725:            sudo_printf(SUDO_CONV_INFO_MSG, "\n");
                    726:        }
                    727:     }
                    728:     debug_return_bool(true);
                    729: }
                    730: 
                    731: static void
                    732: sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook))
                    733: {
                    734:     struct sudo_hook hook;
                    735: 
                    736:     memset(&hook, 0, sizeof(hook));
                    737:     hook.hook_version = SUDO_HOOK_VERSION;
                    738: 
                    739:     hook.hook_type = SUDO_HOOK_SETENV;
                    740:     hook.hook_fn = sudoers_hook_setenv;
                    741:     register_hook(&hook);
                    742: 
                    743:     hook.hook_type = SUDO_HOOK_UNSETENV;
                    744:     hook.hook_fn = sudoers_hook_unsetenv;
                    745:     register_hook(&hook);
                    746: 
                    747:     hook.hook_type = SUDO_HOOK_GETENV;
                    748:     hook.hook_fn = sudoers_hook_getenv;
                    749:     register_hook(&hook);
                    750: 
                    751:     hook.hook_type = SUDO_HOOK_PUTENV;
                    752:     hook.hook_fn = sudoers_hook_putenv;
                    753:     register_hook(&hook);
                    754: }
                    755: 
                    756: __dso_public struct policy_plugin sudoers_policy = {
                    757:     SUDO_POLICY_PLUGIN,
                    758:     SUDO_API_VERSION,
                    759:     sudoers_policy_open,
                    760:     sudoers_policy_close,
                    761:     sudoers_policy_version,
                    762:     sudoers_policy_check,
                    763:     sudoers_policy_list,
                    764:     sudoers_policy_validate,
                    765:     sudoers_policy_invalidate,
                    766:     sudoers_policy_init_session,
                    767:     sudoers_policy_register_hooks
                    768: };

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