#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "context_internal.h"
#include "debug.h"
#include "private.h"
struct sepol_context {
/* Selinux user */
char *user;
/* Selinux role */
char *role;
/* Selinux type */
char *type;
/* MLS */
char *mls;
};
/* User */
const char *sepol_context_get_user(const sepol_context_t * con)
{
return con->user;
}
hidden_def(sepol_context_get_user)
int sepol_context_set_user(sepol_handle_t * handle,
sepol_context_t * con, const char *user)
{
char *tmp_user = strdup(user);
if (!tmp_user) {
ERR(handle, "out of memory, could not set "
"context user to %s", user);
return STATUS_ERR;
}
free(con->user);
con->user = tmp_user;
return STATUS_SUCCESS;
}
hidden_def(sepol_context_set_user)
/* Role */
const char *sepol_context_get_role(const sepol_context_t * con)
{
return con->role;
}
hidden_def(sepol_context_get_role)
int sepol_context_set_role(sepol_handle_t * handle,
sepol_context_t * con, const char *role)
{
char *tmp_role = strdup(role);
if (!tmp_role) {
ERR(handle, "out of memory, could not set "
"context role to %s", role);
return STATUS_ERR;
}
free(con->role);
con->role = tmp_role;
return STATUS_SUCCESS;
}
hidden_def(sepol_context_set_role)
/* Type */
const char *sepol_context_get_type(const sepol_context_t * con)
{
return con->type;
}
hidden_def(sepol_context_get_type)
int sepol_context_set_type(sepol_handle_t * handle,
sepol_context_t * con, const char *type)
{
char *tmp_type = strdup(type);
if (!tmp_type) {
ERR(handle, "out of memory, could not set "
"context type to %s", type);
return STATUS_ERR;
}
free(con->type);
con->type = tmp_type;
return STATUS_SUCCESS;
}
hidden_def(sepol_context_set_type)
/* MLS */
const char *sepol_context_get_mls(const sepol_context_t * con)
{
return con->mls;
}
hidden_def(sepol_context_get_mls)
int sepol_context_set_mls(sepol_handle_t * handle,
sepol_context_t * con, const char *mls)
{
char *tmp_mls = strdup(mls);
if (!tmp_mls) {
ERR(handle, "out of memory, could not set "
"MLS fields to %s", mls);
return STATUS_ERR;
}
free(con->mls);
con->mls = tmp_mls;
return STATUS_SUCCESS;
}
hidden_def(sepol_context_set_mls)
/* Create */
int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
{
sepol_context_t *con =
(sepol_context_t *) malloc(sizeof(sepol_context_t));
if (!con) {
ERR(handle, "out of memory, could not " "create context\n");
return STATUS_ERR;
}
con->user = NULL;
con->role = NULL;
con->type = NULL;
con->mls = NULL;
*con_ptr = con;
return STATUS_SUCCESS;
}
hidden_def(sepol_context_create)
/* Deep copy clone */
int sepol_context_clone(sepol_handle_t * handle,
const sepol_context_t * con, sepol_context_t ** con_ptr)
{
sepol_context_t *new_con = NULL;
if (!con) {
*con_ptr = NULL;
return 0;
}
if (sepol_context_create(handle, &new_con) < 0)
goto err;
if (!(new_con->user = strdup(con->user)))
goto omem;
if (!(new_con->role = strdup(con->role)))
goto omem;
if (!(new_con->type = strdup(con->type)))
goto omem;
if (con->mls && !(new_con->mls = strdup(con->mls)))
goto omem;
*con_ptr = new_con;
return STATUS_SUCCESS;
omem:
ERR(handle, "out of memory");
err:
ERR(handle, "could not clone context record");
sepol_context_free(new_con);
return STATUS_ERR;
}
hidden_def(sepol_context_clone)
/* Destroy */
void sepol_context_free(sepol_context_t * con)
{
if (!con)
return;
free(con->user);
free(con->role);
free(con->type);
free(con->mls);
free(con);
}
hidden_def(sepol_context_free)
int sepol_context_from_string(sepol_handle_t * handle,
const char *str, sepol_context_t ** con)
{
char *tmp = NULL, *low, *high;
sepol_context_t *tmp_con = NULL;
if (!strcmp(str, "<<none>>")) {
*con = NULL;
return STATUS_SUCCESS;
}
if (sepol_context_create(handle, &tmp_con) < 0)
goto err;
/* Working copy context */
tmp = strdup(str);
if (!tmp) {
ERR(handle, "out of memory");
goto err;
}
low = tmp;
/* Then, break it into its components */
/* User */
if (!(high = strchr(low, ':')))
goto mcontext;
else
*high++ = '\0';
if (sepol_context_set_user(handle, tmp_con, low) < 0)
goto err;
low = high;
/* Role */
if (!(high = strchr(low, ':')))
goto mcontext;
else
*high++ = '\0';
if (sepol_context_set_role(handle, tmp_con, low) < 0)
goto err;
low = high;
/* Type, and possibly MLS */
if (!(high = strchr(low, ':'))) {
if (sepol_context_set_type(handle, tmp_con, low) < 0)
goto err;
} else {
*high++ = '\0';
if (sepol_context_set_type(handle, tmp_con, low) < 0)
goto err;
low = high;
if (sepol_context_set_mls(handle, tmp_con, low) < 0)
goto err;
}
free(tmp);
*con = tmp_con;
return STATUS_SUCCESS;
mcontext:
errno = EINVAL;
ERR(handle, "malformed context \"%s\"", str);
err:
ERR(handle, "could not construct context from string");
free(tmp);
sepol_context_free(tmp_con);
return STATUS_ERR;
}
hidden_def(sepol_context_from_string)
static inline int safe_sum(size_t *sum, const size_t augends[], const size_t cnt) {
size_t a, i;
*sum = 0;
for(i=0; i < cnt; i++) {
/* sum should not be smaller than the addend */
a = augends[i];
*sum += a;
if (*sum < a) {
return i;
}
}
return 0;
}
int sepol_context_to_string(sepol_handle_t * handle,
const sepol_context_t * con, char **str_ptr)
{
int rc;
char *str = NULL;
size_t total_sz, err;
const size_t sizes[] = {
strlen(con->user), /* user length */
strlen(con->role), /* role length */
strlen(con->type), /* type length */
(con->mls) ? strlen(con->mls) : 0, /* mls length */
((con->mls) ? 3 : 2) + 1 /* mls has extra ":" also null byte */
};
err = safe_sum(&total_sz, sizes, ARRAY_SIZE(sizes));
if (err) {
ERR(handle, "invalid size, overflow at position: %zu", err);
goto err;
}
str = (char *)malloc(total_sz);
if (!str) {
ERR(handle, "out of memory");
goto err;
}
if (con->mls) {
rc = snprintf(str, total_sz, "%s:%s:%s:%s",
con->user, con->role, con->type, con->mls);
} else {
rc = snprintf(str, total_sz, "%s:%s:%s",
con->user, con->role, con->type);
}
/*
* rc is >= 0 on the size_t cast and is safe to promote
* to an unsigned value.
*/
if (rc < 0 || (size_t)rc >= total_sz) {
ERR(handle, "print error");
goto err;
}
*str_ptr = str;
return STATUS_SUCCESS;
err:
ERR(handle, "could not convert context to string");
free(str);
return STATUS_ERR;
}