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 "label_internal.h" 14 15/* 16 * The read_spec_entries and read_spec_entry functions may be used to 17 * replace sscanf to read entries from spec files. The file and 18 * property services now use these. 19 */ 20static inline int read_spec_entry(char **entry, char **ptr, int *len) 21{ 22 *entry = NULL; 23 char *tmp_buf = NULL; 24 25 while (isspace(**ptr) && **ptr != '\0') 26 (*ptr)++; 27 28 tmp_buf = *ptr; 29 *len = 0; 30 31 while (!isspace(**ptr) && **ptr != '\0') { 32 (*ptr)++; 33 (*len)++; 34 } 35 36 if (*len) { 37 *entry = strndup(tmp_buf, *len); 38 if (!*entry) 39 return -1; 40 } 41 42 return 0; 43} 44 45/* 46 * line_buf - Buffer containing the spec entries . 47 * num_args - The number of spec parameter entries to process. 48 * ... - A 'char **spec_entry' for each parameter. 49 * returns - The number of items processed. 50 * 51 * This function calls read_spec_entry() to do the actual string processing. 52 */ 53int hidden read_spec_entries(char *line_buf, int num_args, ...) 54{ 55 char **spec_entry, *buf_p; 56 int len, rc, items, entry_len = 0; 57 va_list ap; 58 59 len = strlen(line_buf); 60 if (line_buf[len - 1] == '\n') 61 line_buf[len - 1] = '\0'; 62 else 63 /* Handle case if line not \n terminated by bumping 64 * the len for the check below (as the line is NUL 65 * terminated by getline(3)) */ 66 len++; 67 68 buf_p = line_buf; 69 while (isspace(*buf_p)) 70 buf_p++; 71 72 /* Skip comment lines and empty lines. */ 73 if (*buf_p == '#' || *buf_p == '\0') 74 return 0; 75 76 /* Process the spec file entries */ 77 va_start(ap, num_args); 78 79 items = 0; 80 while (items < num_args) { 81 spec_entry = va_arg(ap, char **); 82 83 if (len - 1 == buf_p - line_buf) { 84 va_end(ap); 85 return items; 86 } 87 88 rc = read_spec_entry(spec_entry, &buf_p, &entry_len); 89 if (rc < 0) { 90 va_end(ap); 91 return rc; 92 } 93 if (entry_len) 94 items++; 95 } 96 va_end(ap); 97 return items; 98} 99 100/* Once all the specfiles are in the hash_buf, generate the hash. */ 101void hidden digest_gen_hash(struct selabel_digest *digest) 102{ 103 Sha1Context context; 104 105 /* If SELABEL_OPT_DIGEST not set then just return */ 106 if (!digest) 107 return; 108 109 Sha1Initialise(&context); 110 Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); 111 Sha1Finalise(&context, (SHA1_HASH *)digest->digest); 112 free(digest->hashbuf); 113 digest->hashbuf = NULL; 114 return; 115} 116 117/** 118 * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true 119 * then generate the hash. 120 * @digest: pointer to the selabel_digest struct 121 * @fp: file pointer for fread(3) or NULL if not. 122 * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for 123 * mmap(3) files). 124 * @buf_len: length of buffer to copy. 125 * @path: pointer to the specfile. 126 * 127 * Return %0 on success, -%1 with @errno set on failure. 128 */ 129int hidden digest_add_specfile(struct selabel_digest *digest, FILE *fp, 130 char *from_addr, size_t buf_len, 131 const char *path) 132{ 133 unsigned char *tmp_buf; 134 135 /* If SELABEL_OPT_DIGEST not set then just return */ 136 if (!digest) 137 return 0; 138 139 if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { 140 errno = EOVERFLOW; 141 return -1; 142 } 143 digest->hashbuf_size += buf_len; 144 145 tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size); 146 if (!tmp_buf) 147 return -1; 148 149 digest->hashbuf = tmp_buf; 150 151 if (fp) { 152 rewind(fp); 153 if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len), 154 1, buf_len, fp) != buf_len) 155 return -1; 156 157 rewind(fp); 158 } else if (from_addr) { 159 tmp_buf = memcpy(digest->hashbuf + 160 (digest->hashbuf_size - buf_len), 161 from_addr, buf_len); 162 if (!tmp_buf) 163 return -1; 164 } 165 /* Now add path to list */ 166 digest->specfile_list[digest->specfile_cnt] = strdup(path); 167 if (!digest->specfile_list[digest->specfile_cnt]) 168 return -1; 169 170 digest->specfile_cnt++; 171 if (digest->specfile_cnt > DIGEST_FILES_MAX) { 172 errno = EOVERFLOW; 173 return -1; 174 } 175 176 return 0; 177} 178