]> git.cameronkatri.com Git - trustcache.git/blob - append.c
Add support for new version 2 trustcaches
[trustcache.git] / append.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 Cameron Katri. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY CAMERON KATRI AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL CAMERON KATRI OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <ctype.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "trustcache.h"
38 #include "uuid/uuid.h"
39
40 #include "compat.h"
41
42 static bool
43 ishexstring(const char *s) {
44 for (; *s != '\0'; s++)
45 if (!isxdigit(*s))
46 return false;
47 return true;
48 }
49
50 int
51 tcappend(int argc, char **argv)
52 {
53 int keepuuid = 0;
54 uuid_t uuid;
55 const char *errstr = NULL;
56 uint8_t flags = 0;
57 uint16_t category = 0;
58
59 int ch;
60 while ((ch = getopt(argc, argv, "u:f:c:")) != -1) {
61 switch (ch) {
62 case 'u':
63 if (strlen(optarg) == 1 && *optarg == '0') {
64 keepuuid = 1;
65 } else {
66 if (uuid_parse(optarg, uuid) != 0) {
67 fprintf(stderr, "Failed to parse %s as a UUID\n", optarg);
68 } else
69 keepuuid = 2;
70 }
71 break;
72 case 'f':
73 flags = strtonum(optarg, 0, UINT8_MAX, &errstr);
74 if (errstr != NULL) {
75 fprintf(stderr, "flag number is %s: %s\n", errstr, optarg);
76 exit(1);
77 }
78 break;
79 case 'c':
80 category = strtonum(optarg, 0, UINT16_MAX, &errstr);
81 if (errstr != NULL) {
82 fprintf(stderr, "category number is %s: %s\n", errstr, optarg);
83 exit(1);
84 }
85 break;
86 }
87 }
88
89 argc -= optind;
90 argv += optind;
91
92 if (argc < 2)
93 return -1;
94
95 FILE *f = NULL;
96 struct trust_cache cache = opentrustcache(argv[0]);
97 struct trust_cache append = {
98 .version = cache.version,
99 .num_entries = 0
100 };
101
102 for (int i = 1; i < argc; i++) {
103 if (strlen(argv[i]) == 40 && ishexstring(argv[i])) {
104 append.num_entries = 1;
105 if (append.version == 0) {
106 append.hashes = calloc(1, sizeof(trust_cache_hash0));
107 for (size_t j = 0; j < CS_CDHASH_LEN; j++)
108 sscanf(argv[i] + 2 * j, "%02hhx", &append.hashes[0][j]);
109 } else if (append.version == 1) {
110 append.entries = calloc(1, sizeof(struct trust_cache_entry1));
111 for (size_t j = 0; j < CS_CDHASH_LEN; j++)
112 sscanf(argv[i] + 2 * j, "%02hhx", &append.entries[0].cdhash[j]);
113 } else if (append.version == 2) {
114 append.entries2 = calloc(1, sizeof(struct trust_cache_entry2));
115 for (size_t j = 0; j < CS_CDHASH_LEN; j++)
116 sscanf(argv[i] + 2 * j, "%02hhx", &append.entries2[0].cdhash[j]);
117 }
118 } else {
119 append = cache_from_tree(argv[i], cache.version);
120 }
121 if (append.version == 0) {
122 if ((cache.hashes = realloc(cache.hashes, sizeof(trust_cache_hash0) *
123 (cache.num_entries + append.num_entries))) == NULL)
124 exit(1);
125 for (uint32_t j = 0; j < append.num_entries; j++) {
126 memcpy(cache.hashes[cache.num_entries + j], append.hashes[j], CS_CDHASH_LEN);
127 }
128 } else if (append.version == 1) {
129 if ((cache.entries = realloc(cache.entries, sizeof(struct trust_cache_entry1) *
130 (cache.num_entries + append.num_entries))) == NULL)
131 exit(1);
132 for (uint32_t j = 0; j < append.num_entries; j++) {
133 cache.entries[cache.num_entries + j].hash_type = append.entries[j].hash_type;
134 cache.entries[cache.num_entries + j].flags = flags != 0 ? flags : append.entries[j].flags;
135 memcpy(cache.entries[cache.num_entries + j].cdhash, append.entries[j].cdhash, CS_CDHASH_LEN);
136 }
137 } else if (append.version == 2) {
138 if ((cache.entries2 = realloc(cache.entries, sizeof(struct trust_cache_entry2) *
139 (cache.num_entries + append.num_entries))) == NULL)
140 exit(1);
141 for (uint32_t j = 0; j < append.num_entries; j++) {
142 cache.entries2[cache.num_entries + j].hash_type = append.entries[j].hash_type;
143 cache.entries2[cache.num_entries + j].flags = flags != 0 ? flags : append.entries[j].flags;
144 cache.entries2[cache.num_entries + j].category = category != 0 ? category : append.entries2[j].category;
145 memcpy(cache.entries2[cache.num_entries + j].cdhash, append.entries2[j].cdhash, CS_CDHASH_LEN);
146 }
147 }
148 free(append.hashes);
149 cache.num_entries += append.num_entries;
150 }
151
152 if (cache.version == 0)
153 qsort(cache.hashes, cache.num_entries, sizeof(*cache.hashes), hash_cmp);
154 else if (cache.version == 1)
155 qsort(cache.entries, cache.num_entries, sizeof(*cache.entries), ent_cmp);
156 else if (cache.version == 2)
157 qsort(cache.entries, cache.num_entries, sizeof(*cache.entries2), ent_cmp);
158
159 switch (keepuuid) {
160 case 0:
161 uuid_generate(cache.uuid);
162 break;
163 case 1:
164 break;
165 case 2:
166 uuid_copy(cache.uuid, uuid);
167 break;
168 }
169
170 if (writetrustcache(cache, argv[0]) == -1)
171 return 1;
172
173 free(cache.entries);
174 return 0;
175 }