16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * This file contains helper functions for labeling support.
36cd6a6acSopenharmony_ci *
46cd6a6acSopenharmony_ci * Author : Richard Haines <richard_c_haines@btinternet.com>
56cd6a6acSopenharmony_ci */
66cd6a6acSopenharmony_ci
76cd6a6acSopenharmony_ci#include <stdlib.h>
86cd6a6acSopenharmony_ci#include <stdarg.h>
96cd6a6acSopenharmony_ci#include <ctype.h>
106cd6a6acSopenharmony_ci#include <string.h>
116cd6a6acSopenharmony_ci#include <stdio.h>
126cd6a6acSopenharmony_ci#include <errno.h>
136cd6a6acSopenharmony_ci#include <errno.h>
146cd6a6acSopenharmony_ci#include "label_internal.h"
156cd6a6acSopenharmony_ci
166cd6a6acSopenharmony_ci/*
176cd6a6acSopenharmony_ci * Read an entry from a spec file (e.g. file_contexts)
186cd6a6acSopenharmony_ci * entry - Buffer to allocate for the entry.
196cd6a6acSopenharmony_ci * ptr - current location of the line to be processed.
206cd6a6acSopenharmony_ci * returns  - 0 on success and *entry is set to be a null
216cd6a6acSopenharmony_ci *            terminated value. On Error it returns -1 and
226cd6a6acSopenharmony_ci *            errno will be set.
236cd6a6acSopenharmony_ci *
246cd6a6acSopenharmony_ci */
256cd6a6acSopenharmony_cistatic inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf)
266cd6a6acSopenharmony_ci{
276cd6a6acSopenharmony_ci	*entry = NULL;
286cd6a6acSopenharmony_ci	char *tmp_buf = NULL;
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci	while (isspace(**ptr) && **ptr != '\0')
316cd6a6acSopenharmony_ci		(*ptr)++;
326cd6a6acSopenharmony_ci
336cd6a6acSopenharmony_ci	tmp_buf = *ptr;
346cd6a6acSopenharmony_ci	*len = 0;
356cd6a6acSopenharmony_ci
366cd6a6acSopenharmony_ci	while (!isspace(**ptr) && **ptr != '\0') {
376cd6a6acSopenharmony_ci		if (!isascii(**ptr)) {
386cd6a6acSopenharmony_ci			errno = EINVAL;
396cd6a6acSopenharmony_ci			*errbuf = "Non-ASCII characters found";
406cd6a6acSopenharmony_ci			return -1;
416cd6a6acSopenharmony_ci		}
426cd6a6acSopenharmony_ci		(*ptr)++;
436cd6a6acSopenharmony_ci		(*len)++;
446cd6a6acSopenharmony_ci	}
456cd6a6acSopenharmony_ci
466cd6a6acSopenharmony_ci	if (*len) {
476cd6a6acSopenharmony_ci		*entry = strndup(tmp_buf, *len);
486cd6a6acSopenharmony_ci		if (!*entry)
496cd6a6acSopenharmony_ci			return -1;
506cd6a6acSopenharmony_ci	}
516cd6a6acSopenharmony_ci
526cd6a6acSopenharmony_ci	return 0;
536cd6a6acSopenharmony_ci}
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_ci/*
566cd6a6acSopenharmony_ci * line_buf - Buffer containing the spec entries .
576cd6a6acSopenharmony_ci * errbuf   - Double pointer used for passing back specific error messages.
586cd6a6acSopenharmony_ci * num_args - The number of spec parameter entries to process.
596cd6a6acSopenharmony_ci * ...      - A 'char **spec_entry' for each parameter.
606cd6a6acSopenharmony_ci * returns  - The number of items processed. On error, it returns -1 with errno
616cd6a6acSopenharmony_ci *            set and may set errbuf to a specific error message.
626cd6a6acSopenharmony_ci *
636cd6a6acSopenharmony_ci * This function calls read_spec_entry() to do the actual string processing.
646cd6a6acSopenharmony_ci * As such, can return anything from that function as well.
656cd6a6acSopenharmony_ci */
666cd6a6acSopenharmony_ciint  read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...)
676cd6a6acSopenharmony_ci{
686cd6a6acSopenharmony_ci	char **spec_entry, *buf_p;
696cd6a6acSopenharmony_ci	int len, rc, items, entry_len = 0;
706cd6a6acSopenharmony_ci	va_list ap;
716cd6a6acSopenharmony_ci
726cd6a6acSopenharmony_ci	*errbuf = NULL;
736cd6a6acSopenharmony_ci
746cd6a6acSopenharmony_ci	len = strlen(line_buf);
756cd6a6acSopenharmony_ci	if (line_buf[len - 1] == '\n')
766cd6a6acSopenharmony_ci		line_buf[len - 1] = '\0';
776cd6a6acSopenharmony_ci	else
786cd6a6acSopenharmony_ci		/* Handle case if line not \n terminated by bumping
796cd6a6acSopenharmony_ci		 * the len for the check below (as the line is NUL
806cd6a6acSopenharmony_ci		 * terminated by getline(3)) */
816cd6a6acSopenharmony_ci		len++;
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_ci	buf_p = line_buf;
846cd6a6acSopenharmony_ci	while (isspace(*buf_p))
856cd6a6acSopenharmony_ci		buf_p++;
866cd6a6acSopenharmony_ci
876cd6a6acSopenharmony_ci	/* Skip comment lines and empty lines. */
886cd6a6acSopenharmony_ci	if (*buf_p == '#' || *buf_p == '\0')
896cd6a6acSopenharmony_ci		return 0;
906cd6a6acSopenharmony_ci
916cd6a6acSopenharmony_ci	/* Process the spec file entries */
926cd6a6acSopenharmony_ci	va_start(ap, num_args);
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	items = 0;
956cd6a6acSopenharmony_ci	while (items < num_args) {
966cd6a6acSopenharmony_ci		spec_entry = va_arg(ap, char **);
976cd6a6acSopenharmony_ci
986cd6a6acSopenharmony_ci		if (len - 1 == buf_p - line_buf) {
996cd6a6acSopenharmony_ci			va_end(ap);
1006cd6a6acSopenharmony_ci			return items;
1016cd6a6acSopenharmony_ci		}
1026cd6a6acSopenharmony_ci
1036cd6a6acSopenharmony_ci		rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf);
1046cd6a6acSopenharmony_ci		if (rc < 0) {
1056cd6a6acSopenharmony_ci			va_end(ap);
1066cd6a6acSopenharmony_ci			return rc;
1076cd6a6acSopenharmony_ci		}
1086cd6a6acSopenharmony_ci		if (entry_len)
1096cd6a6acSopenharmony_ci			items++;
1106cd6a6acSopenharmony_ci	}
1116cd6a6acSopenharmony_ci	va_end(ap);
1126cd6a6acSopenharmony_ci	return items;
1136cd6a6acSopenharmony_ci}
1146cd6a6acSopenharmony_ci
1156cd6a6acSopenharmony_ci/* Once all the specfiles are in the hash_buf, generate the hash. */
1166cd6a6acSopenharmony_civoid  digest_gen_hash(struct selabel_digest *digest)
1176cd6a6acSopenharmony_ci{
1186cd6a6acSopenharmony_ci	Sha1Context context;
1196cd6a6acSopenharmony_ci	size_t remaining_size;
1206cd6a6acSopenharmony_ci	const unsigned char *ptr;
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci	/* If SELABEL_OPT_DIGEST not set then just return */
1236cd6a6acSopenharmony_ci	if (!digest)
1246cd6a6acSopenharmony_ci		return;
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci	Sha1Initialise(&context);
1276cd6a6acSopenharmony_ci
1286cd6a6acSopenharmony_ci	/* Process in blocks of UINT32_MAX bytes */
1296cd6a6acSopenharmony_ci	remaining_size = digest->hashbuf_size;
1306cd6a6acSopenharmony_ci	ptr = digest->hashbuf;
1316cd6a6acSopenharmony_ci	while (remaining_size > UINT32_MAX) {
1326cd6a6acSopenharmony_ci		Sha1Update(&context, ptr, UINT32_MAX);
1336cd6a6acSopenharmony_ci		remaining_size -= UINT32_MAX;
1346cd6a6acSopenharmony_ci		ptr += UINT32_MAX;
1356cd6a6acSopenharmony_ci	}
1366cd6a6acSopenharmony_ci	Sha1Update(&context, ptr, remaining_size);
1376cd6a6acSopenharmony_ci
1386cd6a6acSopenharmony_ci	Sha1Finalise(&context, (SHA1_HASH *)digest->digest);
1396cd6a6acSopenharmony_ci	free(digest->hashbuf);
1406cd6a6acSopenharmony_ci	digest->hashbuf = NULL;
1416cd6a6acSopenharmony_ci	return;
1426cd6a6acSopenharmony_ci}
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci/**
1456cd6a6acSopenharmony_ci * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true
1466cd6a6acSopenharmony_ci *			 then generate the hash.
1476cd6a6acSopenharmony_ci * @digest: pointer to the selabel_digest struct
1486cd6a6acSopenharmony_ci * @fp: file pointer for fread(3) or NULL if not.
1496cd6a6acSopenharmony_ci * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for
1506cd6a6acSopenharmony_ci *	       mmap(3) files).
1516cd6a6acSopenharmony_ci * @buf_len: length of buffer to copy.
1526cd6a6acSopenharmony_ci * @path: pointer to the specfile.
1536cd6a6acSopenharmony_ci *
1546cd6a6acSopenharmony_ci * Return %0 on success, -%1 with @errno set on failure.
1556cd6a6acSopenharmony_ci */
1566cd6a6acSopenharmony_ciint  digest_add_specfile(struct selabel_digest *digest, FILE *fp,
1576cd6a6acSopenharmony_ci				    char *from_addr, size_t buf_len,
1586cd6a6acSopenharmony_ci				    const char *path)
1596cd6a6acSopenharmony_ci{
1606cd6a6acSopenharmony_ci	unsigned char *tmp_buf;
1616cd6a6acSopenharmony_ci
1626cd6a6acSopenharmony_ci	/* If SELABEL_OPT_DIGEST not set then just return */
1636cd6a6acSopenharmony_ci	if (!digest)
1646cd6a6acSopenharmony_ci		return 0;
1656cd6a6acSopenharmony_ci
1666cd6a6acSopenharmony_ci	if (digest->hashbuf_size + buf_len < digest->hashbuf_size) {
1676cd6a6acSopenharmony_ci		errno = EOVERFLOW;
1686cd6a6acSopenharmony_ci		return -1;
1696cd6a6acSopenharmony_ci	}
1706cd6a6acSopenharmony_ci	digest->hashbuf_size += buf_len;
1716cd6a6acSopenharmony_ci
1726cd6a6acSopenharmony_ci	tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size);
1736cd6a6acSopenharmony_ci	if (!tmp_buf)
1746cd6a6acSopenharmony_ci		return -1;
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	digest->hashbuf = tmp_buf;
1776cd6a6acSopenharmony_ci
1786cd6a6acSopenharmony_ci	if (fp) {
1796cd6a6acSopenharmony_ci		rewind(fp);
1806cd6a6acSopenharmony_ci		if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len),
1816cd6a6acSopenharmony_ci					    1, buf_len, fp) != buf_len)
1826cd6a6acSopenharmony_ci			return -1;
1836cd6a6acSopenharmony_ci
1846cd6a6acSopenharmony_ci		rewind(fp);
1856cd6a6acSopenharmony_ci	} else if (from_addr) {
1866cd6a6acSopenharmony_ci		tmp_buf = memcpy(digest->hashbuf +
1876cd6a6acSopenharmony_ci				    (digest->hashbuf_size - buf_len),
1886cd6a6acSopenharmony_ci				    from_addr, buf_len);
1896cd6a6acSopenharmony_ci		if (!tmp_buf)
1906cd6a6acSopenharmony_ci			return -1;
1916cd6a6acSopenharmony_ci	}
1926cd6a6acSopenharmony_ci	/* Now add path to list */
1936cd6a6acSopenharmony_ci	digest->specfile_list[digest->specfile_cnt] = strdup(path);
1946cd6a6acSopenharmony_ci	if (!digest->specfile_list[digest->specfile_cnt])
1956cd6a6acSopenharmony_ci		return -1;
1966cd6a6acSopenharmony_ci
1976cd6a6acSopenharmony_ci	digest->specfile_cnt++;
1986cd6a6acSopenharmony_ci	if (digest->specfile_cnt > DIGEST_FILES_MAX) {
1996cd6a6acSopenharmony_ci		errno = EOVERFLOW;
2006cd6a6acSopenharmony_ci		return -1;
2016cd6a6acSopenharmony_ci	}
2026cd6a6acSopenharmony_ci
2036cd6a6acSopenharmony_ci	return 0;
2046cd6a6acSopenharmony_ci}
205