16cd6a6acSopenharmony_ci#include <unistd.h> 26cd6a6acSopenharmony_ci#include <errno.h> 36cd6a6acSopenharmony_ci#include <stdio.h> 46cd6a6acSopenharmony_ci#include <stdio_ext.h> 56cd6a6acSopenharmony_ci#include <stdint.h> 66cd6a6acSopenharmony_ci#include <stdlib.h> 76cd6a6acSopenharmony_ci#include <string.h> 86cd6a6acSopenharmony_ci#include <ctype.h> 96cd6a6acSopenharmony_ci#include <pwd.h> 106cd6a6acSopenharmony_ci#include "selinux_internal.h" 116cd6a6acSopenharmony_ci#include "context_internal.h" 126cd6a6acSopenharmony_ci#include "get_context_list_internal.h" 136cd6a6acSopenharmony_ci 146cd6a6acSopenharmony_ciint get_default_context_with_role(const char *user, 156cd6a6acSopenharmony_ci const char *role, 166cd6a6acSopenharmony_ci const char *fromcon, 176cd6a6acSopenharmony_ci char ** newcon) 186cd6a6acSopenharmony_ci{ 196cd6a6acSopenharmony_ci char **conary; 206cd6a6acSopenharmony_ci char **ptr; 216cd6a6acSopenharmony_ci context_t con; 226cd6a6acSopenharmony_ci const char *role2; 236cd6a6acSopenharmony_ci int rc; 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci rc = get_ordered_context_list(user, fromcon, &conary); 266cd6a6acSopenharmony_ci if (rc <= 0) 276cd6a6acSopenharmony_ci return -1; 286cd6a6acSopenharmony_ci 296cd6a6acSopenharmony_ci for (ptr = conary; *ptr; ptr++) { 306cd6a6acSopenharmony_ci con = context_new(*ptr); 316cd6a6acSopenharmony_ci if (!con) 326cd6a6acSopenharmony_ci continue; 336cd6a6acSopenharmony_ci role2 = context_role_get(con); 346cd6a6acSopenharmony_ci if (role2 && !strcmp(role, role2)) { 356cd6a6acSopenharmony_ci context_free(con); 366cd6a6acSopenharmony_ci break; 376cd6a6acSopenharmony_ci } 386cd6a6acSopenharmony_ci context_free(con); 396cd6a6acSopenharmony_ci } 406cd6a6acSopenharmony_ci 416cd6a6acSopenharmony_ci rc = -1; 426cd6a6acSopenharmony_ci if (!(*ptr)) { 436cd6a6acSopenharmony_ci errno = EINVAL; 446cd6a6acSopenharmony_ci goto out; 456cd6a6acSopenharmony_ci } 466cd6a6acSopenharmony_ci *newcon = strdup(*ptr); 476cd6a6acSopenharmony_ci if (!(*newcon)) 486cd6a6acSopenharmony_ci goto out; 496cd6a6acSopenharmony_ci rc = 0; 506cd6a6acSopenharmony_ci out: 516cd6a6acSopenharmony_ci freeconary(conary); 526cd6a6acSopenharmony_ci return rc; 536cd6a6acSopenharmony_ci} 546cd6a6acSopenharmony_ci 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ciint get_default_context_with_rolelevel(const char *user, 576cd6a6acSopenharmony_ci const char *role, 586cd6a6acSopenharmony_ci const char *level, 596cd6a6acSopenharmony_ci const char *fromcon, 606cd6a6acSopenharmony_ci char ** newcon) 616cd6a6acSopenharmony_ci{ 626cd6a6acSopenharmony_ci 636cd6a6acSopenharmony_ci int rc; 646cd6a6acSopenharmony_ci char *backup_fromcon = NULL; 656cd6a6acSopenharmony_ci context_t con; 666cd6a6acSopenharmony_ci const char *newfromcon; 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_ci if (!level) 696cd6a6acSopenharmony_ci return get_default_context_with_role(user, role, fromcon, 706cd6a6acSopenharmony_ci newcon); 716cd6a6acSopenharmony_ci 726cd6a6acSopenharmony_ci if (!fromcon) { 736cd6a6acSopenharmony_ci rc = getcon(&backup_fromcon); 746cd6a6acSopenharmony_ci if (rc < 0) 756cd6a6acSopenharmony_ci return rc; 766cd6a6acSopenharmony_ci fromcon = backup_fromcon; 776cd6a6acSopenharmony_ci } 786cd6a6acSopenharmony_ci 796cd6a6acSopenharmony_ci rc = -1; 806cd6a6acSopenharmony_ci con = context_new(fromcon); 816cd6a6acSopenharmony_ci if (!con) 826cd6a6acSopenharmony_ci goto out; 836cd6a6acSopenharmony_ci 846cd6a6acSopenharmony_ci if (context_range_set(con, level)) 856cd6a6acSopenharmony_ci goto out; 866cd6a6acSopenharmony_ci 876cd6a6acSopenharmony_ci newfromcon = context_str(con); 886cd6a6acSopenharmony_ci if (!newfromcon) 896cd6a6acSopenharmony_ci goto out; 906cd6a6acSopenharmony_ci 916cd6a6acSopenharmony_ci rc = get_default_context_with_role(user, role, newfromcon, newcon); 926cd6a6acSopenharmony_ci 936cd6a6acSopenharmony_ci out: 946cd6a6acSopenharmony_ci context_free(con); 956cd6a6acSopenharmony_ci freecon(backup_fromcon); 966cd6a6acSopenharmony_ci return rc; 976cd6a6acSopenharmony_ci 986cd6a6acSopenharmony_ci} 996cd6a6acSopenharmony_ci 1006cd6a6acSopenharmony_ciint get_default_context(const char *user, 1016cd6a6acSopenharmony_ci const char *fromcon, char ** newcon) 1026cd6a6acSopenharmony_ci{ 1036cd6a6acSopenharmony_ci char **conary; 1046cd6a6acSopenharmony_ci int rc; 1056cd6a6acSopenharmony_ci 1066cd6a6acSopenharmony_ci rc = get_ordered_context_list(user, fromcon, &conary); 1076cd6a6acSopenharmony_ci if (rc <= 0) 1086cd6a6acSopenharmony_ci return -1; 1096cd6a6acSopenharmony_ci 1106cd6a6acSopenharmony_ci *newcon = strdup(conary[0]); 1116cd6a6acSopenharmony_ci freeconary(conary); 1126cd6a6acSopenharmony_ci if (!(*newcon)) 1136cd6a6acSopenharmony_ci return -1; 1146cd6a6acSopenharmony_ci return 0; 1156cd6a6acSopenharmony_ci} 1166cd6a6acSopenharmony_ci 1176cd6a6acSopenharmony_cistatic int is_in_reachable(char **reachable, const char *usercon_str) 1186cd6a6acSopenharmony_ci{ 1196cd6a6acSopenharmony_ci if (!reachable) 1206cd6a6acSopenharmony_ci return 0; 1216cd6a6acSopenharmony_ci 1226cd6a6acSopenharmony_ci for (; *reachable != NULL; reachable++) { 1236cd6a6acSopenharmony_ci if (strcmp(*reachable, usercon_str) == 0) { 1246cd6a6acSopenharmony_ci return 1; 1256cd6a6acSopenharmony_ci } 1266cd6a6acSopenharmony_ci } 1276cd6a6acSopenharmony_ci return 0; 1286cd6a6acSopenharmony_ci} 1296cd6a6acSopenharmony_ci 1306cd6a6acSopenharmony_cistatic int get_context_user(FILE * fp, 1316cd6a6acSopenharmony_ci const char * fromcon, 1326cd6a6acSopenharmony_ci const char * user, 1336cd6a6acSopenharmony_ci char ***reachable, 1346cd6a6acSopenharmony_ci unsigned int *nreachable) 1356cd6a6acSopenharmony_ci{ 1366cd6a6acSopenharmony_ci char *start, *end = NULL; 1376cd6a6acSopenharmony_ci char *line = NULL; 1386cd6a6acSopenharmony_ci size_t line_len = 0, usercon_len; 1396cd6a6acSopenharmony_ci size_t user_len = strlen(user); 1406cd6a6acSopenharmony_ci ssize_t len; 1416cd6a6acSopenharmony_ci int found = 0; 1426cd6a6acSopenharmony_ci const char *fromrole, *fromtype, *fromlevel; 1436cd6a6acSopenharmony_ci char *linerole, *linetype; 1446cd6a6acSopenharmony_ci char **new_reachable = NULL; 1456cd6a6acSopenharmony_ci char *usercon_str; 1466cd6a6acSopenharmony_ci const char *usercon_str2; 1476cd6a6acSopenharmony_ci context_t con; 1486cd6a6acSopenharmony_ci context_t usercon; 1496cd6a6acSopenharmony_ci 1506cd6a6acSopenharmony_ci int rc; 1516cd6a6acSopenharmony_ci 1526cd6a6acSopenharmony_ci errno = EINVAL; 1536cd6a6acSopenharmony_ci 1546cd6a6acSopenharmony_ci /* Extract the role and type of the fromcon for matching. 1556cd6a6acSopenharmony_ci User identity and MLS range can be variable. */ 1566cd6a6acSopenharmony_ci con = context_new(fromcon); 1576cd6a6acSopenharmony_ci if (!con) 1586cd6a6acSopenharmony_ci return -1; 1596cd6a6acSopenharmony_ci fromrole = context_role_get(con); 1606cd6a6acSopenharmony_ci fromtype = context_type_get(con); 1616cd6a6acSopenharmony_ci fromlevel = context_range_get(con); 1626cd6a6acSopenharmony_ci if (!fromrole || !fromtype) { 1636cd6a6acSopenharmony_ci context_free(con); 1646cd6a6acSopenharmony_ci return -1; 1656cd6a6acSopenharmony_ci } 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_ci while ((len = getline(&line, &line_len, fp)) > 0) { 1686cd6a6acSopenharmony_ci if (line[len - 1] == '\n') 1696cd6a6acSopenharmony_ci line[len - 1] = 0; 1706cd6a6acSopenharmony_ci 1716cd6a6acSopenharmony_ci /* Skip leading whitespace. */ 1726cd6a6acSopenharmony_ci start = line; 1736cd6a6acSopenharmony_ci while (*start && isspace(*start)) 1746cd6a6acSopenharmony_ci start++; 1756cd6a6acSopenharmony_ci if (!(*start)) 1766cd6a6acSopenharmony_ci continue; 1776cd6a6acSopenharmony_ci 1786cd6a6acSopenharmony_ci /* Find the end of the (partial) fromcon in the line. */ 1796cd6a6acSopenharmony_ci end = start; 1806cd6a6acSopenharmony_ci while (*end && !isspace(*end)) 1816cd6a6acSopenharmony_ci end++; 1826cd6a6acSopenharmony_ci if (!(*end)) 1836cd6a6acSopenharmony_ci continue; 1846cd6a6acSopenharmony_ci 1856cd6a6acSopenharmony_ci /* Check for a match. */ 1866cd6a6acSopenharmony_ci linerole = start; 1876cd6a6acSopenharmony_ci while (*start && !isspace(*start) && *start != ':') 1886cd6a6acSopenharmony_ci start++; 1896cd6a6acSopenharmony_ci if (*start != ':') 1906cd6a6acSopenharmony_ci continue; 1916cd6a6acSopenharmony_ci *start = 0; 1926cd6a6acSopenharmony_ci linetype = ++start; 1936cd6a6acSopenharmony_ci while (*start && !isspace(*start) && *start != ':') 1946cd6a6acSopenharmony_ci start++; 1956cd6a6acSopenharmony_ci if (!(*start)) 1966cd6a6acSopenharmony_ci continue; 1976cd6a6acSopenharmony_ci *start = 0; 1986cd6a6acSopenharmony_ci if (!strcmp(fromrole, linerole) && !strcmp(fromtype, linetype)) { 1996cd6a6acSopenharmony_ci found = 1; 2006cd6a6acSopenharmony_ci break; 2016cd6a6acSopenharmony_ci } 2026cd6a6acSopenharmony_ci } 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci if (!found) { 2056cd6a6acSopenharmony_ci errno = ENOENT; 2066cd6a6acSopenharmony_ci rc = -1; 2076cd6a6acSopenharmony_ci goto out; 2086cd6a6acSopenharmony_ci } 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci start = ++end; 2116cd6a6acSopenharmony_ci while (*start) { 2126cd6a6acSopenharmony_ci /* Skip leading whitespace */ 2136cd6a6acSopenharmony_ci while (*start && isspace(*start)) 2146cd6a6acSopenharmony_ci start++; 2156cd6a6acSopenharmony_ci if (!(*start)) 2166cd6a6acSopenharmony_ci break; 2176cd6a6acSopenharmony_ci 2186cd6a6acSopenharmony_ci /* Find the end of this partial context. */ 2196cd6a6acSopenharmony_ci end = start; 2206cd6a6acSopenharmony_ci while (*end && !isspace(*end)) 2216cd6a6acSopenharmony_ci end++; 2226cd6a6acSopenharmony_ci if (*end) 2236cd6a6acSopenharmony_ci *end++ = 0; 2246cd6a6acSopenharmony_ci 2256cd6a6acSopenharmony_ci /* Check whether a new context is valid */ 2266cd6a6acSopenharmony_ci if (SIZE_MAX - user_len < strlen(start) + 2) { 2276cd6a6acSopenharmony_ci fprintf(stderr, "%s: one of partial contexts is too big\n", __FUNCTION__); 2286cd6a6acSopenharmony_ci errno = EINVAL; 2296cd6a6acSopenharmony_ci rc = -1; 2306cd6a6acSopenharmony_ci goto out; 2316cd6a6acSopenharmony_ci } 2326cd6a6acSopenharmony_ci usercon_len = user_len + strlen(start) + 2; 2336cd6a6acSopenharmony_ci usercon_str = malloc(usercon_len); 2346cd6a6acSopenharmony_ci if (!usercon_str) { 2356cd6a6acSopenharmony_ci rc = -1; 2366cd6a6acSopenharmony_ci goto out; 2376cd6a6acSopenharmony_ci } 2386cd6a6acSopenharmony_ci 2396cd6a6acSopenharmony_ci /* set range from fromcon in the new usercon */ 2406cd6a6acSopenharmony_ci snprintf(usercon_str, usercon_len, "%s:%s", user, start); 2416cd6a6acSopenharmony_ci usercon = context_new(usercon_str); 2426cd6a6acSopenharmony_ci if (!usercon) { 2436cd6a6acSopenharmony_ci if (errno != EINVAL) { 2446cd6a6acSopenharmony_ci free(usercon_str); 2456cd6a6acSopenharmony_ci rc = -1; 2466cd6a6acSopenharmony_ci goto out; 2476cd6a6acSopenharmony_ci } 2486cd6a6acSopenharmony_ci fprintf(stderr, 2496cd6a6acSopenharmony_ci "%s: can't create a context from %s, skipping\n", 2506cd6a6acSopenharmony_ci __FUNCTION__, usercon_str); 2516cd6a6acSopenharmony_ci free(usercon_str); 2526cd6a6acSopenharmony_ci start = end; 2536cd6a6acSopenharmony_ci continue; 2546cd6a6acSopenharmony_ci } 2556cd6a6acSopenharmony_ci free(usercon_str); 2566cd6a6acSopenharmony_ci if (context_range_set(usercon, fromlevel) != 0) { 2576cd6a6acSopenharmony_ci context_free(usercon); 2586cd6a6acSopenharmony_ci rc = -1; 2596cd6a6acSopenharmony_ci goto out; 2606cd6a6acSopenharmony_ci } 2616cd6a6acSopenharmony_ci usercon_str2 = context_str(usercon); 2626cd6a6acSopenharmony_ci if (!usercon_str2) { 2636cd6a6acSopenharmony_ci context_free(usercon); 2646cd6a6acSopenharmony_ci rc = -1; 2656cd6a6acSopenharmony_ci goto out; 2666cd6a6acSopenharmony_ci } 2676cd6a6acSopenharmony_ci 2686cd6a6acSopenharmony_ci /* check whether usercon is already in reachable */ 2696cd6a6acSopenharmony_ci if (is_in_reachable(*reachable, usercon_str2)) { 2706cd6a6acSopenharmony_ci context_free(usercon); 2716cd6a6acSopenharmony_ci start = end; 2726cd6a6acSopenharmony_ci continue; 2736cd6a6acSopenharmony_ci } 2746cd6a6acSopenharmony_ci if (security_check_context(usercon_str2) == 0) { 2756cd6a6acSopenharmony_ci new_reachable = realloc(*reachable, (*nreachable + 2) * sizeof(char *)); 2766cd6a6acSopenharmony_ci if (!new_reachable) { 2776cd6a6acSopenharmony_ci context_free(usercon); 2786cd6a6acSopenharmony_ci rc = -1; 2796cd6a6acSopenharmony_ci goto out; 2806cd6a6acSopenharmony_ci } 2816cd6a6acSopenharmony_ci *reachable = new_reachable; 2826cd6a6acSopenharmony_ci new_reachable[*nreachable] = strdup(usercon_str2); 2836cd6a6acSopenharmony_ci if (new_reachable[*nreachable] == NULL) { 2846cd6a6acSopenharmony_ci context_free(usercon); 2856cd6a6acSopenharmony_ci rc = -1; 2866cd6a6acSopenharmony_ci goto out; 2876cd6a6acSopenharmony_ci } 2886cd6a6acSopenharmony_ci new_reachable[*nreachable + 1] = 0; 2896cd6a6acSopenharmony_ci *nreachable += 1; 2906cd6a6acSopenharmony_ci } 2916cd6a6acSopenharmony_ci context_free(usercon); 2926cd6a6acSopenharmony_ci start = end; 2936cd6a6acSopenharmony_ci } 2946cd6a6acSopenharmony_ci rc = 0; 2956cd6a6acSopenharmony_ci 2966cd6a6acSopenharmony_ci out: 2976cd6a6acSopenharmony_ci context_free(con); 2986cd6a6acSopenharmony_ci free(line); 2996cd6a6acSopenharmony_ci return rc; 3006cd6a6acSopenharmony_ci} 3016cd6a6acSopenharmony_ci 3026cd6a6acSopenharmony_cistatic int get_failsafe_context(const char *user, char ** newcon) 3036cd6a6acSopenharmony_ci{ 3046cd6a6acSopenharmony_ci FILE *fp; 3056cd6a6acSopenharmony_ci char buf[255], *ptr; 3066cd6a6acSopenharmony_ci size_t plen, nlen; 3076cd6a6acSopenharmony_ci int rc; 3086cd6a6acSopenharmony_ci 3096cd6a6acSopenharmony_ci fp = fopen(selinux_failsafe_context_path(), "re"); 3106cd6a6acSopenharmony_ci if (!fp) 3116cd6a6acSopenharmony_ci return -1; 3126cd6a6acSopenharmony_ci 3136cd6a6acSopenharmony_ci ptr = fgets_unlocked(buf, sizeof buf, fp); 3146cd6a6acSopenharmony_ci fclose(fp); 3156cd6a6acSopenharmony_ci 3166cd6a6acSopenharmony_ci if (!ptr) 3176cd6a6acSopenharmony_ci return -1; 3186cd6a6acSopenharmony_ci plen = strlen(ptr); 3196cd6a6acSopenharmony_ci if (buf[plen - 1] == '\n') 3206cd6a6acSopenharmony_ci buf[plen - 1] = 0; 3216cd6a6acSopenharmony_ci 3226cd6a6acSopenharmony_ci nlen = strlen(user) + 1 + plen + 1; 3236cd6a6acSopenharmony_ci *newcon = malloc(nlen); 3246cd6a6acSopenharmony_ci if (!(*newcon)) 3256cd6a6acSopenharmony_ci return -1; 3266cd6a6acSopenharmony_ci rc = snprintf(*newcon, nlen, "%s:%s", user, ptr); 3276cd6a6acSopenharmony_ci if (rc < 0 || (size_t) rc >= nlen) { 3286cd6a6acSopenharmony_ci free(*newcon); 3296cd6a6acSopenharmony_ci *newcon = 0; 3306cd6a6acSopenharmony_ci return -1; 3316cd6a6acSopenharmony_ci } 3326cd6a6acSopenharmony_ci 3336cd6a6acSopenharmony_ci /* If possible, check the context to catch 3346cd6a6acSopenharmony_ci errors early rather than waiting until the 3356cd6a6acSopenharmony_ci caller tries to use setexeccon on the context. 3366cd6a6acSopenharmony_ci But this may not always be possible, e.g. if 3376cd6a6acSopenharmony_ci selinuxfs isn't mounted. */ 3386cd6a6acSopenharmony_ci if (security_check_context(*newcon) && errno != ENOENT) { 3396cd6a6acSopenharmony_ci free(*newcon); 3406cd6a6acSopenharmony_ci *newcon = 0; 3416cd6a6acSopenharmony_ci return -1; 3426cd6a6acSopenharmony_ci } 3436cd6a6acSopenharmony_ci 3446cd6a6acSopenharmony_ci return 0; 3456cd6a6acSopenharmony_ci} 3466cd6a6acSopenharmony_ci 3476cd6a6acSopenharmony_ciint get_ordered_context_list_with_level(const char *user, 3486cd6a6acSopenharmony_ci const char *level, 3496cd6a6acSopenharmony_ci const char *fromcon, 3506cd6a6acSopenharmony_ci char *** list) 3516cd6a6acSopenharmony_ci{ 3526cd6a6acSopenharmony_ci int rc; 3536cd6a6acSopenharmony_ci char *backup_fromcon = NULL; 3546cd6a6acSopenharmony_ci context_t con; 3556cd6a6acSopenharmony_ci const char *newfromcon; 3566cd6a6acSopenharmony_ci 3576cd6a6acSopenharmony_ci if (!level) 3586cd6a6acSopenharmony_ci return get_ordered_context_list(user, fromcon, list); 3596cd6a6acSopenharmony_ci 3606cd6a6acSopenharmony_ci if (!fromcon) { 3616cd6a6acSopenharmony_ci rc = getcon(&backup_fromcon); 3626cd6a6acSopenharmony_ci if (rc < 0) 3636cd6a6acSopenharmony_ci return rc; 3646cd6a6acSopenharmony_ci fromcon = backup_fromcon; 3656cd6a6acSopenharmony_ci } 3666cd6a6acSopenharmony_ci 3676cd6a6acSopenharmony_ci rc = -1; 3686cd6a6acSopenharmony_ci con = context_new(fromcon); 3696cd6a6acSopenharmony_ci if (!con) 3706cd6a6acSopenharmony_ci goto out; 3716cd6a6acSopenharmony_ci 3726cd6a6acSopenharmony_ci if (context_range_set(con, level)) 3736cd6a6acSopenharmony_ci goto out; 3746cd6a6acSopenharmony_ci 3756cd6a6acSopenharmony_ci newfromcon = context_str(con); 3766cd6a6acSopenharmony_ci if (!newfromcon) 3776cd6a6acSopenharmony_ci goto out; 3786cd6a6acSopenharmony_ci 3796cd6a6acSopenharmony_ci rc = get_ordered_context_list(user, newfromcon, list); 3806cd6a6acSopenharmony_ci 3816cd6a6acSopenharmony_ci out: 3826cd6a6acSopenharmony_ci context_free(con); 3836cd6a6acSopenharmony_ci freecon(backup_fromcon); 3846cd6a6acSopenharmony_ci return rc; 3856cd6a6acSopenharmony_ci} 3866cd6a6acSopenharmony_ci 3876cd6a6acSopenharmony_ci 3886cd6a6acSopenharmony_ciint get_default_context_with_level(const char *user, 3896cd6a6acSopenharmony_ci const char *level, 3906cd6a6acSopenharmony_ci const char *fromcon, 3916cd6a6acSopenharmony_ci char ** newcon) 3926cd6a6acSopenharmony_ci{ 3936cd6a6acSopenharmony_ci char **conary; 3946cd6a6acSopenharmony_ci int rc; 3956cd6a6acSopenharmony_ci 3966cd6a6acSopenharmony_ci rc = get_ordered_context_list_with_level(user, level, fromcon, &conary); 3976cd6a6acSopenharmony_ci if (rc <= 0) 3986cd6a6acSopenharmony_ci return -1; 3996cd6a6acSopenharmony_ci 4006cd6a6acSopenharmony_ci *newcon = strdup(conary[0]); 4016cd6a6acSopenharmony_ci freeconary(conary); 4026cd6a6acSopenharmony_ci if (!(*newcon)) 4036cd6a6acSopenharmony_ci return -1; 4046cd6a6acSopenharmony_ci return 0; 4056cd6a6acSopenharmony_ci} 4066cd6a6acSopenharmony_ci 4076cd6a6acSopenharmony_ciint get_ordered_context_list(const char *user, 4086cd6a6acSopenharmony_ci const char *fromcon, 4096cd6a6acSopenharmony_ci char *** list) 4106cd6a6acSopenharmony_ci{ 4116cd6a6acSopenharmony_ci char **reachable = NULL; 4126cd6a6acSopenharmony_ci int rc = 0; 4136cd6a6acSopenharmony_ci unsigned nreachable = 0; 4146cd6a6acSopenharmony_ci char *backup_fromcon = NULL; 4156cd6a6acSopenharmony_ci FILE *fp; 4166cd6a6acSopenharmony_ci char *fname = NULL; 4176cd6a6acSopenharmony_ci size_t fname_len; 4186cd6a6acSopenharmony_ci const char *user_contexts_path = selinux_user_contexts_path(); 4196cd6a6acSopenharmony_ci 4206cd6a6acSopenharmony_ci if (!fromcon) { 4216cd6a6acSopenharmony_ci /* Get the current context and use it for the starting context */ 4226cd6a6acSopenharmony_ci rc = getcon(&backup_fromcon); 4236cd6a6acSopenharmony_ci if (rc < 0) 4246cd6a6acSopenharmony_ci return rc; 4256cd6a6acSopenharmony_ci fromcon = backup_fromcon; 4266cd6a6acSopenharmony_ci } 4276cd6a6acSopenharmony_ci 4286cd6a6acSopenharmony_ci /* Determine the ordering to apply from the optional per-user config 4296cd6a6acSopenharmony_ci and from the global config. */ 4306cd6a6acSopenharmony_ci fname_len = strlen(user_contexts_path) + strlen(user) + 2; 4316cd6a6acSopenharmony_ci fname = malloc(fname_len); 4326cd6a6acSopenharmony_ci if (!fname) 4336cd6a6acSopenharmony_ci goto failsafe; 4346cd6a6acSopenharmony_ci snprintf(fname, fname_len, "%s%s", user_contexts_path, user); 4356cd6a6acSopenharmony_ci fp = fopen(fname, "re"); 4366cd6a6acSopenharmony_ci if (fp) { 4376cd6a6acSopenharmony_ci __fsetlocking(fp, FSETLOCKING_BYCALLER); 4386cd6a6acSopenharmony_ci rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); 4396cd6a6acSopenharmony_ci 4406cd6a6acSopenharmony_ci fclose(fp); 4416cd6a6acSopenharmony_ci if (rc < 0 && errno != ENOENT) { 4426cd6a6acSopenharmony_ci fprintf(stderr, 4436cd6a6acSopenharmony_ci "%s: error in processing configuration file %s\n", 4446cd6a6acSopenharmony_ci __FUNCTION__, fname); 4456cd6a6acSopenharmony_ci /* Fall through, try global config */ 4466cd6a6acSopenharmony_ci } 4476cd6a6acSopenharmony_ci } 4486cd6a6acSopenharmony_ci free(fname); 4496cd6a6acSopenharmony_ci fp = fopen(selinux_default_context_path(), "re"); 4506cd6a6acSopenharmony_ci if (fp) { 4516cd6a6acSopenharmony_ci __fsetlocking(fp, FSETLOCKING_BYCALLER); 4526cd6a6acSopenharmony_ci rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); 4536cd6a6acSopenharmony_ci fclose(fp); 4546cd6a6acSopenharmony_ci if (rc < 0 && errno != ENOENT) { 4556cd6a6acSopenharmony_ci fprintf(stderr, 4566cd6a6acSopenharmony_ci "%s: error in processing configuration file %s\n", 4576cd6a6acSopenharmony_ci __FUNCTION__, selinux_default_context_path()); 4586cd6a6acSopenharmony_ci /* Fall through */ 4596cd6a6acSopenharmony_ci } 4606cd6a6acSopenharmony_ci } 4616cd6a6acSopenharmony_ci 4626cd6a6acSopenharmony_ci if (!nreachable) 4636cd6a6acSopenharmony_ci goto failsafe; 4646cd6a6acSopenharmony_ci 4656cd6a6acSopenharmony_ci out: 4666cd6a6acSopenharmony_ci if (nreachable > 0) { 4676cd6a6acSopenharmony_ci *list = reachable; 4686cd6a6acSopenharmony_ci rc = nreachable; 4696cd6a6acSopenharmony_ci } 4706cd6a6acSopenharmony_ci else 4716cd6a6acSopenharmony_ci freeconary(reachable); 4726cd6a6acSopenharmony_ci 4736cd6a6acSopenharmony_ci freecon(backup_fromcon); 4746cd6a6acSopenharmony_ci 4756cd6a6acSopenharmony_ci return rc; 4766cd6a6acSopenharmony_ci 4776cd6a6acSopenharmony_ci failsafe: 4786cd6a6acSopenharmony_ci /* Unable to determine a reachable context list, try to fall back to 4796cd6a6acSopenharmony_ci the "failsafe" context to at least permit root login 4806cd6a6acSopenharmony_ci for emergency recovery if possible. */ 4816cd6a6acSopenharmony_ci freeconary(reachable); 4826cd6a6acSopenharmony_ci reachable = malloc(2 * sizeof(char *)); 4836cd6a6acSopenharmony_ci if (!reachable) { 4846cd6a6acSopenharmony_ci rc = -1; 4856cd6a6acSopenharmony_ci goto out; 4866cd6a6acSopenharmony_ci } 4876cd6a6acSopenharmony_ci reachable[0] = reachable[1] = 0; 4886cd6a6acSopenharmony_ci rc = get_failsafe_context(user, &reachable[0]); 4896cd6a6acSopenharmony_ci if (rc < 0) { 4906cd6a6acSopenharmony_ci freeconary(reachable); 4916cd6a6acSopenharmony_ci reachable = NULL; 4926cd6a6acSopenharmony_ci goto out; 4936cd6a6acSopenharmony_ci } 4946cd6a6acSopenharmony_ci nreachable = 1; /* one context in the list */ 4956cd6a6acSopenharmony_ci goto out; 4966cd6a6acSopenharmony_ci} 4976cd6a6acSopenharmony_ci 498