16cd6a6acSopenharmony_ci#include <unistd.h>
26cd6a6acSopenharmony_ci#include <sys/types.h>
36cd6a6acSopenharmony_ci#include <fcntl.h>
46cd6a6acSopenharmony_ci#include <stdlib.h>
56cd6a6acSopenharmony_ci#include <stdio.h>
66cd6a6acSopenharmony_ci#include <errno.h>
76cd6a6acSopenharmony_ci#include <string.h>
86cd6a6acSopenharmony_ci#include <limits.h>
96cd6a6acSopenharmony_ci#include <ctype.h>
106cd6a6acSopenharmony_ci#include "selinux_internal.h"
116cd6a6acSopenharmony_ci#include "policy.h"
126cd6a6acSopenharmony_ci#include "mapping.h"
136cd6a6acSopenharmony_ci
146cd6a6acSopenharmony_cistatic int object_name_encode(const char *objname, char *buffer, size_t buflen)
156cd6a6acSopenharmony_ci{
166cd6a6acSopenharmony_ci	int	code;
176cd6a6acSopenharmony_ci	size_t	offset = 0;
186cd6a6acSopenharmony_ci
196cd6a6acSopenharmony_ci	if (buflen - offset < 1)
206cd6a6acSopenharmony_ci		return -1;
216cd6a6acSopenharmony_ci	buffer[offset++] = ' ';
226cd6a6acSopenharmony_ci
236cd6a6acSopenharmony_ci	do {
246cd6a6acSopenharmony_ci		code = *objname++;
256cd6a6acSopenharmony_ci
266cd6a6acSopenharmony_ci		if (isalnum(code) || code == '\0' || code == '-' ||
276cd6a6acSopenharmony_ci		    code == '.' || code == '_' || code == '~') {
286cd6a6acSopenharmony_ci			if (buflen - offset < 1)
296cd6a6acSopenharmony_ci				return -1;
306cd6a6acSopenharmony_ci			buffer[offset++] = code;
316cd6a6acSopenharmony_ci		} else if (code == ' ') {
326cd6a6acSopenharmony_ci			if (buflen - offset < 1)
336cd6a6acSopenharmony_ci				return -1;
346cd6a6acSopenharmony_ci			buffer[offset++] = '+';
356cd6a6acSopenharmony_ci		} else {
366cd6a6acSopenharmony_ci			static const char *table = "0123456789ABCDEF";
376cd6a6acSopenharmony_ci			int	l = (code & 0x0f);
386cd6a6acSopenharmony_ci			int	h = (code & 0xf0) >> 4;
396cd6a6acSopenharmony_ci
406cd6a6acSopenharmony_ci			if (buflen - offset < 3)
416cd6a6acSopenharmony_ci				return -1;
426cd6a6acSopenharmony_ci			buffer[offset++] = '%';
436cd6a6acSopenharmony_ci			buffer[offset++] = table[h];
446cd6a6acSopenharmony_ci			buffer[offset++] = table[l];
456cd6a6acSopenharmony_ci		}
466cd6a6acSopenharmony_ci	} while (code != '\0');
476cd6a6acSopenharmony_ci
486cd6a6acSopenharmony_ci	return 0;
496cd6a6acSopenharmony_ci}
506cd6a6acSopenharmony_ci
516cd6a6acSopenharmony_ciint security_compute_create_name_raw(const char * scon,
526cd6a6acSopenharmony_ci				     const char * tcon,
536cd6a6acSopenharmony_ci				     security_class_t tclass,
546cd6a6acSopenharmony_ci				     const char *objname,
556cd6a6acSopenharmony_ci				     char ** newcon)
566cd6a6acSopenharmony_ci{
576cd6a6acSopenharmony_ci	char path[PATH_MAX];
586cd6a6acSopenharmony_ci	char *buf;
596cd6a6acSopenharmony_ci	size_t size;
606cd6a6acSopenharmony_ci	int fd, ret, len;
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_ci	if (!selinux_mnt) {
636cd6a6acSopenharmony_ci		errno = ENOENT;
646cd6a6acSopenharmony_ci		return -1;
656cd6a6acSopenharmony_ci	}
666cd6a6acSopenharmony_ci
676cd6a6acSopenharmony_ci	snprintf(path, sizeof path, "%s/create", selinux_mnt);
686cd6a6acSopenharmony_ci	fd = open(path, O_RDWR | O_CLOEXEC);
696cd6a6acSopenharmony_ci	if (fd < 0)
706cd6a6acSopenharmony_ci		return -1;
716cd6a6acSopenharmony_ci
726cd6a6acSopenharmony_ci	size = selinux_page_size;
736cd6a6acSopenharmony_ci	buf = malloc(size);
746cd6a6acSopenharmony_ci	if (!buf) {
756cd6a6acSopenharmony_ci		ret = -1;
766cd6a6acSopenharmony_ci		goto out;
776cd6a6acSopenharmony_ci	}
786cd6a6acSopenharmony_ci
796cd6a6acSopenharmony_ci	len = snprintf(buf, size, "%s %s %hu",
806cd6a6acSopenharmony_ci		       scon, tcon, unmap_class(tclass));
816cd6a6acSopenharmony_ci	if (len < 0 || (size_t)len >= size) {
826cd6a6acSopenharmony_ci		errno = EOVERFLOW;
836cd6a6acSopenharmony_ci		ret = -1;
846cd6a6acSopenharmony_ci		goto out2;
856cd6a6acSopenharmony_ci	}
866cd6a6acSopenharmony_ci
876cd6a6acSopenharmony_ci	if (objname &&
886cd6a6acSopenharmony_ci	    object_name_encode(objname, buf + len, size - len) < 0) {
896cd6a6acSopenharmony_ci		errno = ENAMETOOLONG;
906cd6a6acSopenharmony_ci		ret = -1;
916cd6a6acSopenharmony_ci		goto out2;
926cd6a6acSopenharmony_ci	}
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	ret = write(fd, buf, strlen(buf));
956cd6a6acSopenharmony_ci	if (ret < 0)
966cd6a6acSopenharmony_ci		goto out2;
976cd6a6acSopenharmony_ci
986cd6a6acSopenharmony_ci	memset(buf, 0, size);
996cd6a6acSopenharmony_ci	ret = read(fd, buf, size - 1);
1006cd6a6acSopenharmony_ci	if (ret < 0)
1016cd6a6acSopenharmony_ci		goto out2;
1026cd6a6acSopenharmony_ci
1036cd6a6acSopenharmony_ci	*newcon = strdup(buf);
1046cd6a6acSopenharmony_ci	if (!(*newcon)) {
1056cd6a6acSopenharmony_ci		ret = -1;
1066cd6a6acSopenharmony_ci		goto out2;
1076cd6a6acSopenharmony_ci	}
1086cd6a6acSopenharmony_ci	ret = 0;
1096cd6a6acSopenharmony_ci      out2:
1106cd6a6acSopenharmony_ci	free(buf);
1116cd6a6acSopenharmony_ci      out:
1126cd6a6acSopenharmony_ci	close(fd);
1136cd6a6acSopenharmony_ci	return ret;
1146cd6a6acSopenharmony_ci}
1156cd6a6acSopenharmony_ci
1166cd6a6acSopenharmony_ciint security_compute_create_raw(const char * scon,
1176cd6a6acSopenharmony_ci				const char * tcon,
1186cd6a6acSopenharmony_ci				security_class_t tclass,
1196cd6a6acSopenharmony_ci				char ** newcon)
1206cd6a6acSopenharmony_ci{
1216cd6a6acSopenharmony_ci	return security_compute_create_name_raw(scon, tcon, tclass,
1226cd6a6acSopenharmony_ci						NULL, newcon);
1236cd6a6acSopenharmony_ci}
1246cd6a6acSopenharmony_ci
1256cd6a6acSopenharmony_ciint security_compute_create_name(const char * scon,
1266cd6a6acSopenharmony_ci				 const char * tcon,
1276cd6a6acSopenharmony_ci				 security_class_t tclass,
1286cd6a6acSopenharmony_ci				 const char *objname,
1296cd6a6acSopenharmony_ci				 char ** newcon)
1306cd6a6acSopenharmony_ci{
1316cd6a6acSopenharmony_ci	int ret;
1326cd6a6acSopenharmony_ci	char * rscon;
1336cd6a6acSopenharmony_ci	char * rtcon;
1346cd6a6acSopenharmony_ci	char * rnewcon;
1356cd6a6acSopenharmony_ci
1366cd6a6acSopenharmony_ci	if (selinux_trans_to_raw_context(scon, &rscon))
1376cd6a6acSopenharmony_ci		return -1;
1386cd6a6acSopenharmony_ci	if (selinux_trans_to_raw_context(tcon, &rtcon)) {
1396cd6a6acSopenharmony_ci		freecon(rscon);
1406cd6a6acSopenharmony_ci		return -1;
1416cd6a6acSopenharmony_ci	}
1426cd6a6acSopenharmony_ci
1436cd6a6acSopenharmony_ci	ret = security_compute_create_name_raw(rscon, rtcon, tclass,
1446cd6a6acSopenharmony_ci					       objname, &rnewcon);
1456cd6a6acSopenharmony_ci	freecon(rscon);
1466cd6a6acSopenharmony_ci	freecon(rtcon);
1476cd6a6acSopenharmony_ci	if (!ret) {
1486cd6a6acSopenharmony_ci		ret = selinux_raw_to_trans_context(rnewcon, newcon);
1496cd6a6acSopenharmony_ci		freecon(rnewcon);
1506cd6a6acSopenharmony_ci	}
1516cd6a6acSopenharmony_ci
1526cd6a6acSopenharmony_ci	return ret;
1536cd6a6acSopenharmony_ci}
1546cd6a6acSopenharmony_ci
1556cd6a6acSopenharmony_ciint security_compute_create(const char * scon,
1566cd6a6acSopenharmony_ci				const char * tcon,
1576cd6a6acSopenharmony_ci			    security_class_t tclass,
1586cd6a6acSopenharmony_ci				char ** newcon)
1596cd6a6acSopenharmony_ci{
1606cd6a6acSopenharmony_ci	return security_compute_create_name(scon, tcon, tclass, NULL, newcon);
1616cd6a6acSopenharmony_ci}
162