16cd6a6acSopenharmony_ci#include <errno.h> 26cd6a6acSopenharmony_ci#include <stdlib.h> 36cd6a6acSopenharmony_ci#include <string.h> 46cd6a6acSopenharmony_ci#include <stdio.h> 56cd6a6acSopenharmony_ci 66cd6a6acSopenharmony_ci#include "context_internal.h" 76cd6a6acSopenharmony_ci#include "debug.h" 86cd6a6acSopenharmony_ci#include "private.h" 96cd6a6acSopenharmony_ci 106cd6a6acSopenharmony_cistruct sepol_context { 116cd6a6acSopenharmony_ci 126cd6a6acSopenharmony_ci /* Selinux user */ 136cd6a6acSopenharmony_ci char *user; 146cd6a6acSopenharmony_ci 156cd6a6acSopenharmony_ci /* Selinux role */ 166cd6a6acSopenharmony_ci char *role; 176cd6a6acSopenharmony_ci 186cd6a6acSopenharmony_ci /* Selinux type */ 196cd6a6acSopenharmony_ci char *type; 206cd6a6acSopenharmony_ci 216cd6a6acSopenharmony_ci /* MLS */ 226cd6a6acSopenharmony_ci char *mls; 236cd6a6acSopenharmony_ci}; 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci/* User */ 266cd6a6acSopenharmony_ciconst char *sepol_context_get_user(const sepol_context_t * con) 276cd6a6acSopenharmony_ci{ 286cd6a6acSopenharmony_ci 296cd6a6acSopenharmony_ci return con->user; 306cd6a6acSopenharmony_ci} 316cd6a6acSopenharmony_ci 326cd6a6acSopenharmony_ci 336cd6a6acSopenharmony_ciint sepol_context_set_user(sepol_handle_t * handle, 346cd6a6acSopenharmony_ci sepol_context_t * con, const char *user) 356cd6a6acSopenharmony_ci{ 366cd6a6acSopenharmony_ci 376cd6a6acSopenharmony_ci char *tmp_user = strdup(user); 386cd6a6acSopenharmony_ci if (!tmp_user) { 396cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not set " 406cd6a6acSopenharmony_ci "context user to %s", user); 416cd6a6acSopenharmony_ci return STATUS_ERR; 426cd6a6acSopenharmony_ci } 436cd6a6acSopenharmony_ci 446cd6a6acSopenharmony_ci free(con->user); 456cd6a6acSopenharmony_ci con->user = tmp_user; 466cd6a6acSopenharmony_ci return STATUS_SUCCESS; 476cd6a6acSopenharmony_ci} 486cd6a6acSopenharmony_ci 496cd6a6acSopenharmony_ci 506cd6a6acSopenharmony_ci/* Role */ 516cd6a6acSopenharmony_ciconst char *sepol_context_get_role(const sepol_context_t * con) 526cd6a6acSopenharmony_ci{ 536cd6a6acSopenharmony_ci 546cd6a6acSopenharmony_ci return con->role; 556cd6a6acSopenharmony_ci} 566cd6a6acSopenharmony_ci 576cd6a6acSopenharmony_ci 586cd6a6acSopenharmony_ciint sepol_context_set_role(sepol_handle_t * handle, 596cd6a6acSopenharmony_ci sepol_context_t * con, const char *role) 606cd6a6acSopenharmony_ci{ 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_ci char *tmp_role = strdup(role); 636cd6a6acSopenharmony_ci if (!tmp_role) { 646cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not set " 656cd6a6acSopenharmony_ci "context role to %s", role); 666cd6a6acSopenharmony_ci return STATUS_ERR; 676cd6a6acSopenharmony_ci } 686cd6a6acSopenharmony_ci free(con->role); 696cd6a6acSopenharmony_ci con->role = tmp_role; 706cd6a6acSopenharmony_ci return STATUS_SUCCESS; 716cd6a6acSopenharmony_ci} 726cd6a6acSopenharmony_ci 736cd6a6acSopenharmony_ci 746cd6a6acSopenharmony_ci/* Type */ 756cd6a6acSopenharmony_ciconst char *sepol_context_get_type(const sepol_context_t * con) 766cd6a6acSopenharmony_ci{ 776cd6a6acSopenharmony_ci 786cd6a6acSopenharmony_ci return con->type; 796cd6a6acSopenharmony_ci} 806cd6a6acSopenharmony_ci 816cd6a6acSopenharmony_ci 826cd6a6acSopenharmony_ciint sepol_context_set_type(sepol_handle_t * handle, 836cd6a6acSopenharmony_ci sepol_context_t * con, const char *type) 846cd6a6acSopenharmony_ci{ 856cd6a6acSopenharmony_ci 866cd6a6acSopenharmony_ci char *tmp_type = strdup(type); 876cd6a6acSopenharmony_ci if (!tmp_type) { 886cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not set " 896cd6a6acSopenharmony_ci "context type to %s", type); 906cd6a6acSopenharmony_ci return STATUS_ERR; 916cd6a6acSopenharmony_ci } 926cd6a6acSopenharmony_ci free(con->type); 936cd6a6acSopenharmony_ci con->type = tmp_type; 946cd6a6acSopenharmony_ci return STATUS_SUCCESS; 956cd6a6acSopenharmony_ci} 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_ci 986cd6a6acSopenharmony_ci/* MLS */ 996cd6a6acSopenharmony_ciconst char *sepol_context_get_mls(const sepol_context_t * con) 1006cd6a6acSopenharmony_ci{ 1016cd6a6acSopenharmony_ci 1026cd6a6acSopenharmony_ci return con->mls; 1036cd6a6acSopenharmony_ci} 1046cd6a6acSopenharmony_ci 1056cd6a6acSopenharmony_ci 1066cd6a6acSopenharmony_ciint sepol_context_set_mls(sepol_handle_t * handle, 1076cd6a6acSopenharmony_ci sepol_context_t * con, const char *mls) 1086cd6a6acSopenharmony_ci{ 1096cd6a6acSopenharmony_ci 1106cd6a6acSopenharmony_ci char *tmp_mls = strdup(mls); 1116cd6a6acSopenharmony_ci if (!tmp_mls) { 1126cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not set " 1136cd6a6acSopenharmony_ci "MLS fields to %s", mls); 1146cd6a6acSopenharmony_ci return STATUS_ERR; 1156cd6a6acSopenharmony_ci } 1166cd6a6acSopenharmony_ci free(con->mls); 1176cd6a6acSopenharmony_ci con->mls = tmp_mls; 1186cd6a6acSopenharmony_ci return STATUS_SUCCESS; 1196cd6a6acSopenharmony_ci} 1206cd6a6acSopenharmony_ci 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci/* Create */ 1236cd6a6acSopenharmony_ciint sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr) 1246cd6a6acSopenharmony_ci{ 1256cd6a6acSopenharmony_ci 1266cd6a6acSopenharmony_ci sepol_context_t *con = 1276cd6a6acSopenharmony_ci (sepol_context_t *) malloc(sizeof(sepol_context_t)); 1286cd6a6acSopenharmony_ci 1296cd6a6acSopenharmony_ci if (!con) { 1306cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not create context"); 1316cd6a6acSopenharmony_ci return STATUS_ERR; 1326cd6a6acSopenharmony_ci } 1336cd6a6acSopenharmony_ci 1346cd6a6acSopenharmony_ci con->user = NULL; 1356cd6a6acSopenharmony_ci con->role = NULL; 1366cd6a6acSopenharmony_ci con->type = NULL; 1376cd6a6acSopenharmony_ci con->mls = NULL; 1386cd6a6acSopenharmony_ci *con_ptr = con; 1396cd6a6acSopenharmony_ci return STATUS_SUCCESS; 1406cd6a6acSopenharmony_ci} 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ci/* Deep copy clone */ 1446cd6a6acSopenharmony_ciint sepol_context_clone(sepol_handle_t * handle, 1456cd6a6acSopenharmony_ci const sepol_context_t * con, sepol_context_t ** con_ptr) 1466cd6a6acSopenharmony_ci{ 1476cd6a6acSopenharmony_ci 1486cd6a6acSopenharmony_ci sepol_context_t *new_con = NULL; 1496cd6a6acSopenharmony_ci 1506cd6a6acSopenharmony_ci if (!con) { 1516cd6a6acSopenharmony_ci *con_ptr = NULL; 1526cd6a6acSopenharmony_ci return 0; 1536cd6a6acSopenharmony_ci } 1546cd6a6acSopenharmony_ci 1556cd6a6acSopenharmony_ci if (sepol_context_create(handle, &new_con) < 0) 1566cd6a6acSopenharmony_ci goto err; 1576cd6a6acSopenharmony_ci 1586cd6a6acSopenharmony_ci if (!(new_con->user = strdup(con->user))) 1596cd6a6acSopenharmony_ci goto omem; 1606cd6a6acSopenharmony_ci 1616cd6a6acSopenharmony_ci if (!(new_con->role = strdup(con->role))) 1626cd6a6acSopenharmony_ci goto omem; 1636cd6a6acSopenharmony_ci 1646cd6a6acSopenharmony_ci if (!(new_con->type = strdup(con->type))) 1656cd6a6acSopenharmony_ci goto omem; 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_ci if (con->mls && !(new_con->mls = strdup(con->mls))) 1686cd6a6acSopenharmony_ci goto omem; 1696cd6a6acSopenharmony_ci 1706cd6a6acSopenharmony_ci *con_ptr = new_con; 1716cd6a6acSopenharmony_ci return STATUS_SUCCESS; 1726cd6a6acSopenharmony_ci 1736cd6a6acSopenharmony_ci omem: 1746cd6a6acSopenharmony_ci ERR(handle, "out of memory"); 1756cd6a6acSopenharmony_ci 1766cd6a6acSopenharmony_ci err: 1776cd6a6acSopenharmony_ci ERR(handle, "could not clone context record"); 1786cd6a6acSopenharmony_ci sepol_context_free(new_con); 1796cd6a6acSopenharmony_ci return STATUS_ERR; 1806cd6a6acSopenharmony_ci} 1816cd6a6acSopenharmony_ci 1826cd6a6acSopenharmony_ci 1836cd6a6acSopenharmony_ci/* Destroy */ 1846cd6a6acSopenharmony_civoid sepol_context_free(sepol_context_t * con) 1856cd6a6acSopenharmony_ci{ 1866cd6a6acSopenharmony_ci 1876cd6a6acSopenharmony_ci if (!con) 1886cd6a6acSopenharmony_ci return; 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ci free(con->user); 1916cd6a6acSopenharmony_ci free(con->role); 1926cd6a6acSopenharmony_ci free(con->type); 1936cd6a6acSopenharmony_ci free(con->mls); 1946cd6a6acSopenharmony_ci free(con); 1956cd6a6acSopenharmony_ci} 1966cd6a6acSopenharmony_ci 1976cd6a6acSopenharmony_ci 1986cd6a6acSopenharmony_ciint sepol_context_from_string(sepol_handle_t * handle, 1996cd6a6acSopenharmony_ci const char *str, sepol_context_t ** con) 2006cd6a6acSopenharmony_ci{ 2016cd6a6acSopenharmony_ci 2026cd6a6acSopenharmony_ci char *tmp = NULL, *low, *high; 2036cd6a6acSopenharmony_ci sepol_context_t *tmp_con = NULL; 2046cd6a6acSopenharmony_ci 2056cd6a6acSopenharmony_ci if (!strcmp(str, "<<none>>")) { 2066cd6a6acSopenharmony_ci *con = NULL; 2076cd6a6acSopenharmony_ci return STATUS_SUCCESS; 2086cd6a6acSopenharmony_ci } 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci if (sepol_context_create(handle, &tmp_con) < 0) 2116cd6a6acSopenharmony_ci goto err; 2126cd6a6acSopenharmony_ci 2136cd6a6acSopenharmony_ci /* Working copy context */ 2146cd6a6acSopenharmony_ci tmp = strdup(str); 2156cd6a6acSopenharmony_ci if (!tmp) { 2166cd6a6acSopenharmony_ci ERR(handle, "out of memory"); 2176cd6a6acSopenharmony_ci goto err; 2186cd6a6acSopenharmony_ci } 2196cd6a6acSopenharmony_ci low = tmp; 2206cd6a6acSopenharmony_ci 2216cd6a6acSopenharmony_ci /* Then, break it into its components */ 2226cd6a6acSopenharmony_ci 2236cd6a6acSopenharmony_ci /* User */ 2246cd6a6acSopenharmony_ci if (!(high = strchr(low, ':'))) 2256cd6a6acSopenharmony_ci goto mcontext; 2266cd6a6acSopenharmony_ci else 2276cd6a6acSopenharmony_ci *high++ = '\0'; 2286cd6a6acSopenharmony_ci if (sepol_context_set_user(handle, tmp_con, low) < 0) 2296cd6a6acSopenharmony_ci goto err; 2306cd6a6acSopenharmony_ci low = high; 2316cd6a6acSopenharmony_ci 2326cd6a6acSopenharmony_ci /* Role */ 2336cd6a6acSopenharmony_ci if (!(high = strchr(low, ':'))) 2346cd6a6acSopenharmony_ci goto mcontext; 2356cd6a6acSopenharmony_ci else 2366cd6a6acSopenharmony_ci *high++ = '\0'; 2376cd6a6acSopenharmony_ci if (sepol_context_set_role(handle, tmp_con, low) < 0) 2386cd6a6acSopenharmony_ci goto err; 2396cd6a6acSopenharmony_ci low = high; 2406cd6a6acSopenharmony_ci 2416cd6a6acSopenharmony_ci /* Type, and possibly MLS */ 2426cd6a6acSopenharmony_ci if (!(high = strchr(low, ':'))) { 2436cd6a6acSopenharmony_ci if (sepol_context_set_type(handle, tmp_con, low) < 0) 2446cd6a6acSopenharmony_ci goto err; 2456cd6a6acSopenharmony_ci } else { 2466cd6a6acSopenharmony_ci *high++ = '\0'; 2476cd6a6acSopenharmony_ci if (sepol_context_set_type(handle, tmp_con, low) < 0) 2486cd6a6acSopenharmony_ci goto err; 2496cd6a6acSopenharmony_ci low = high; 2506cd6a6acSopenharmony_ci if (sepol_context_set_mls(handle, tmp_con, low) < 0) 2516cd6a6acSopenharmony_ci goto err; 2526cd6a6acSopenharmony_ci } 2536cd6a6acSopenharmony_ci 2546cd6a6acSopenharmony_ci free(tmp); 2556cd6a6acSopenharmony_ci *con = tmp_con; 2566cd6a6acSopenharmony_ci 2576cd6a6acSopenharmony_ci return STATUS_SUCCESS; 2586cd6a6acSopenharmony_ci 2596cd6a6acSopenharmony_ci mcontext: 2606cd6a6acSopenharmony_ci errno = EINVAL; 2616cd6a6acSopenharmony_ci ERR(handle, "malformed context \"%s\"", str); 2626cd6a6acSopenharmony_ci 2636cd6a6acSopenharmony_ci err: 2646cd6a6acSopenharmony_ci ERR(handle, "could not construct context from string"); 2656cd6a6acSopenharmony_ci free(tmp); 2666cd6a6acSopenharmony_ci sepol_context_free(tmp_con); 2676cd6a6acSopenharmony_ci return STATUS_ERR; 2686cd6a6acSopenharmony_ci} 2696cd6a6acSopenharmony_ci 2706cd6a6acSopenharmony_ciint sepol_context_to_string(sepol_handle_t * handle, 2716cd6a6acSopenharmony_ci const sepol_context_t * con, char **str_ptr) 2726cd6a6acSopenharmony_ci{ 2736cd6a6acSopenharmony_ci 2746cd6a6acSopenharmony_ci int rc; 2756cd6a6acSopenharmony_ci char *str = NULL; 2766cd6a6acSopenharmony_ci size_t total_sz = 0, i; 2776cd6a6acSopenharmony_ci const size_t sizes[] = { 2786cd6a6acSopenharmony_ci strlen(con->user), /* user length */ 2796cd6a6acSopenharmony_ci strlen(con->role), /* role length */ 2806cd6a6acSopenharmony_ci strlen(con->type), /* type length */ 2816cd6a6acSopenharmony_ci (con->mls) ? strlen(con->mls) : 0, /* mls length */ 2826cd6a6acSopenharmony_ci ((con->mls) ? 3 : 2) + 1 /* mls has extra ":" also null byte */ 2836cd6a6acSopenharmony_ci }; 2846cd6a6acSopenharmony_ci 2856cd6a6acSopenharmony_ci for (i = 0; i < ARRAY_SIZE(sizes); i++) { 2866cd6a6acSopenharmony_ci if (__builtin_add_overflow(total_sz, sizes[i], &total_sz)) { 2876cd6a6acSopenharmony_ci ERR(handle, "invalid size, overflow at position: %zu", i); 2886cd6a6acSopenharmony_ci goto err; 2896cd6a6acSopenharmony_ci } 2906cd6a6acSopenharmony_ci } 2916cd6a6acSopenharmony_ci 2926cd6a6acSopenharmony_ci str = (char *)malloc(total_sz); 2936cd6a6acSopenharmony_ci if (!str) { 2946cd6a6acSopenharmony_ci ERR(handle, "out of memory"); 2956cd6a6acSopenharmony_ci goto err; 2966cd6a6acSopenharmony_ci } 2976cd6a6acSopenharmony_ci if (con->mls) { 2986cd6a6acSopenharmony_ci rc = snprintf(str, total_sz, "%s:%s:%s:%s", 2996cd6a6acSopenharmony_ci con->user, con->role, con->type, con->mls); 3006cd6a6acSopenharmony_ci } else { 3016cd6a6acSopenharmony_ci rc = snprintf(str, total_sz, "%s:%s:%s", 3026cd6a6acSopenharmony_ci con->user, con->role, con->type); 3036cd6a6acSopenharmony_ci } 3046cd6a6acSopenharmony_ci 3056cd6a6acSopenharmony_ci /* 3066cd6a6acSopenharmony_ci * rc is >= 0 on the size_t cast and is safe to promote 3076cd6a6acSopenharmony_ci * to an unsigned value. 3086cd6a6acSopenharmony_ci */ 3096cd6a6acSopenharmony_ci if (rc < 0 || (size_t)rc >= total_sz) { 3106cd6a6acSopenharmony_ci ERR(handle, "print error"); 3116cd6a6acSopenharmony_ci goto err; 3126cd6a6acSopenharmony_ci } 3136cd6a6acSopenharmony_ci 3146cd6a6acSopenharmony_ci *str_ptr = str; 3156cd6a6acSopenharmony_ci return STATUS_SUCCESS; 3166cd6a6acSopenharmony_ci 3176cd6a6acSopenharmony_ci err: 3186cd6a6acSopenharmony_ci ERR(handle, "could not convert context to string"); 3196cd6a6acSopenharmony_ci free(str); 3206cd6a6acSopenharmony_ci return STATUS_ERR; 3216cd6a6acSopenharmony_ci} 322