1 /* 2 * This file contains helper functions for labeling support. 3 * 4 * Author : Richard Haines <richard_c_haines (at) 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 */ 25 static 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 */ 66 int hidden 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. */ 116 void hidden digest_gen_hash(struct selabel_digest *digest) 117 { 118 Sha1Context context; 119 120 /* If SELABEL_OPT_DIGEST not set then just return */ 121 if (!digest) 122 return; 123 124 Sha1Initialise(&context); 125 Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); 126 Sha1Finalise(&context, (SHA1_HASH *)digest->digest); 127 free(digest->hashbuf); 128 digest->hashbuf = NULL; 129 return; 130 } 131 132 /** 133 * digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true 134 * then generate the hash. 135 * @digest: pointer to the selabel_digest struct 136 * @fp: file pointer for fread(3) or NULL if not. 137 * @from_addr: pointer at start of buffer for memcpy or NULL if not (used for 138 * mmap(3) files). 139 * @buf_len: length of buffer to copy. 140 * @path: pointer to the specfile. 141 * 142 * Return %0 on success, -%1 with @errno set on failure. 143 */ 144 int hidden digest_add_specfile(struct selabel_digest *digest, FILE *fp, 145 char *from_addr, size_t buf_len, 146 const char *path) 147 { 148 unsigned char *tmp_buf; 149 150 /* If SELABEL_OPT_DIGEST not set then just return */ 151 if (!digest) 152 return 0; 153 154 if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { 155 errno = EOVERFLOW; 156 return -1; 157 } 158 digest->hashbuf_size += buf_len; 159 160 tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size); 161 if (!tmp_buf) 162 return -1; 163 164 digest->hashbuf = tmp_buf; 165 166 if (fp) { 167 rewind(fp); 168 if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len), 169 1, buf_len, fp) != buf_len) 170 return -1; 171 172 rewind(fp); 173 } else if (from_addr) { 174 tmp_buf = memcpy(digest->hashbuf + 175 (digest->hashbuf_size - buf_len), 176 from_addr, buf_len); 177 if (!tmp_buf) 178 return -1; 179 } 180 /* Now add path to list */ 181 digest->specfile_list[digest->specfile_cnt] = strdup(path); 182 if (!digest->specfile_list[digest->specfile_cnt]) 183 return -1; 184 185 digest->specfile_cnt++; 186 if (digest->specfile_cnt > DIGEST_FILES_MAX) { 187 errno = EOVERFLOW; 188 return -1; 189 } 190 191 return 0; 192 } 193