Chris PeBenito 473ea7
#include <unistd.h>
Chris PeBenito 473ea7
#include <errno.h>
Chris PeBenito 473ea7
#include <stdio.h>
Chris PeBenito 473ea7
#include <stdlib.h>
Chris PeBenito 473ea7
#include <string.h>
Chris PeBenito 473ea7
#include <ctype.h>
Chris PeBenito 473ea7
#include <pwd.h>
Chris PeBenito 473ea7
#include "selinux_internal.h"
Chris PeBenito 473ea7
#include "context_internal.h"
Chris PeBenito 473ea7
#include "get_context_list_internal.h"
Chris PeBenito 473ea7
Chris PeBenito 473ea7
int get_default_context_with_role(const char* user, 
Chris PeBenito 473ea7
				  const char *role,
Chris PeBenito 473ea7
				  security_context_t fromcon,
Chris PeBenito 473ea7
				  security_context_t *newcon)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    security_context_t *conary;
Chris PeBenito 473ea7
    char **ptr;
Chris PeBenito 473ea7
    context_t con;
Chris PeBenito 473ea7
    const char *role2;
Chris PeBenito 473ea7
    int rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = get_ordered_context_list(user, fromcon, &conary);
Chris PeBenito 473ea7
    if (rc <= 0)
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    for (ptr = conary; *ptr; ptr++) {
Chris PeBenito 473ea7
	    con = context_new(*ptr);
Chris PeBenito 473ea7
	    if (!con)
Chris PeBenito 473ea7
		    continue;
Chris PeBenito 473ea7
	    role2 = context_role_get(con);
Chris PeBenito 473ea7
	    if (role2 && !strcmp(role, role2)) {
Chris PeBenito 473ea7
		    context_free(con);
Chris PeBenito 473ea7
		    break;
Chris PeBenito 473ea7
	    }
Chris PeBenito 473ea7
	    context_free(con);
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = -1;
Chris PeBenito 473ea7
    if (!(*ptr))
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
    *newcon = strdup(*ptr);
Chris PeBenito 473ea7
    if (!(*newcon))
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
    rc = 0;
Chris PeBenito 473ea7
out:
Chris PeBenito 473ea7
    freeconary(conary);
Chris PeBenito 473ea7
    return rc;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
int get_default_context(const char* user, 
Chris PeBenito 473ea7
			security_context_t fromcon,
Chris PeBenito 473ea7
			security_context_t *newcon)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    security_context_t *conary;
Chris PeBenito 473ea7
    int rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = get_ordered_context_list(user, fromcon, &conary);
Chris PeBenito 473ea7
    if (rc <= 0)
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    *newcon = strdup(conary[0]);
Chris PeBenito 473ea7
    freeconary(conary);
Chris PeBenito 473ea7
    if (!(*newcon))
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
    return 0;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
static int find_partialcon(security_context_t *list,
Chris PeBenito 473ea7
			   unsigned int nreach,
Chris PeBenito 473ea7
			   char *part)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
	const char *conrole, *contype;
Chris PeBenito 473ea7
	char *partrole, *parttype, *ptr;
Chris PeBenito 473ea7
	context_t con;
Chris PeBenito 473ea7
	unsigned int i;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	partrole = part;
Chris PeBenito 473ea7
	ptr = part;
Chris PeBenito 473ea7
	while (*ptr && !isspace(*ptr) && *ptr != ':')
Chris PeBenito 473ea7
		ptr++;
Chris PeBenito 473ea7
	if (*ptr != ':')
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	*ptr++ = 0;
Chris PeBenito 473ea7
	parttype = ptr;
Chris PeBenito 473ea7
	while (*ptr && !isspace(*ptr) && *ptr != ':')
Chris PeBenito 473ea7
		ptr++;
Chris PeBenito 473ea7
	*ptr = 0;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	for (i = 0; i < nreach; i++) {
Chris PeBenito 473ea7
		con = context_new(list[i]);
Chris PeBenito 473ea7
		if (!con)
Chris PeBenito 473ea7
			return -1;
Chris PeBenito 473ea7
		conrole = context_role_get(con);
Chris PeBenito 473ea7
		contype = context_type_get(con);
Chris PeBenito 473ea7
		if (!conrole || !contype) {
Chris PeBenito 473ea7
			context_free(con);
Chris PeBenito 473ea7
			return -1;
Chris PeBenito 473ea7
		}
Chris PeBenito 473ea7
		if (!strcmp(conrole, partrole) && !strcmp(contype, parttype)) {
Chris PeBenito 473ea7
			context_free(con);
Chris PeBenito 473ea7
			return i;
Chris PeBenito 473ea7
		}
Chris PeBenito 473ea7
		context_free(con);
Chris PeBenito 473ea7
	}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	return -1;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
static int get_context_order(FILE *fp, 
Chris PeBenito 473ea7
			     security_context_t fromcon, 
Chris PeBenito 473ea7
			     security_context_t *reachable, 
Chris PeBenito 473ea7
			     unsigned int nreach,
Chris PeBenito 473ea7
			     unsigned int *ordering,
Chris PeBenito 473ea7
			     unsigned int *nordered)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    char *start, *end = NULL;
Chris PeBenito 473ea7
    char *line = NULL;
Chris PeBenito 473ea7
    size_t line_len = 0, len;
Chris PeBenito 473ea7
    int found = 0;
Chris PeBenito 473ea7
    const char *fromrole, *fromtype;
Chris PeBenito 473ea7
    char *linerole, *linetype;
Chris PeBenito 473ea7
    unsigned int i;
Chris PeBenito 473ea7
    context_t con;
Chris PeBenito 473ea7
    int rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    errno = -EINVAL;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Extract the role and type of the fromcon for matching.
Chris PeBenito 473ea7
       User identity and MLS range can be variable. */
Chris PeBenito 473ea7
    con = context_new(fromcon);
Chris PeBenito 473ea7
    if (!con)
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
    fromrole = context_role_get(con);
Chris PeBenito 473ea7
    fromtype = context_type_get(con);
Chris PeBenito 473ea7
    if (!fromrole || !fromtype) {
Chris PeBenito 473ea7
	    context_free(con);
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    while (getline(&line, &line_len, fp) > 0) {
Chris PeBenito 473ea7
	    len = strlen(line);
Chris PeBenito 473ea7
	    if (line[len - 1] == '\n')
Chris PeBenito 473ea7
		    line[len - 1] = 0;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	    /* Skip leading whitespace. */
Chris PeBenito 473ea7
	    start = line;
Chris PeBenito 473ea7
	    while (*start && isspace(*start))
Chris PeBenito 473ea7
		    start++;
Chris PeBenito 473ea7
	    if (!(*start))
Chris PeBenito 473ea7
		    continue;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	    /* Find the end of the (partial) fromcon in the line. */
Chris PeBenito 473ea7
	    end = start;
Chris PeBenito 473ea7
	    while (*end && !isspace(*end))
Chris PeBenito 473ea7
		    end++;
Chris PeBenito 473ea7
	    if (!(*end))
Chris PeBenito 473ea7
		    continue;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	    /* Check for a match. */
Chris PeBenito 473ea7
	    linerole = start;
Chris PeBenito 473ea7
	    while (*start && !isspace(*start) && *start != ':')
Chris PeBenito 473ea7
		    start++;
Chris PeBenito 473ea7
	    if (*start != ':')
Chris PeBenito 473ea7
		    continue;
Chris PeBenito 473ea7
	    *start = 0;
Chris PeBenito 473ea7
	    linetype = ++start;
Chris PeBenito 473ea7
	    while (*start && !isspace(*start) && *start != ':')
Chris PeBenito 473ea7
		    start++;
Chris PeBenito 473ea7
	    if (!(*start))
Chris PeBenito 473ea7
		    continue;
Chris PeBenito 473ea7
	    *start = 0;
Chris PeBenito 473ea7
	    if (!strcmp(fromrole, linerole) && !strcmp(fromtype, linetype)) {
Chris PeBenito 473ea7
		    found = 1;
Chris PeBenito 473ea7
		    break;
Chris PeBenito 473ea7
	    }
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    if (!found) {
Chris PeBenito 473ea7
	    errno = ENOENT;
Chris PeBenito 473ea7
	    rc = -1;
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    start = ++end;
Chris PeBenito 473ea7
    while (*start) {
Chris PeBenito 473ea7
        /* Skip leading whitespace */
Chris PeBenito 473ea7
        while (*start && isspace(*start))
Chris PeBenito 473ea7
		start++;
Chris PeBenito 473ea7
	if (!(*start))
Chris PeBenito 473ea7
		break;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
        /* Find the end of this partial context. */
Chris PeBenito 473ea7
        end = start;
Chris PeBenito 473ea7
        while (*end && !isspace(*end))
Chris PeBenito 473ea7
		end++;
Chris PeBenito 473ea7
	if (*end)
Chris PeBenito 473ea7
		*end++ = 0;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	/* Check for a match in the reachable list. */
Chris PeBenito 473ea7
	rc = find_partialcon(reachable, nreach, start);
Chris PeBenito 473ea7
	if (rc < 0) {
Chris PeBenito 473ea7
		/* No match, skip it. */
Chris PeBenito 473ea7
		start = end;
Chris PeBenito 473ea7
		continue;
Chris PeBenito 473ea7
	}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	/* If a match is found and the entry is not already ordered
Chris PeBenito 473ea7
	   (e.g. due to prior match in prior config file), then set
Chris PeBenito 473ea7
	   the ordering for it. */
Chris PeBenito 473ea7
	i = rc;
Chris PeBenito 473ea7
	if (ordering[i] == nreach)
Chris PeBenito 473ea7
		ordering[i] = (*nordered)++;
Chris PeBenito 473ea7
	start = end;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = 0;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
out:
Chris PeBenito 473ea7
    context_free(con);
Chris PeBenito 473ea7
    free(line);
Chris PeBenito 473ea7
    return rc;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
static int get_failsafe_context(const char* user, 
Chris PeBenito 473ea7
				security_context_t *newcon)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
	FILE *fp;
Chris PeBenito 473ea7
	char buf[255], *ptr;
Chris PeBenito 473ea7
	size_t plen, nlen;
Chris PeBenito 473ea7
	int rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	fp = fopen(selinux_failsafe_context_path(), "r");
Chris PeBenito 473ea7
	if (!fp)
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	ptr = fgets_unlocked(buf, sizeof buf, fp);
Chris PeBenito 473ea7
	fclose(fp);
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	if (!ptr)
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	plen = strlen(ptr);
Chris PeBenito 473ea7
	if (buf[plen-1] == '\n') 
Chris PeBenito 473ea7
		buf[plen-1] = 0;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
 retry:
Chris PeBenito 473ea7
	nlen = strlen(user)+1+plen+1;
Chris PeBenito 473ea7
	*newcon = malloc(nlen);
Chris PeBenito 473ea7
	if(!(*newcon))
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	rc = snprintf(*newcon, nlen, "%s:%s", user, ptr);
Chris PeBenito 473ea7
	if (rc < 0 || (size_t) rc >= nlen) {
Chris PeBenito 473ea7
		free(*newcon);
Chris PeBenito 473ea7
		*newcon = 0;
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	/* If possible, check the context to catch
Chris PeBenito 473ea7
	   errors early rather than waiting until the
Chris PeBenito 473ea7
	   caller tries to use setexeccon on the context.
Chris PeBenito 473ea7
	   But this may not always be possible, e.g. if
Chris PeBenito 473ea7
	   selinuxfs isn't mounted. */
Chris PeBenito 473ea7
	if (security_check_context(*newcon) && errno != ENOENT) {
Chris PeBenito 473ea7
		free(*newcon);
Chris PeBenito 473ea7
		*newcon = 0;
Chris PeBenito 473ea7
		if (strcmp(user, SELINUX_DEFAULTUSER)) {
Chris PeBenito 473ea7
			user = SELINUX_DEFAULTUSER;
Chris PeBenito 473ea7
			goto retry;
Chris PeBenito 473ea7
		}
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
	return 0;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
struct context_order {
Chris PeBenito 473ea7
	security_context_t con;
Chris PeBenito 473ea7
	unsigned int order;
Chris PeBenito 473ea7
};
Chris PeBenito 473ea7
Chris PeBenito 473ea7
static int order_compare(const void *A, const void *B) 
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
	const struct context_order *c1 = A, *c2 = B;
Chris PeBenito 473ea7
	if (c1->order < c2->order)
Chris PeBenito 473ea7
		return -1;
Chris PeBenito 473ea7
	else if (c1->order > c2->order)
Chris PeBenito 473ea7
		return 1;
Chris PeBenito 473ea7
	return strcmp(c1->con, c2->con);
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
int get_ordered_context_list_with_level (const char *user, 
Chris PeBenito 473ea7
					 const char *level, 
Chris PeBenito 473ea7
					 security_context_t fromcon, 
Chris PeBenito 473ea7
					 security_context_t **list)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    int rc;
Chris PeBenito 473ea7
    int freefrom = 0;
Chris PeBenito 473ea7
    context_t con;
Chris PeBenito 473ea7
    char *newfromcon;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    if (!level) 
Chris PeBenito 473ea7
	    return get_ordered_context_list (user, fromcon, list);
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    if (!fromcon) {
Chris PeBenito 473ea7
	rc = getcon(&fromcon);
Chris PeBenito 473ea7
	if (rc < 0)
Chris PeBenito 473ea7
		return rc;
Chris PeBenito 473ea7
	freefrom = 1;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = -1;
Chris PeBenito 473ea7
    con=context_new(fromcon);
Chris PeBenito 473ea7
    if (!con)
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    if (context_range_set(con, level))
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    newfromcon = context_str(con);
Chris PeBenito 473ea7
    if (!newfromcon)
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = get_ordered_context_list (user, newfromcon, list);
Chris PeBenito 473ea7
Chris PeBenito 473ea7
out:
Chris PeBenito 473ea7
    context_free(con);
Chris PeBenito 473ea7
    if (freefrom) 
Chris PeBenito 473ea7
	    freecon(fromcon);
Chris PeBenito 473ea7
    return rc;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
hidden_def(get_ordered_context_list_with_level)
Chris PeBenito 473ea7
Chris PeBenito 473ea7
int get_default_context_with_level(const char *user, 
Chris PeBenito 473ea7
				   const char *level,
Chris PeBenito 473ea7
				   security_context_t fromcon,
Chris PeBenito 473ea7
				   security_context_t *newcon)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    security_context_t *conary;
Chris PeBenito 473ea7
    int rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    rc = get_ordered_context_list_with_level(user, level, fromcon, &conary);
Chris PeBenito 473ea7
    if (rc <= 0)
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    *newcon = strdup(conary[0]);
Chris PeBenito 473ea7
    freeconary(conary);
Chris PeBenito 473ea7
    if (!(*newcon))
Chris PeBenito 473ea7
	    return -1;
Chris PeBenito 473ea7
    return 0;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
Chris PeBenito 473ea7
int get_ordered_context_list (const char *user, 
Chris PeBenito 473ea7
			      security_context_t fromcon, 
Chris PeBenito 473ea7
			      security_context_t **list)
Chris PeBenito 473ea7
{
Chris PeBenito 473ea7
    security_context_t *reachable = NULL;
Chris PeBenito 473ea7
    unsigned int *ordering = NULL;
Chris PeBenito 473ea7
    struct context_order *co = NULL;
Chris PeBenito 473ea7
    char **ptr;
Chris PeBenito 473ea7
    int rc = 0;
Chris PeBenito 473ea7
    unsigned int nreach = 0, nordered = 0, freefrom = 0, i;
Chris PeBenito 473ea7
    FILE *fp;
Chris PeBenito 473ea7
    char *fname = NULL;
Chris PeBenito 473ea7
    size_t fname_len;
Chris PeBenito 473ea7
    const char *user_contexts_path = selinux_user_contexts_path();
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    if (!fromcon) {
Chris PeBenito 473ea7
	    /* Get the current context and use it for the starting context */
Chris PeBenito 473ea7
	    rc = getcon(&fromcon);
Chris PeBenito 473ea7
	    if (rc < 0)
Chris PeBenito 473ea7
		    return rc;
Chris PeBenito 473ea7
	    freefrom = 1;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Determine the set of reachable contexts for the user. */
Chris PeBenito 473ea7
    rc = security_compute_user(fromcon, user, &reachable);
Chris PeBenito 473ea7
    if (rc < 0) {
Chris PeBenito 473ea7
	    /* Retry with the default SELinux user identity. */
Chris PeBenito 473ea7
	    user = SELINUX_DEFAULTUSER;
Chris PeBenito 473ea7
	    rc = security_compute_user(fromcon, user, &reachable);
Chris PeBenito 473ea7
	    if (rc < 0)
Chris PeBenito 473ea7
		    goto failsafe;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
    nreach = 0;
Chris PeBenito 473ea7
    for (ptr = reachable; *ptr; ptr++) 
Chris PeBenito 473ea7
	    nreach++;
Chris PeBenito 473ea7
    if (!nreach)
Chris PeBenito 473ea7
	    goto failsafe;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Initialize ordering array. */
Chris PeBenito 473ea7
    ordering = malloc(nreach * sizeof(unsigned int));
Chris PeBenito 473ea7
    if (!ordering)
Chris PeBenito 473ea7
	    goto oom_order;
Chris PeBenito 473ea7
    for (i = 0; i < nreach; i++)
Chris PeBenito 473ea7
	    ordering[i] = nreach;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Determine the ordering to apply from the optional per-user config
Chris PeBenito 473ea7
       and from the global config. */
Chris PeBenito 473ea7
    fname_len = strlen(user_contexts_path) + strlen(user) + 2;
Chris PeBenito 473ea7
    fname = malloc(fname_len);
Chris PeBenito 473ea7
    if (!fname)
Chris PeBenito 473ea7
	    goto oom_order;
Chris PeBenito 473ea7
    snprintf(fname, fname_len, "%s%s", user_contexts_path, user);
Chris PeBenito 473ea7
    fp = fopen(fname, "r");
Chris PeBenito 473ea7
    if (fp) {
Chris PeBenito 473ea7
	    rc = get_context_order(fp, fromcon, reachable, nreach, ordering, &nordered);
Chris PeBenito 473ea7
	    fclose(fp);
Chris PeBenito 473ea7
	    if (rc < 0 && errno != ENOENT) {
Chris PeBenito 473ea7
		    fprintf(stderr, "%s:  error in processing configuration file %s\n", __FUNCTION__, fname);
Chris PeBenito 473ea7
		    /* Fall through, try global config */
Chris PeBenito 473ea7
	    }
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
    free(fname);
Chris PeBenito 473ea7
    fp = fopen(selinux_default_context_path(), "r");
Chris PeBenito 473ea7
    if (fp) {
Chris PeBenito 473ea7
	    rc = get_context_order(fp, fromcon, reachable, nreach, ordering, &nordered);
Chris PeBenito 473ea7
	    fclose(fp);
Chris PeBenito 473ea7
	    if (rc < 0 && errno != ENOENT) {
Chris PeBenito 473ea7
		    fprintf(stderr, "%s:  error in processing configuration file %s\n", __FUNCTION__, selinux_default_context_path());
Chris PeBenito 473ea7
		   /* Fall through */
Chris PeBenito 473ea7
	    }
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Apply the ordering. */
Chris PeBenito 473ea7
    if (nordered) {
Chris PeBenito 473ea7
	    co = malloc(nreach * sizeof(struct context_order));
Chris PeBenito 473ea7
	    if (!co)
Chris PeBenito 473ea7
		    goto oom_order;
Chris PeBenito 473ea7
	    for (i = 0; i < nreach; i++) {
Chris PeBenito 473ea7
		    co[i].con = reachable[i];
Chris PeBenito 473ea7
		    co[i].order = ordering[i];
Chris PeBenito 473ea7
	    }
Chris PeBenito 473ea7
	    qsort(co, nreach, sizeof(struct context_order), order_compare);
Chris PeBenito 473ea7
	    for (i = 0; i < nreach; i++)
Chris PeBenito 473ea7
		    reachable[i] = co[i].con;
Chris PeBenito 473ea7
	    free(co);
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    /* Return the ordered list. 
Chris PeBenito 473ea7
       If we successfully ordered it, then only report the ordered entries
Chris PeBenito 473ea7
       to the caller.  Otherwise, fall back to the entire reachable list. */
Chris PeBenito 473ea7
    if (nordered && nordered < nreach) {
Chris PeBenito 473ea7
	    for (i = nordered; i < nreach; i++)
Chris PeBenito 473ea7
		    free(reachable[i]);
Chris PeBenito 473ea7
	    reachable[nordered] = NULL;
Chris PeBenito 473ea7
	    rc = nordered;
Chris PeBenito 473ea7
    } else {
Chris PeBenito 473ea7
	    rc = nreach;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
Chris PeBenito 473ea7
out:
Chris PeBenito 473ea7
    *list = reachable;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    free(ordering);
Chris PeBenito 473ea7
    if (freefrom)
Chris PeBenito 473ea7
	    freecon(fromcon);
Chris PeBenito 473ea7
Chris PeBenito 473ea7
    return rc;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
failsafe:
Chris PeBenito 473ea7
    /* Unable to determine a reachable context list, try to fall back to
Chris PeBenito 473ea7
       the "failsafe" context to at least permit root login
Chris PeBenito 473ea7
       for emergency recovery if possible. */
Chris PeBenito 473ea7
    freeconary(reachable);
Chris PeBenito 473ea7
    reachable = malloc(2*sizeof(security_context_t));
Chris PeBenito 473ea7
    if (!reachable) {
Chris PeBenito 473ea7
	    rc = -1;
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
    reachable[0] = reachable[1] = 0;
Chris PeBenito 473ea7
    rc = get_failsafe_context(user, &reachable[0]);
Chris PeBenito 473ea7
    if (rc < 0) {
Chris PeBenito 473ea7
	    freeconary(reachable);
Chris PeBenito 473ea7
	    reachable = NULL;
Chris PeBenito 473ea7
	    goto out;
Chris PeBenito 473ea7
    }
Chris PeBenito 473ea7
    rc = 1; /* one context in the list */
Chris PeBenito 473ea7
    goto out;
Chris PeBenito 473ea7
Chris PeBenito 473ea7
oom_order:
Chris PeBenito 473ea7
    /* Unable to order context list due to OOM condition.
Chris PeBenito 473ea7
       Fall back to unordered reachable context list. */
Chris PeBenito 473ea7
    fprintf(stderr, "%s:  out of memory, unable to order list\n", __FUNCTION__);
Chris PeBenito 473ea7
    rc = nreach;
Chris PeBenito 473ea7
    goto out;
Chris PeBenito 473ea7
}
Chris PeBenito 473ea7
hidden_def(get_ordered_context_list)