/*
 * Close all descriptors, startfd and higher except those listed
 * in pfds.
 */
void
closefrom_except(int startfd, struct preserved_fd_list *pfds)
{
    int debug_fd, fd, lastfd = -1;
    struct preserved_fd *pfd, *pfd_next;
    fd_set *fdsp;
    debug_decl(closefrom_except, SUDO_DEBUG_UTIL)

    debug_fd = sudo_debug_fd_get();

    /* First, relocate preserved fds to be as contiguous as possible.  */
    TAILQ_FOREACH_REVERSE_SAFE(pfd, pfds, preserved_fd_list, entries, pfd_next) {
        if (pfd->highfd < startfd)
            continue;
        fd = dup(pfd->highfd);
        if (fd == -1) {
            sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
                              "dup %d", pfd->highfd);
            if (errno == EBADF) {
                TAILQ_REMOVE(pfds, pfd, entries);
                continue;
            }
            /* NOTE: still need to adjust lastfd below with unchanged lowfd. */
        } else if (fd < pfd->highfd) {
            pfd->lowfd = fd;
            fd = pfd->highfd;
            if (fd == debug_fd)
                debug_fd = sudo_debug_fd_set(pfd->lowfd);
            sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                              "dup %d -> %d", pfd->highfd, pfd->lowfd);
        }
        if (fd != -1)
            (void) close(fd);

        if (pfd->lowfd > lastfd)
            lastfd = pfd->lowfd;	/* highest (relocated) preserved fd */
    }

    if (lastfd == -1) {
        /* No fds to preserve. */
        sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                          "closefrom(%d)", startfd);
        closefrom(startfd);
        debug_return;
    }

    /* Create bitmap of preserved (relocated) fds.  */
    fdsp = ecalloc(howmany(lastfd + 1, NFDBITS), sizeof(fd_mask));
    TAILQ_FOREACH(pfd, pfds, entries) {
        FD_SET(pfd->lowfd, fdsp);
    }
예제 #2
0
파일: redblack.c 프로젝트: millert/sudo
/*
 * Create a red black tree struct using the specified compare routine.
 * Allocates and returns the initialized (empty) tree or NULL if
 * memory cannot be allocated.
 */
struct rbtree *
rbcreate(int (*compar)(const void *, const void*))
{
    struct rbtree *tree;
    debug_decl(rbcreate, SUDOERS_DEBUG_RBTREE)

    if ((tree = malloc(sizeof(*tree))) == NULL) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "unable to allocate memory");
	debug_return_ptr(NULL);
    }

    tree->compar = compar;

    /*
     * We use a self-referencing sentinel node called nil to simplify the
     * code by avoiding the need to check for NULL pointers.
     */
    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
    tree->nil.color = black;
    tree->nil.data = NULL;

    /*
     * Similarly, the fake root node keeps us from having to worry
     * about splitting the root.
     */
    tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
    tree->root.color = black;
    tree->root.data = NULL;

    debug_return_ptr(tree);
}
예제 #3
0
파일: boottime.c 프로젝트: millert/sudo
bool
get_boottime(struct timespec *ts)
{
    size_t size;
    int mib[2];
    struct timeval tv;
    debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)

    mib[0] = CTL_KERN;
    mib[1] = KERN_BOOTTIME;
    size = sizeof(tv);
    if (sysctl(mib, 2, &tv, &size, NULL, 0) != -1) {
	sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
	    "KERN_BOOTTIME: %lld, %ld", (long long)tv.tv_sec, (long)tv.tv_usec);
	TIMEVAL_TO_TIMESPEC(&tv, ts);
	debug_return_bool(true);
    }

    sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
	"KERN_BOOTTIME: %s", strerror(errno));
    debug_return_bool(false);
}
예제 #4
0
파일: boottime.c 프로젝트: millert/sudo
bool
get_boottime(struct timespec *ts)
{
    char *line = NULL;
    size_t linesize = 0;
    bool found = false;
    long long llval;
    ssize_t len;
    FILE *fp;
    debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)

    /* read btime from /proc/stat */
    fp = fopen("/proc/stat", "r");
    if (fp != NULL) {
	while ((len = getdelim(&line, &linesize, '\n', fp)) != -1) {
	    if (strncmp(line, "btime ", 6) == 0) {
		if (line[len - 1] == '\n')
		    line[len - 1] = '\0';
		llval = strtonum(line + 6, 1, LLONG_MAX, NULL);
		if (llval > 0) {
		    ts->tv_sec = (time_t)llval;
		    ts->tv_nsec = 0;
		    found = true;
		    sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
			"found btime in /proc/stat: %lld", llval);
		    break;
		} else {
		    sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
			"invalid btime in /proc/stat: %s", line);
		}
	    }
	}
	fclose(fp);
	free(line);
    }

    debug_return_bool(found);
}
/*
 * Add an fd to preserve.
 */
int
add_preserved_fd(struct preserved_fd_list *pfds, int fd)
{
    struct preserved_fd *pfd, *pfd_new;
    debug_decl(add_preserved_fd, SUDO_DEBUG_UTIL)

    pfd_new = emalloc(sizeof(*pfd));
    pfd_new->lowfd = fd;
    pfd_new->highfd = fd;
    pfd_new->flags = fcntl(fd, F_GETFD);
    if (pfd_new->flags == -1) {
        efree(pfd_new);
        debug_return_int(-1);
    }

    TAILQ_FOREACH(pfd, pfds, entries) {
        if (fd == pfd->highfd) {
            /* already preserved */
            sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                              "fd %d already preserved", fd);
            efree(pfd_new);
            break;
        }
        if (fd < pfd->highfd) {
            TAILQ_INSERT_BEFORE(pfd, pfd_new, entries);
            sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                              "preserving fd %d", fd);
            break;
        }
    }
    if (pfd == NULL) {
        TAILQ_INSERT_TAIL(pfds, pfd_new, entries);
        sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
                          "preserving fd %d", fd);
    }

    debug_return_int(0);
}
예제 #6
0
/*
 * Take a uid in string form "#123" and return a faked up passwd struct.
 */
struct passwd *
sudo_fakepwnam(const char *user, gid_t gid)
{
    const char *errstr;
    uid_t uid;
    debug_decl(sudo_fakepwnam, SUDOERS_DEBUG_NSS)

    uid = (uid_t) sudo_strtoid(user + 1, NULL, NULL, &errstr);
    if (errstr != NULL) {
	sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG,
	    "uid %s %s", user, errstr);
	debug_return_ptr(NULL);
    }
    debug_return_ptr(sudo_mkpwent(user, uid, gid, NULL, NULL));
}
예제 #7
0
파일: boottime.c 프로젝트: millert/sudo
bool
get_boottime(struct timespec *ts)
{
    struct utmp *ut, key;
    debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)

    memset(&key, 0, sizeof(key));
    key.ut_type = BOOT_TIME;
    setutent();
    if ((ut = getutid(&key)) != NULL) {
	sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
	    "BOOT_TIME: %lld", (long long)ut->ut_time);
	ts->tv_sec = ut->ut_time;
	ts->tv_nsec = 0;
    }
    endutent();
    debug_return_bool(ut != NULL);
}
예제 #8
0
파일: boottime.c 프로젝트: millert/sudo
bool
get_boottime(struct timespec *ts)
{
    struct utmpx *ut, key;
    debug_decl(get_boottime, SUDOERS_DEBUG_UTIL)

    memset(&key, 0, sizeof(key));
    key.ut_type = BOOT_TIME;
    setutxent();
    if ((ut = getutxid(&key)) != NULL) {
	sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
	    "BOOT_TIME: %lld, %ld", (long long)ut->ut_tv.tv_sec,
	    (long)ut->ut_tv.tv_usec);
	TIMEVAL_TO_TIMESPEC(&ut->ut_tv, ts);
    }
    endutxent();
    debug_return_bool(ut != NULL);
}
static bool
addr_matches_if_netmask(const char *n, const char *m)
{
    unsigned int i;
    union sudo_in_addr_un addr, mask;
    struct interface *ifp;
#ifdef HAVE_STRUCT_IN6_ADDR
    unsigned int j;
#endif
    unsigned int family;
    const char *errstr;
    debug_decl(addr_matches_if, SUDO_DEBUG_MATCH)

#ifdef HAVE_STRUCT_IN6_ADDR
    if (inet_pton(AF_INET6, n, &addr.ip6) == 1)
	family = AF_INET6;
    else
#endif /* HAVE_STRUCT_IN6_ADDR */
    if (inet_pton(AF_INET, n, &addr.ip4) == 1) {
	family = AF_INET;
    } else {
	debug_return_bool(false);
    }

    if (family == AF_INET) {
	if (strchr(m, '.')) {
	    if (inet_pton(AF_INET, m, &mask.ip4) != 1) {
		sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
		    "IPv4 netmask %s: %s", m, "invalid value");
		debug_return_bool(false);
	    }
	} else {
	    i = strtonum(m, 0, 32, &errstr);
	    if (errstr != NULL) {
		sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
		    "IPv4 netmask %s: %s", m, errstr);
		debug_return_bool(false);
	    }
	    if (i == 0)
		mask.ip4.s_addr = 0;
	    else if (i == 32)
		mask.ip4.s_addr = 0xffffffff;
	    else
		mask.ip4.s_addr = 0xffffffff - (1 << (32 - i)) + 1;
	    mask.ip4.s_addr = htonl(mask.ip4.s_addr);
	}
	addr.ip4.s_addr &= mask.ip4.s_addr;
    }
#ifdef HAVE_STRUCT_IN6_ADDR
    else {
	if (inet_pton(AF_INET6, m, &mask.ip6) != 1) {
	    j = strtonum(m, 0, 128, &errstr);
	    if (errstr != NULL) {
		sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
		    "IPv6 netmask %s: %s", m, errstr);
		debug_return_bool(false);
	    }
	    for (i = 0; i < sizeof(addr.ip6.s6_addr); i++) {
		if (j < i * 8)
		    mask.ip6.s6_addr[i] = 0;
		else if (i * 8 + 8 <= j)
		    mask.ip6.s6_addr[i] = 0xff;
		else
		    mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
		addr.ip6.s6_addr[i] &= mask.ip6.s6_addr[i];
	    }
	}
    }
예제 #10
0
파일: iolog_util.c 프로젝트: millert/sudo
struct log_info *
parse_logfile(const char *logfile)
{
    FILE *fp;
    char *buf = NULL, *cp, *ep;
    const char *errstr;
    size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
    struct log_info *li = NULL;
    debug_decl(parse_logfile, SUDO_DEBUG_UTIL)

    fp = fopen(logfile, "r");
    if (fp == NULL) {
	sudo_warn(U_("unable to open %s"), logfile);
	goto bad;
    }

    /*
     * ID file has three lines:
     *  1) a log info line
     *  2) cwd
     *  3) command with args
     */
    if ((li = calloc(1, sizeof(*li))) == NULL)
	sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
    if (getdelim(&buf, &bufsize, '\n', fp) == -1 ||
	getdelim(&li->cwd, &cwdsize, '\n', fp) == -1 ||
	getdelim(&li->cmd, &cmdsize, '\n', fp) == -1) {
	sudo_warn(U_("%s: invalid log file"), logfile);
	goto bad;
    }

    /* Strip the newline from the cwd and command. */
    li->cwd[strcspn(li->cwd, "\n")] = '\0';
    li->cmd[strcspn(li->cmd, "\n")] = '\0';

    /*
     * Crack the log line (rows and cols not present in old versions).
     *	timestamp:user:runas_user:runas_group:tty:rows:cols
     * XXX - probably better to use strtok and switch on the state.
     */
    buf[strcspn(buf, "\n")] = '\0';
    cp = buf;

    /* timestamp */
    if ((ep = strchr(cp, ':')) == NULL) {
	sudo_warn(U_("%s: time stamp field is missing"), logfile);
	goto bad;
    }
    *ep = '\0';
    li->tstamp = strtonum(cp, 0, TIME_T_MAX, &errstr);
    if (errstr != NULL) {
	sudo_warn(U_("%s: time stamp %s: %s"), logfile, cp, errstr);
	goto bad;
    }

    /* user */
    cp = ep + 1;
    if ((ep = strchr(cp, ':')) == NULL) {
	sudo_warn(U_("%s: user field is missing"), logfile);
	goto bad;
    }
    if ((li->user = strndup(cp, (size_t)(ep - cp))) == NULL)
	sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));

    /* runas user */
    cp = ep + 1;
    if ((ep = strchr(cp, ':')) == NULL) {
	sudo_warn(U_("%s: runas user field is missing"), logfile);
	goto bad;
    }
    if ((li->runas_user = strndup(cp, (size_t)(ep - cp))) == NULL)
	sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));

    /* runas group */
    cp = ep + 1;
    if ((ep = strchr(cp, ':')) == NULL) {
	sudo_warn(U_("%s: runas group field is missing"), logfile);
	goto bad;
    }
    if (cp != ep) {
	if ((li->runas_group = strndup(cp, (size_t)(ep - cp))) == NULL)
	    sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
    }

    /* tty, followed by optional rows + columns */
    cp = ep + 1;
    if ((ep = strchr(cp, ':')) == NULL) {
	/* just the tty */
	if ((li->tty = strdup(cp)) == NULL)
	    sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
    } else {
	/* tty followed by rows + columns */
	if ((li->tty = strndup(cp, (size_t)(ep - cp))) == NULL)
	    sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
	cp = ep + 1;
	/* need to NULL out separator to use strtonum() */
	if ((ep = strchr(cp, ':')) != NULL) {
	    *ep = '\0';
	}
	li->rows = strtonum(cp, 1, INT_MAX, &errstr);
	if (errstr != NULL) {
	    sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
		"%s: tty rows %s: %s", logfile, cp, errstr);
	}
	if (ep != NULL) {
	    cp = ep + 1;
	    li->cols = strtonum(cp, 1, INT_MAX, &errstr);
	    if (errstr != NULL) {
		sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
		    "%s: tty cols %s: %s", logfile, cp, errstr);
	    }
	}
    }
    fclose(fp);
    free(buf);
    debug_return_ptr(li);

bad:
    if (fp != NULL)
	fclose(fp);
    free(buf);
    free_log_info(li);
    debug_return_ptr(NULL);
}
예제 #11
0
파일: iolog_util.c 프로젝트: millert/sudo
/*
 * Parse the delay as seconds and nanoseconds: %lld.%09ld
 * Sudo used to write this as a double, but since timing data is logged
 * in the C locale this may not match the current locale.
 */
char *
parse_delay(const char *cp, struct timespec *delay, const char *decimal_point)
{
    char numbuf[(((sizeof(long long) * 8) + 2) / 3) + 2];
    const char *errstr, *ep;
    long long llval;
    size_t len;
    debug_decl(parse_delay, SUDO_DEBUG_UTIL)

    /* Parse seconds (whole number portion). */
    for (ep = cp; isdigit((unsigned char)*ep); ep++)
	continue;
    len = (size_t)(ep - cp);
    if (len >= sizeof(numbuf)) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "%s: number of seconds is too large", cp);
	debug_return_ptr(NULL);
    }
    memcpy(numbuf, cp, len);
    numbuf[len] = '\0';
    delay->tv_sec = strtonum(numbuf, 0, TIME_T_MAX, &errstr);
    if (errstr != NULL) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "%s: number of seconds is %s", numbuf, errstr);
	debug_return_ptr(NULL);
    }

    /* Radix may be in user's locale for sudo < 1.7.4 so accept that too. */
    if (*ep != '.' && *ep != *decimal_point) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "invalid characters after seconds: %s", ep);
	debug_return_ptr(NULL);
    }
    cp = ep + 1;

    /* Parse fractional part, we may read more precision than we can store. */
    for (ep = cp; isdigit((unsigned char)*ep); ep++)
	continue;
    len = (size_t)(ep - cp);
    if (len >= sizeof(numbuf)) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "%s: number of nanoseconds is too large", cp);
	debug_return_ptr(NULL);
    }
    memcpy(numbuf, cp, len);
    numbuf[len] = '\0';
    llval = strtonum(numbuf, 0, LLONG_MAX, &errstr);
    if (errstr != NULL) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "%s: number of nanoseconds is %s", numbuf, errstr);
	debug_return_ptr(NULL);
    }

    /* Adjust fractional part to nanosecond precision. */
    if (len < 9) {
	/* Convert to nanosecond precision. */
	do {
	    llval *= 10;
	} while (++len < 9);
    } else if (len > 9) {
	/* Clamp to nanoseconds. */
	do {
	    llval /= 10;
	} while (--len > 9);
    }
    delay->tv_nsec = (long)llval;

    /* Advance to the next field. */
    while (isspace((unsigned char)*ep))
	ep++;

    debug_return_str((char *)ep);
}
예제 #12
0
/*
 * Deserialize args, settings and user_info arrays.
 * Fills in struct sudo_user and other common sudoers state.
 */
int
sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group)
{
    struct sudoers_policy_open_info *info = v;
    char * const *cur;
    const char *p, *errstr, *groups = NULL;
    const char *remhost = NULL;
    int flags = 0;
    debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN)

#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)

    /* Parse sudo.conf plugin args. */
    if (info->plugin_args != NULL) {
	for (cur = info->plugin_args; *cur != NULL; cur++) {
	    if (MATCHES(*cur, "sudoers_file=")) {
		sudoers_file = *cur + sizeof("sudoers_file=") - 1;
		continue;
	    }
	    if (MATCHES(*cur, "sudoers_uid=")) {
		p = *cur + sizeof("sudoers_uid=") - 1;
		sudoers_uid = (uid_t) sudo_strtoid(p, NULL, NULL, &errstr);
		if (errstr != NULL) {
		    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		    goto bad;
		}
		continue;
	    }
	    if (MATCHES(*cur, "sudoers_gid=")) {
		p = *cur + sizeof("sudoers_gid=") - 1;
		sudoers_gid = (gid_t) sudo_strtoid(p, NULL, NULL, &errstr);
		if (errstr != NULL) {
		    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		    goto bad;
		}
		continue;
	    }
	    if (MATCHES(*cur, "sudoers_mode=")) {
		p = *cur + sizeof("sudoers_mode=") - 1;
		sudoers_mode = sudo_strtomode(p, &errstr);
		if (errstr != NULL) {
		    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		    goto bad;
		}
		continue;
	    }
	    if (MATCHES(*cur, "ldap_conf=")) {
		path_ldap_conf = *cur + sizeof("ldap_conf=") - 1;
		continue;
	    }
	    if (MATCHES(*cur, "ldap_secret=")) {
		path_ldap_secret = *cur + sizeof("ldap_secret=") - 1;
		continue;
	    }
	}
    }

    /* Parse command line settings. */
    user_closefrom = -1;
    for (cur = info->settings; *cur != NULL; cur++) {
	if (MATCHES(*cur, "closefrom=")) {
	    errno = 0;
	    p = *cur + sizeof("closefrom=") - 1;
	    user_closefrom = strtonum(p, 4, INT_MAX, &errstr);
	    if (user_closefrom == 0) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "runas_user="******"runas_user="******"runas_group=")) {
	    *runas_group = *cur + sizeof("runas_group=") - 1;
	    sudo_user.flags |= RUNAS_GROUP_SPECIFIED;
	    continue;
	}
	if (MATCHES(*cur, "prompt=")) {
	    user_prompt = *cur + sizeof("prompt=") - 1;
	    def_passprompt_override = true;
	    continue;
	}
	if (MATCHES(*cur, "set_home=")) {
	    if (sudo_strtobool(*cur + sizeof("set_home=") - 1) == true)
		SET(flags, MODE_RESET_HOME);
	    continue;
	}
	if (MATCHES(*cur, "preserve_environment=")) {
	    if (sudo_strtobool(*cur + sizeof("preserve_environment=") - 1) == true)
		SET(flags, MODE_PRESERVE_ENV);
	    continue;
	}
	if (MATCHES(*cur, "run_shell=")) {
	    if (sudo_strtobool(*cur + sizeof("run_shell=") - 1) == true)
		SET(flags, MODE_SHELL);
	    continue;
	}
	if (MATCHES(*cur, "login_shell=")) {
	    if (sudo_strtobool(*cur + sizeof("login_shell=") - 1) == true) {
		SET(flags, MODE_LOGIN_SHELL);
		def_env_reset = true;
	    }
	    continue;
	}
	if (MATCHES(*cur, "implied_shell=")) {
	    if (sudo_strtobool(*cur + sizeof("implied_shell=") - 1) == true)
		SET(flags, MODE_IMPLIED_SHELL);
	    continue;
	}
	if (MATCHES(*cur, "preserve_groups=")) {
	    if (sudo_strtobool(*cur + sizeof("preserve_groups=") - 1) == true)
		SET(flags, MODE_PRESERVE_GROUPS);
	    continue;
	}
	if (MATCHES(*cur, "ignore_ticket=")) {
	    if (sudo_strtobool(*cur + sizeof("ignore_ticket=") - 1) == true)
		SET(flags, MODE_IGNORE_TICKET);
	    continue;
	}
	if (MATCHES(*cur, "noninteractive=")) {
	    if (sudo_strtobool(*cur + sizeof("noninteractive=") - 1) == true)
		SET(flags, MODE_NONINTERACTIVE);
	    continue;
	}
	if (MATCHES(*cur, "sudoedit=")) {
	    if (sudo_strtobool(*cur + sizeof("sudoedit=") - 1) == true)
		SET(flags, MODE_EDIT);
	    continue;
	}
	if (MATCHES(*cur, "login_class=")) {
	    login_class = *cur + sizeof("login_class=") - 1;
	    def_use_loginclass = true;
	    continue;
	}
#ifdef HAVE_PRIV_SET
	if (MATCHES(*cur, "runas_privs=")) {
	    def_privs = *cur + sizeof("runas_privs=") - 1;
	    continue;
	}
	if (MATCHES(*cur, "runas_limitprivs=")) {
	    def_limitprivs = *cur + sizeof("runas_limitprivs=") - 1;
	    continue;
	}
#endif /* HAVE_PRIV_SET */
#ifdef HAVE_SELINUX
	if (MATCHES(*cur, "selinux_role=")) {
	    user_role = *cur + sizeof("selinux_role=") - 1;
	    continue;
	}
	if (MATCHES(*cur, "selinux_type=")) {
	    user_type = *cur + sizeof("selinux_type=") - 1;
	    continue;
	}
#endif /* HAVE_SELINUX */
#ifdef HAVE_BSD_AUTH_H
	if (MATCHES(*cur, "bsdauth_type=")) {
	    login_style = *cur + sizeof("bsdauth_type=") - 1;
	    continue;
	}
#endif /* HAVE_BSD_AUTH_H */
	if (MATCHES(*cur, "network_addrs=")) {
	    interfaces_string = *cur + sizeof("network_addrs=") - 1;
	    set_interfaces(interfaces_string);
	    continue;
	}
	if (MATCHES(*cur, "max_groups=")) {
	    errno = 0;
	    p = *cur + sizeof("max_groups=") - 1;
	    sudo_user.max_groups = strtonum(p, 1, INT_MAX, &errstr);
	    if (sudo_user.max_groups == 0) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "remote_host=")) {
	    remhost = *cur + sizeof("remote_host=") - 1;
	    continue;
	}
    }

    for (cur = info->user_info; *cur != NULL; cur++) {
	if (MATCHES(*cur, "user="******"user="******"uid=")) {
	    p = *cur + sizeof("uid=") - 1;
	    user_uid = (uid_t) sudo_strtoid(p, NULL, NULL, &errstr);
	    if (errstr != NULL) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "gid=")) {
	    p = *cur + sizeof("gid=") - 1;
	    user_gid = (gid_t) sudo_strtoid(p, NULL, NULL, &errstr);
	    if (errstr != NULL) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "groups=")) {
	    groups = *cur + sizeof("groups=") - 1;
	    continue;
	}
	if (MATCHES(*cur, "cwd=")) {
	    user_cwd = sudo_estrdup(*cur + sizeof("cwd=") - 1);
	    continue;
	}
	if (MATCHES(*cur, "tty=")) {
	    user_tty = user_ttypath = sudo_estrdup(*cur + sizeof("tty=") - 1);
	    if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
		user_tty += sizeof(_PATH_DEV) - 1;
	    continue;
	}
	if (MATCHES(*cur, "host=")) {
	    user_host = user_shost = sudo_estrdup(*cur + sizeof("host=") - 1);
	    if ((p = strchr(user_host, '.')))
		user_shost = sudo_estrndup(user_host, (size_t)(p - user_host));
	    continue;
	}
	if (MATCHES(*cur, "lines=")) {
	    errno = 0;
	    p = *cur + sizeof("lines=") - 1;
	    sudo_user.lines = strtonum(p, 1, INT_MAX, &errstr);
	    if (sudo_user.lines == 0) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "cols=")) {
	    errno = 0;
	    p = *cur + sizeof("cols=") - 1;
	    sudo_user.cols = strtonum(p, 1, INT_MAX, &errstr);
	    if (sudo_user.lines == 0) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
	if (MATCHES(*cur, "sid=")) {
	    p = *cur + sizeof("sid=") - 1;
	    sudo_user.sid = (pid_t) sudo_strtoid(p, NULL, NULL, &errstr);
	    if (errstr != NULL) {
		sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
		goto bad;
	    }
	    continue;
	}
    }
    user_runhost = user_srunhost = sudo_estrdup(remhost ? remhost : user_host);
    if ((p = strchr(user_runhost, '.')))
	user_srunhost = sudo_estrndup(user_runhost, (size_t)(p - user_runhost));
    if (user_cwd == NULL)
	user_cwd = sudo_estrdup("unknown");
    if (user_tty == NULL)
	user_tty = sudo_estrdup("unknown"); /* user_ttypath remains NULL */

    if (groups != NULL && groups[0] != '\0') {
	/* sudo_parse_gids() will print a warning on error. */
	user_ngids = sudo_parse_gids(groups, &user_gid, &user_gids);
	if (user_ngids == -1)
	    goto bad;
    }

    /* Stash initial umask for later use. */
    user_umask = umask(SUDO_UMASK);
    umask(user_umask);

    /* Dump settings and user info (XXX - plugin args) */
    for (cur = info->settings; *cur != NULL; cur++)
	sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur);
    for (cur = info->user_info; *cur != NULL; cur++)
	sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur);

#undef MATCHES
    debug_return_int(flags);

bad:
    debug_return_int(MODE_ERROR);
}
예제 #13
0
파일: redblack.c 프로젝트: millert/sudo
/*
 * Insert data pointer into a redblack tree.
 * Returns a 0 on success, 1 if a node matching "data" already exists
 * (filling in "existing" if not NULL), or -1 on malloc() failure.
 */
int
rbinsert(struct rbtree *tree, void *data, struct rbnode **existing)
{
    struct rbnode *node = rbfirst(tree);
    struct rbnode *parent = rbroot(tree);
    int res;
    debug_decl(rbinsert, SUDOERS_DEBUG_RBTREE)

    /* Find correct insertion point. */
    while (node != rbnil(tree)) {
	parent = node;
	if ((res = tree->compar(data, node->data)) == 0) {
	    if (existing != NULL)
		*existing = node;
	    debug_return_int(1);
	}
	node = res < 0 ? node->left : node->right;
    }

    node = malloc(sizeof(*node));
    if (node == NULL) {
	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
	    "unable to allocate memory");
	debug_return_int(-1);
    }
    node->data = data;
    node->left = node->right = rbnil(tree);
    node->parent = parent;
    if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0)
	parent->left = node;
    else
	parent->right = node;
    node->color = red;

    /*
     * If the parent node is black we are all set, if it is red we have
     * the following possible cases to deal with.  We iterate through
     * the rest of the tree to make sure none of the required properties
     * is violated.
     *
     *	1) The uncle is red.  We repaint both the parent and uncle black
     *     and repaint the grandparent node red.
     *
     *  2) The uncle is black and the new node is the right child of its
     *     parent, and the parent in turn is the left child of its parent.
     *     We do a left rotation to switch the roles of the parent and
     *     child, relying on further iterations to fixup the old parent.
     *
     *  3) The uncle is black and the new node is the left child of its
     *     parent, and the parent in turn is the left child of its parent.
     *     We switch the colors of the parent and grandparent and perform
     *     a right rotation around the grandparent.  This makes the former
     *     parent the parent of the new node and the former grandparent.
     *
     * Note that because we use a sentinel for the root node we never
     * need to worry about replacing the root.
     */
    while (node->parent->color == red) {
	struct rbnode *uncle;
	if (node->parent == node->parent->parent->left) {
	    uncle = node->parent->parent->right;
	    if (uncle->color == red) {
		node->parent->color = black;
		uncle->color = black;
		node->parent->parent->color = red;
		node = node->parent->parent;
	    } else /* if (uncle->color == black) */ {
		if (node == node->parent->right) {
		    node = node->parent;
		    rotate_left(tree, node);
		}
		node->parent->color = black;
		node->parent->parent->color = red;
		rotate_right(tree, node->parent->parent);
	    }
	} else { /* if (node->parent == node->parent->parent->right) */
	    uncle = node->parent->parent->left;
	    if (uncle->color == red) {
		node->parent->color = black;
		uncle->color = black;
		node->parent->parent->color = red;
		node = node->parent->parent;
	    } else /* if (uncle->color == black) */ {
		if (node == node->parent->left) {
		    node = node->parent;
		    rotate_right(tree, node);
		}
		node->parent->color = black;
		node->parent->parent->color = red;
		rotate_left(tree, node->parent->parent);
	    }
	}
    }
    rbfirst(tree)->color = black;	/* first node is always black */
    debug_return_int(0);
}