16cd6a6acSopenharmony_ci#include <errno.h>
26cd6a6acSopenharmony_ci#include <stdlib.h>
36cd6a6acSopenharmony_ci#include <string.h>
46cd6a6acSopenharmony_ci
56cd6a6acSopenharmony_ci#include "user_internal.h"
66cd6a6acSopenharmony_ci#include "debug.h"
76cd6a6acSopenharmony_ci#include "private.h"
86cd6a6acSopenharmony_ci
96cd6a6acSopenharmony_cistruct sepol_user {
106cd6a6acSopenharmony_ci	/* This user's name */
116cd6a6acSopenharmony_ci	char *name;
126cd6a6acSopenharmony_ci
136cd6a6acSopenharmony_ci	/* This user's mls level (only required for mls) */
146cd6a6acSopenharmony_ci	char *mls_level;
156cd6a6acSopenharmony_ci
166cd6a6acSopenharmony_ci	/* This user's mls range (only required for mls) */
176cd6a6acSopenharmony_ci	char *mls_range;
186cd6a6acSopenharmony_ci
196cd6a6acSopenharmony_ci	/* The role array */
206cd6a6acSopenharmony_ci	char **roles;
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_ci	/* The number of roles */
236cd6a6acSopenharmony_ci	unsigned int num_roles;
246cd6a6acSopenharmony_ci};
256cd6a6acSopenharmony_ci
266cd6a6acSopenharmony_cistruct sepol_user_key {
276cd6a6acSopenharmony_ci	/* This user's name */
286cd6a6acSopenharmony_ci	char *name;
296cd6a6acSopenharmony_ci};
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_ciint sepol_user_key_create(sepol_handle_t * handle,
326cd6a6acSopenharmony_ci			  const char *name, sepol_user_key_t ** key_ptr)
336cd6a6acSopenharmony_ci{
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci	sepol_user_key_t *tmp_key =
366cd6a6acSopenharmony_ci	    (sepol_user_key_t *) malloc(sizeof(sepol_user_key_t));
376cd6a6acSopenharmony_ci
386cd6a6acSopenharmony_ci	if (!tmp_key) {
396cd6a6acSopenharmony_ci		ERR(handle, "out of memory, "
406cd6a6acSopenharmony_ci		    "could not create selinux user key");
416cd6a6acSopenharmony_ci		return STATUS_ERR;
426cd6a6acSopenharmony_ci	}
436cd6a6acSopenharmony_ci
446cd6a6acSopenharmony_ci	tmp_key->name = strdup(name);
456cd6a6acSopenharmony_ci	if (!tmp_key->name) {
466cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not create selinux user key");
476cd6a6acSopenharmony_ci		free(tmp_key);
486cd6a6acSopenharmony_ci		return STATUS_ERR;
496cd6a6acSopenharmony_ci	}
506cd6a6acSopenharmony_ci
516cd6a6acSopenharmony_ci	*key_ptr = tmp_key;
526cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
536cd6a6acSopenharmony_ci}
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_ci
566cd6a6acSopenharmony_civoid sepol_user_key_unpack(const sepol_user_key_t * key, const char **name)
576cd6a6acSopenharmony_ci{
586cd6a6acSopenharmony_ci
596cd6a6acSopenharmony_ci	*name = key->name;
606cd6a6acSopenharmony_ci}
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_ci
636cd6a6acSopenharmony_ciint sepol_user_key_extract(sepol_handle_t * handle,
646cd6a6acSopenharmony_ci			   const sepol_user_t * user,
656cd6a6acSopenharmony_ci			   sepol_user_key_t ** key_ptr)
666cd6a6acSopenharmony_ci{
676cd6a6acSopenharmony_ci
686cd6a6acSopenharmony_ci	if (sepol_user_key_create(handle, user->name, key_ptr) < 0) {
696cd6a6acSopenharmony_ci		ERR(handle, "could not extract key from user %s", user->name);
706cd6a6acSopenharmony_ci		return STATUS_ERR;
716cd6a6acSopenharmony_ci	}
726cd6a6acSopenharmony_ci
736cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
746cd6a6acSopenharmony_ci}
756cd6a6acSopenharmony_ci
766cd6a6acSopenharmony_civoid sepol_user_key_free(sepol_user_key_t * key)
776cd6a6acSopenharmony_ci{
786cd6a6acSopenharmony_ci	if (!key)
796cd6a6acSopenharmony_ci		return;
806cd6a6acSopenharmony_ci	free(key->name);
816cd6a6acSopenharmony_ci	free(key);
826cd6a6acSopenharmony_ci}
836cd6a6acSopenharmony_ci
846cd6a6acSopenharmony_ciint sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key)
856cd6a6acSopenharmony_ci{
866cd6a6acSopenharmony_ci
876cd6a6acSopenharmony_ci	return strcmp(user->name, key->name);
886cd6a6acSopenharmony_ci}
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ciint sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2)
916cd6a6acSopenharmony_ci{
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_ci	return strcmp(user->name, user2->name);
946cd6a6acSopenharmony_ci}
956cd6a6acSopenharmony_ci
966cd6a6acSopenharmony_ci/* Name */
976cd6a6acSopenharmony_ciconst char *sepol_user_get_name(const sepol_user_t * user)
986cd6a6acSopenharmony_ci{
996cd6a6acSopenharmony_ci
1006cd6a6acSopenharmony_ci	return user->name;
1016cd6a6acSopenharmony_ci}
1026cd6a6acSopenharmony_ci
1036cd6a6acSopenharmony_ciint sepol_user_set_name(sepol_handle_t * handle,
1046cd6a6acSopenharmony_ci			sepol_user_t * user, const char *name)
1056cd6a6acSopenharmony_ci{
1066cd6a6acSopenharmony_ci
1076cd6a6acSopenharmony_ci	char *tmp_name = strdup(name);
1086cd6a6acSopenharmony_ci	if (!tmp_name) {
1096cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not set name");
1106cd6a6acSopenharmony_ci		return STATUS_ERR;
1116cd6a6acSopenharmony_ci	}
1126cd6a6acSopenharmony_ci	free(user->name);
1136cd6a6acSopenharmony_ci	user->name = tmp_name;
1146cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1156cd6a6acSopenharmony_ci}
1166cd6a6acSopenharmony_ci
1176cd6a6acSopenharmony_ci
1186cd6a6acSopenharmony_ci/* MLS */
1196cd6a6acSopenharmony_ciconst char *sepol_user_get_mlslevel(const sepol_user_t * user)
1206cd6a6acSopenharmony_ci{
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci	return user->mls_level;
1236cd6a6acSopenharmony_ci}
1246cd6a6acSopenharmony_ci
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ciint sepol_user_set_mlslevel(sepol_handle_t * handle,
1276cd6a6acSopenharmony_ci			    sepol_user_t * user, const char *mls_level)
1286cd6a6acSopenharmony_ci{
1296cd6a6acSopenharmony_ci
1306cd6a6acSopenharmony_ci	char *tmp_mls_level = strdup(mls_level);
1316cd6a6acSopenharmony_ci	if (!tmp_mls_level) {
1326cd6a6acSopenharmony_ci		ERR(handle, "out of memory, "
1336cd6a6acSopenharmony_ci		    "could not set MLS default level");
1346cd6a6acSopenharmony_ci		return STATUS_ERR;
1356cd6a6acSopenharmony_ci	}
1366cd6a6acSopenharmony_ci	free(user->mls_level);
1376cd6a6acSopenharmony_ci	user->mls_level = tmp_mls_level;
1386cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1396cd6a6acSopenharmony_ci}
1406cd6a6acSopenharmony_ci
1416cd6a6acSopenharmony_ci
1426cd6a6acSopenharmony_ciconst char *sepol_user_get_mlsrange(const sepol_user_t * user)
1436cd6a6acSopenharmony_ci{
1446cd6a6acSopenharmony_ci
1456cd6a6acSopenharmony_ci	return user->mls_range;
1466cd6a6acSopenharmony_ci}
1476cd6a6acSopenharmony_ci
1486cd6a6acSopenharmony_ci
1496cd6a6acSopenharmony_ciint sepol_user_set_mlsrange(sepol_handle_t * handle,
1506cd6a6acSopenharmony_ci			    sepol_user_t * user, const char *mls_range)
1516cd6a6acSopenharmony_ci{
1526cd6a6acSopenharmony_ci
1536cd6a6acSopenharmony_ci	char *tmp_mls_range = strdup(mls_range);
1546cd6a6acSopenharmony_ci	if (!tmp_mls_range) {
1556cd6a6acSopenharmony_ci		ERR(handle, "out of memory, "
1566cd6a6acSopenharmony_ci		    "could not set MLS allowed range");
1576cd6a6acSopenharmony_ci		return STATUS_ERR;
1586cd6a6acSopenharmony_ci	}
1596cd6a6acSopenharmony_ci	free(user->mls_range);
1606cd6a6acSopenharmony_ci	user->mls_range = tmp_mls_range;
1616cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1626cd6a6acSopenharmony_ci}
1636cd6a6acSopenharmony_ci
1646cd6a6acSopenharmony_ci
1656cd6a6acSopenharmony_ci/* Roles */
1666cd6a6acSopenharmony_ciint sepol_user_get_num_roles(const sepol_user_t * user)
1676cd6a6acSopenharmony_ci{
1686cd6a6acSopenharmony_ci
1696cd6a6acSopenharmony_ci	return user->num_roles;
1706cd6a6acSopenharmony_ci}
1716cd6a6acSopenharmony_ci
1726cd6a6acSopenharmony_ciint sepol_user_add_role(sepol_handle_t * handle,
1736cd6a6acSopenharmony_ci			sepol_user_t * user, const char *role)
1746cd6a6acSopenharmony_ci{
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	char *role_cp;
1776cd6a6acSopenharmony_ci	char **roles_realloc = NULL;
1786cd6a6acSopenharmony_ci
1796cd6a6acSopenharmony_ci	if (sepol_user_has_role(user, role))
1806cd6a6acSopenharmony_ci		return STATUS_SUCCESS;
1816cd6a6acSopenharmony_ci
1826cd6a6acSopenharmony_ci	role_cp = strdup(role);
1836cd6a6acSopenharmony_ci	if (!role_cp)
1846cd6a6acSopenharmony_ci		goto omem;
1856cd6a6acSopenharmony_ci
1866cd6a6acSopenharmony_ci	roles_realloc = reallocarray(user->roles,
1876cd6a6acSopenharmony_ci				     user->num_roles + 1,
1886cd6a6acSopenharmony_ci				     sizeof(char *));
1896cd6a6acSopenharmony_ci	if (!roles_realloc)
1906cd6a6acSopenharmony_ci		goto omem;
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci	user->num_roles++;
1936cd6a6acSopenharmony_ci	user->roles = roles_realloc;
1946cd6a6acSopenharmony_ci	user->roles[user->num_roles - 1] = role_cp;
1956cd6a6acSopenharmony_ci
1966cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1976cd6a6acSopenharmony_ci
1986cd6a6acSopenharmony_ci      omem:
1996cd6a6acSopenharmony_ci	ERR(handle, "out of memory, could not add role %s", role);
2006cd6a6acSopenharmony_ci	free(role_cp);
2016cd6a6acSopenharmony_ci	free(roles_realloc);
2026cd6a6acSopenharmony_ci	return STATUS_ERR;
2036cd6a6acSopenharmony_ci}
2046cd6a6acSopenharmony_ci
2056cd6a6acSopenharmony_ci
2066cd6a6acSopenharmony_ciint sepol_user_has_role(const sepol_user_t * user, const char *role)
2076cd6a6acSopenharmony_ci{
2086cd6a6acSopenharmony_ci
2096cd6a6acSopenharmony_ci	unsigned int i;
2106cd6a6acSopenharmony_ci
2116cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++)
2126cd6a6acSopenharmony_ci		if (!strcmp(user->roles[i], role))
2136cd6a6acSopenharmony_ci			return 1;
2146cd6a6acSopenharmony_ci	return 0;
2156cd6a6acSopenharmony_ci}
2166cd6a6acSopenharmony_ci
2176cd6a6acSopenharmony_ci
2186cd6a6acSopenharmony_ciint sepol_user_set_roles(sepol_handle_t * handle,
2196cd6a6acSopenharmony_ci			 sepol_user_t * user,
2206cd6a6acSopenharmony_ci			 const char **roles_arr, unsigned int num_roles)
2216cd6a6acSopenharmony_ci{
2226cd6a6acSopenharmony_ci
2236cd6a6acSopenharmony_ci	unsigned int i;
2246cd6a6acSopenharmony_ci	char **tmp_roles = NULL;
2256cd6a6acSopenharmony_ci
2266cd6a6acSopenharmony_ci	if (num_roles > 0) {
2276cd6a6acSopenharmony_ci
2286cd6a6acSopenharmony_ci		/* First, make a copy */
2296cd6a6acSopenharmony_ci		tmp_roles = (char **)calloc(1, sizeof(char *) * num_roles);
2306cd6a6acSopenharmony_ci		if (!tmp_roles)
2316cd6a6acSopenharmony_ci			goto omem;
2326cd6a6acSopenharmony_ci
2336cd6a6acSopenharmony_ci		for (i = 0; i < num_roles; i++) {
2346cd6a6acSopenharmony_ci			tmp_roles[i] = strdup(roles_arr[i]);
2356cd6a6acSopenharmony_ci			if (!tmp_roles[i])
2366cd6a6acSopenharmony_ci				goto omem;
2376cd6a6acSopenharmony_ci		}
2386cd6a6acSopenharmony_ci	}
2396cd6a6acSopenharmony_ci
2406cd6a6acSopenharmony_ci	/* Apply other changes */
2416cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++)
2426cd6a6acSopenharmony_ci		free(user->roles[i]);
2436cd6a6acSopenharmony_ci	free(user->roles);
2446cd6a6acSopenharmony_ci	user->roles = tmp_roles;
2456cd6a6acSopenharmony_ci	user->num_roles = num_roles;
2466cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2476cd6a6acSopenharmony_ci
2486cd6a6acSopenharmony_ci      omem:
2496cd6a6acSopenharmony_ci	ERR(handle, "out of memory, could not allocate roles array for"
2506cd6a6acSopenharmony_ci	    "user %s", user->name);
2516cd6a6acSopenharmony_ci
2526cd6a6acSopenharmony_ci	if (tmp_roles) {
2536cd6a6acSopenharmony_ci		for (i = 0; i < num_roles; i++) {
2546cd6a6acSopenharmony_ci			if (!tmp_roles[i])
2556cd6a6acSopenharmony_ci				break;
2566cd6a6acSopenharmony_ci			free(tmp_roles[i]);
2576cd6a6acSopenharmony_ci		}
2586cd6a6acSopenharmony_ci	}
2596cd6a6acSopenharmony_ci	free(tmp_roles);
2606cd6a6acSopenharmony_ci	return STATUS_ERR;
2616cd6a6acSopenharmony_ci}
2626cd6a6acSopenharmony_ci
2636cd6a6acSopenharmony_ciint sepol_user_get_roles(sepol_handle_t * handle,
2646cd6a6acSopenharmony_ci			 const sepol_user_t * user,
2656cd6a6acSopenharmony_ci			 const char ***roles_arr, unsigned int *num_roles)
2666cd6a6acSopenharmony_ci{
2676cd6a6acSopenharmony_ci
2686cd6a6acSopenharmony_ci	unsigned int i;
2696cd6a6acSopenharmony_ci	const char **tmp_roles =
2706cd6a6acSopenharmony_ci	    (const char **)calloc(user->num_roles, sizeof(char *));
2716cd6a6acSopenharmony_ci	if (!tmp_roles)
2726cd6a6acSopenharmony_ci		goto omem;
2736cd6a6acSopenharmony_ci
2746cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++)
2756cd6a6acSopenharmony_ci		tmp_roles[i] = user->roles[i];
2766cd6a6acSopenharmony_ci
2776cd6a6acSopenharmony_ci	*roles_arr = tmp_roles;
2786cd6a6acSopenharmony_ci	*num_roles = user->num_roles;
2796cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2806cd6a6acSopenharmony_ci
2816cd6a6acSopenharmony_ci      omem:
2826cd6a6acSopenharmony_ci	ERR(handle, "out of memory, could not "
2836cd6a6acSopenharmony_ci	    "allocate roles array for user %s", user->name);
2846cd6a6acSopenharmony_ci	free(tmp_roles);
2856cd6a6acSopenharmony_ci	return STATUS_ERR;
2866cd6a6acSopenharmony_ci}
2876cd6a6acSopenharmony_ci
2886cd6a6acSopenharmony_ci
2896cd6a6acSopenharmony_civoid sepol_user_del_role(sepol_user_t * user, const char *role)
2906cd6a6acSopenharmony_ci{
2916cd6a6acSopenharmony_ci
2926cd6a6acSopenharmony_ci	unsigned int i;
2936cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++) {
2946cd6a6acSopenharmony_ci		if (!strcmp(user->roles[i], role)) {
2956cd6a6acSopenharmony_ci			free(user->roles[i]);
2966cd6a6acSopenharmony_ci			user->roles[i] = NULL;
2976cd6a6acSopenharmony_ci			user->roles[i] = user->roles[user->num_roles - 1];
2986cd6a6acSopenharmony_ci			user->num_roles--;
2996cd6a6acSopenharmony_ci		}
3006cd6a6acSopenharmony_ci	}
3016cd6a6acSopenharmony_ci}
3026cd6a6acSopenharmony_ci
3036cd6a6acSopenharmony_ci/* Create */
3046cd6a6acSopenharmony_ciint sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr)
3056cd6a6acSopenharmony_ci{
3066cd6a6acSopenharmony_ci
3076cd6a6acSopenharmony_ci	sepol_user_t *user = (sepol_user_t *) malloc(sizeof(sepol_user_t));
3086cd6a6acSopenharmony_ci
3096cd6a6acSopenharmony_ci	if (!user) {
3106cd6a6acSopenharmony_ci		ERR(handle, "out of memory, "
3116cd6a6acSopenharmony_ci		    "could not create selinux user record");
3126cd6a6acSopenharmony_ci		return STATUS_ERR;
3136cd6a6acSopenharmony_ci	}
3146cd6a6acSopenharmony_ci
3156cd6a6acSopenharmony_ci	user->roles = NULL;
3166cd6a6acSopenharmony_ci	user->num_roles = 0;
3176cd6a6acSopenharmony_ci	user->name = NULL;
3186cd6a6acSopenharmony_ci	user->mls_level = NULL;
3196cd6a6acSopenharmony_ci	user->mls_range = NULL;
3206cd6a6acSopenharmony_ci
3216cd6a6acSopenharmony_ci	*user_ptr = user;
3226cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3236cd6a6acSopenharmony_ci}
3246cd6a6acSopenharmony_ci
3256cd6a6acSopenharmony_ci
3266cd6a6acSopenharmony_ci/* Deep copy clone */
3276cd6a6acSopenharmony_ciint sepol_user_clone(sepol_handle_t * handle,
3286cd6a6acSopenharmony_ci		     const sepol_user_t * user, sepol_user_t ** user_ptr)
3296cd6a6acSopenharmony_ci{
3306cd6a6acSopenharmony_ci
3316cd6a6acSopenharmony_ci	sepol_user_t *new_user = NULL;
3326cd6a6acSopenharmony_ci	unsigned int i;
3336cd6a6acSopenharmony_ci
3346cd6a6acSopenharmony_ci	if (sepol_user_create(handle, &new_user) < 0)
3356cd6a6acSopenharmony_ci		goto err;
3366cd6a6acSopenharmony_ci
3376cd6a6acSopenharmony_ci	if (sepol_user_set_name(handle, new_user, user->name) < 0)
3386cd6a6acSopenharmony_ci		goto err;
3396cd6a6acSopenharmony_ci
3406cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++) {
3416cd6a6acSopenharmony_ci		if (sepol_user_add_role(handle, new_user, user->roles[i]) < 0)
3426cd6a6acSopenharmony_ci			goto err;
3436cd6a6acSopenharmony_ci	}
3446cd6a6acSopenharmony_ci
3456cd6a6acSopenharmony_ci	if (user->mls_level &&
3466cd6a6acSopenharmony_ci	    (sepol_user_set_mlslevel(handle, new_user, user->mls_level) < 0))
3476cd6a6acSopenharmony_ci		goto err;
3486cd6a6acSopenharmony_ci
3496cd6a6acSopenharmony_ci	if (user->mls_range &&
3506cd6a6acSopenharmony_ci	    (sepol_user_set_mlsrange(handle, new_user, user->mls_range) < 0))
3516cd6a6acSopenharmony_ci		goto err;
3526cd6a6acSopenharmony_ci
3536cd6a6acSopenharmony_ci	*user_ptr = new_user;
3546cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3556cd6a6acSopenharmony_ci
3566cd6a6acSopenharmony_ci      err:
3576cd6a6acSopenharmony_ci	ERR(handle, "could not clone selinux user record");
3586cd6a6acSopenharmony_ci	sepol_user_free(new_user);
3596cd6a6acSopenharmony_ci	return STATUS_ERR;
3606cd6a6acSopenharmony_ci}
3616cd6a6acSopenharmony_ci
3626cd6a6acSopenharmony_ci/* Destroy */
3636cd6a6acSopenharmony_civoid sepol_user_free(sepol_user_t * user)
3646cd6a6acSopenharmony_ci{
3656cd6a6acSopenharmony_ci
3666cd6a6acSopenharmony_ci	unsigned int i;
3676cd6a6acSopenharmony_ci
3686cd6a6acSopenharmony_ci	if (!user)
3696cd6a6acSopenharmony_ci		return;
3706cd6a6acSopenharmony_ci
3716cd6a6acSopenharmony_ci	free(user->name);
3726cd6a6acSopenharmony_ci	for (i = 0; i < user->num_roles; i++)
3736cd6a6acSopenharmony_ci		free(user->roles[i]);
3746cd6a6acSopenharmony_ci	free(user->roles);
3756cd6a6acSopenharmony_ci	free(user->mls_level);
3766cd6a6acSopenharmony_ci	free(user->mls_range);
3776cd6a6acSopenharmony_ci	free(user);
3786cd6a6acSopenharmony_ci}
3796cd6a6acSopenharmony_ci
380