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