1/* 2 * This file contains helper functions for labeling support. 3 * 4 * Author : Richard Haines <richard_c_haines@btinternet.com> 5 */ 6 7#include <stdlib.h> 8#include <stdarg.h> 9#include <ctype.h> 10#include <string.h> 11#include <stdio.h> 12#include <errno.h> 13#include <errno.h> 14#include "label_internal.h" 15 16/* 17 * Read an entry from a spec file (e.g. file_contexts) 18 * entry - Buffer to allocate for the entry. 19 * ptr - current location of the line to be processed. 20 * returns - 0 on success and *entry is set to be a null 21 * terminated value. On Error it returns -1 and 22 * errno will be set. 23 * 24 */ 25static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf) 26{ 27 *entry = NULL; 28 char *tmp_buf = NULL; 29 30 while (isspace(**ptr) && **ptr != '\0') 31 (*ptr)++; 32 33 tmp_buf = *ptr; 34 *len = 0; 35 36 while (!isspace(**ptr) && **ptr != '\0') { 37 if (!isascii(**ptr)) { 38 errno = EINVAL; 39 *errbuf = "Non-ASCII characters found"; 40 return -1; 41 } 42 (*ptr)++; 43 (*len)++; 44 } 45 46 if (*len) { 47 *entry = strndup(tmp_buf, *len); 48 if (!*entry) 49 return -1; 50 } 51 52 return 0; 53} 54 55/* 56 * line_buf - Buffer containing the spec entries . 57 * errbuf - Double pointer used for passing back specific error messages. 58 * num_args - The number of spec parameter entries to process. 59 * ... - A 'char **spec_entry' for each parameter. 60 * returns - The number of items processed. On error, it returns -1 with errno 61 * set and may set errbuf to a specific error message. 62 * 63 * This function calls read_spec_entry() to do the actual string processing. 64 * As such, can return anything from that function as well. 65 */ 66int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) 67{ 68 char **spec_entry, *buf_p; 69 int len, rc, items, entry_len = 0; 70 va_list ap; 71 72 *errbuf = NULL; 73 74 len = strlen(line_buf); 75 if (line_buf[len - 1] == '\n') 76 line_buf[len - 1] = '\0'; 77 else 78 /* Handle case if line not \n terminated by bumping 79 * the len for the check below (as the line is NUL 80 * terminated by getline(3)) */ 81 len++; 82 83 buf_p = line_buf; 84 while (isspace(*buf_p)) 85 buf_p++; 86 87 /* Skip comment lines and empty lines. */ 88 if (*buf_p == '#' || *buf_p == '\0') 89 return 0; 90 91 /* Process the spec file entries */ 92 va_start(ap, num_args); 93 94 items = 0; 95 while (items < num_args) { 96 spec_entry = va_arg(ap, char **); 97 98 if (len - 1 == buf_p - line_buf) { 99 va_end(ap); 100 return items; 101 } 102 103 rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf); 104 if (rc < 0) { 105 va_end(ap); 106 return rc; 107 } 108 if (entry_len) 109 items++; 110 } 111 va_end(ap); 112 return items; 113} 114 115/* Once all the specfiles are in the hash_buf, generate the hash. */ 116void digest_gen_hash(struct selabel_digest *digest) 117{ 118 Sha1Context context; 119 size_t remaining_size; 120 const unsigned char *ptr; 121 122 /* If SELABEL_OPT_DIGEST not set then just return */ 123 if (!digest) 124 return; 125 126 Sha1Initialise(&context); 127 128 /* Process in blocks of UINT32_MAX bytes */ 129 remaining_size = digest->hashbuf_size; 130 ptr = digest->hashbuf; 131 while (remaining_size > UINT32_MAX) { 132 Sha1Update(&context, ptr, UINT32_MAX); 133 remaining_size -= UINT32_MAX; 134 ptr += UINT32_MAX; 135 } 136 Sha1Update(&context, ptr, remaining_size); 137 138 Sha1Finalise(&context, (SHA1_HASH *)digest->digest); 139 free(digest->hashbuf); 140 digest->hashbuf = NULL; 141 return; 142} 143 144/** 145 * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true 146 * then generate the hash. 147 * @digest: pointer to the selabel_digest struct 148 * @fp: file pointer for fread(3) or NULL if not. 149 * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for 150 * mmap(3) files). 151 * @buf_len: length of buffer to copy. 152 * @path: pointer to the specfile. 153 * 154 * Return %0 on success, -%1 with @errno set on failure. 155 */ 156int digest_add_specfile(struct selabel_digest *digest, FILE *fp, 157 char *from_addr, size_t buf_len, 158 const char *path) 159{ 160 unsigned char *tmp_buf; 161 162 /* If SELABEL_OPT_DIGEST not set then just return */ 163 if (!digest) 164 return 0; 165 166 if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { 167 errno = EOVERFLOW; 168 return -1; 169 } 170 digest->hashbuf_size += buf_len; 171 172 tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size); 173 if (!tmp_buf) 174 return -1; 175 176 digest->hashbuf = tmp_buf; 177 178 if (fp) { 179 rewind(fp); 180 if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len), 181 1, buf_len, fp) != buf_len) 182 return -1; 183 184 rewind(fp); 185 } else if (from_addr) { 186 tmp_buf = memcpy(digest->hashbuf + 187 (digest->hashbuf_size - buf_len), 188 from_addr, buf_len); 189 if (!tmp_buf) 190 return -1; 191 } 192 /* Now add path to list */ 193 digest->specfile_list[digest->specfile_cnt] = strdup(path); 194 if (!digest->specfile_list[digest->specfile_cnt]) 195 return -1; 196 197 digest->specfile_cnt++; 198 if (digest->specfile_cnt > DIGEST_FILES_MAX) { 199 errno = EOVERFLOW; 200 return -1; 201 } 202 203 return 0; 204} 205