aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2022-05-21 23:44:49 -0400
committerCameron Katri <me@cameronkatri.com>2022-05-21 23:44:49 -0400
commit2288b178e612386e7a75471c8861c3f6d81c300d (patch)
tree18209f47e0bc635000f7bf86b83f43a9ab0aa3ea
parentaa035f73ce081b3f07247bd15860d72355a096b2 (diff)
downloadtrustcache-2288b178e612386e7a75471c8861c3f6d81c300d.tar.gz
trustcache-2288b178e612386e7a75471c8861c3f6d81c300d.tar.zst
trustcache-2288b178e612386e7a75471c8861c3f6d81c300d.zip
Add tc remove and append -f flags
Also fix some conflicting types to hopefully prevent possible overflows.
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--README.txt13
-rw-r--r--append.c26
-rw-r--r--create.c9
-rw-r--r--info.c25
-rw-r--r--remove.c120
-rw-r--r--tc.123
-rw-r--r--tc.c7
-rw-r--r--trustcache.h7
10 files changed, 200 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
index 4c3a795..93ac639 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ a.out
*.o
*.bin
tc
+.vscode
diff --git a/Makefile b/Makefile
index 364764d..fb2bd37 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
OBJS = tc.o
-OBJS += append.o create.o info.o
+OBJS += append.o create.o info.o remove.o
OBJS += machoparse/cdhash.o cache_from_tree.o sort.o
OBJS += uuid/gen_uuid.o uuid/pack.o uuid/unpack.o uuid/parse.o uuid/unparse.o uuid/copy.o
diff --git a/README.txt b/README.txt
index 2e55a09..295f66f 100644
--- a/README.txt
+++ b/README.txt
@@ -4,20 +4,22 @@ NAME
tc – Create and interact with trustcaches
SYNOPSIS
- tc append [-u uuid | 0] infile file ...
+ tc append [-f flags] [-u uuid | 0] infile file ...
tc create [-u uuid] [-v version] outfile file ...
tc info [-c] [-h] [-e entrynum] file
+ tc remove [-k] file hash ...
DESCRIPTION
The tc utility is used to get info about and modify Apple trustcaches.
The following commands are supported by tc:
- append [-u uuid | 0] infile file ...
+ append [-f flags] [-u uuid | 0] infile file ...
Modify the trustcache at infile to include each signed Mach-O in
the specified path. uuid is used to specify a custom uuid to be
used. If it is 0, the uuid will be left the same, otherwise, it
- will be regenerated.
+ will be regenerated. If -f is specified, any new entries with
+ have the flags specified at flags.
create [-u uuid] [-v version] outfile file ...
Create a trustcache at outfile. Each Mach-O found in the
@@ -37,6 +39,11 @@ DESCRIPTION
given, only the header will be printed. If entrynum is
specified, only that entry will be printed.
+ remove [-k] file hash ...
+ Remove each specified hash from file. If -k is specified, the
+ uuid will not be regenerated. The number of removed entries will
+ be printed.
+
EXIT STATUS
The tc utility exits 0 on success, and >0 if an error occurs.
diff --git a/append.c b/append.c
index 475200e..a5cd031 100644
--- a/append.c
+++ b/append.c
@@ -28,6 +28,7 @@
#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -38,14 +39,13 @@
int
tcappend(int argc, char **argv)
{
- if (argc < 3)
- return -1;
-
int keepuuid = 0;
uuid_t uuid;
+ const char *errstr = NULL;
+ uint8_t flags = 0;
int ch;
- while ((ch = getopt(argc, argv, "u:")) != -1) {
+ while ((ch = getopt(argc, argv, "u:f:")) != -1) {
switch (ch) {
case 'u':
if (strlen(optarg) == 1 && *optarg == '0') {
@@ -57,12 +57,22 @@ tcappend(int argc, char **argv)
keepuuid = 2;
}
break;
+ case 'f':
+ flags = strtonum(optarg, 0, UINT8_MAX, &errstr);
+ if (errstr != NULL) {
+ fprintf(stderr, "flag number is %s: %s\n", errstr, optarg);
+ exit(1);
+ }
+ break;
}
}
argc -= optind;
argv += optind;
+ if (argc < 2)
+ return -1;
+
FILE *f = NULL;
struct trust_cache cache = opentrustcache(argv[0]);
struct trust_cache append = {
@@ -76,16 +86,16 @@ tcappend(int argc, char **argv)
if ((cache.hashes = realloc(cache.hashes, sizeof(trust_cache_hash0) *
(cache.num_entries + append.num_entries))) == NULL)
exit(1);
- for (int j = 0; j < append.num_entries; j++) {
+ for (uint32_t j = 0; j < append.num_entries; j++) {
memcpy(cache.hashes[cache.num_entries + j], append.hashes[j], CS_CDHASH_LEN);
}
} else if (append.version == 1) {
if ((cache.entries = realloc(cache.entries, sizeof(struct trust_cache_entry1) *
(cache.num_entries + append.num_entries))) == NULL)
exit(1);
- for (int j = 0; j < append.num_entries; j++) {
+ for (uint32_t j = 0; j < append.num_entries; j++) {
cache.entries[cache.num_entries + j].hash_type = append.entries[j].hash_type;
- cache.entries[cache.num_entries + j].flags = append.entries[j].flags;
+ cache.entries[cache.num_entries + j].flags = flags != 0 ? flags : append.entries[j].flags;
memcpy(cache.entries[cache.num_entries + j].cdhash, append.entries[j].cdhash, CS_CDHASH_LEN);
}
}
@@ -120,7 +130,7 @@ tcappend(int argc, char **argv)
cache.version = le32toh(cache.version);
cache.num_entries = le32toh(cache.num_entries);
- for (int i = 0; i < cache.num_entries; i++) {
+ for (uint32_t i = 0; i < cache.num_entries; i++) {
if (cache.version == 0)
fwrite(&cache.hashes[i], sizeof(trust_cache_hash0), 1, f);
else if (cache.version == 1)
diff --git a/create.c b/create.c
index a19d7f3..955c833 100644
--- a/create.c
+++ b/create.c
@@ -71,9 +71,8 @@ tccreate(int argc, char **argv)
argc -= optind;
argv += optind;
- if (argc == 0) {
+ if (argc == 0)
return -1;
- }
for (int i = 1; i < argc; i++) {
append = cache_from_tree(argv[i], cache.version);
@@ -81,14 +80,14 @@ tccreate(int argc, char **argv)
if ((cache.hashes = realloc(cache.hashes, sizeof(trust_cache_hash0) *
(cache.num_entries + append.num_entries))) == NULL)
exit(1);
- for (int j = 0; j < append.num_entries; j++) {
+ for (uint32_t j = 0; j < append.num_entries; j++) {
memcpy(cache.hashes[cache.num_entries + j], append.hashes[j], CS_CDHASH_LEN);
}
} else if (append.version == 1) {
if ((cache.entries = realloc(cache.entries, sizeof(struct trust_cache_entry1) *
(cache.num_entries + append.num_entries))) == NULL)
exit(1);
- for (int j = 0; j < append.num_entries; j++) {
+ for (uint32_t j = 0; j < append.num_entries; j++) {
cache.entries[cache.num_entries + j].hash_type = append.entries[j].hash_type;
cache.entries[cache.num_entries + j].flags = append.entries[j].flags;
memcpy(cache.entries[cache.num_entries + j].cdhash, append.entries[j].cdhash, CS_CDHASH_LEN);
@@ -115,7 +114,7 @@ tccreate(int argc, char **argv)
cache.version = le32toh(cache.version);
cache.num_entries = le32toh(cache.num_entries);
- for (int i = 0; i < cache.num_entries; i++) {
+ for (uint32_t i = 0; i < cache.num_entries; i++) {
if (cache.version == 1)
fwrite(&cache.entries[i], sizeof(struct trust_cache_entry1), 1, f);
else if (cache.version == 0)
diff --git a/info.c b/info.c
index c676586..8de924c 100644
--- a/info.c
+++ b/info.c
@@ -26,24 +26,19 @@
*/
#include <getopt.h>
-#include <limits.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "trustcache.h"
-void print_header(struct trust_cache cache);
-void print_hash(uint8_t cdhash[CS_CDHASH_LEN], bool newline);
-void print_entry(struct trust_cache_entry1 entry);
-void print_entries(struct trust_cache cache);
-
int
tcinfo(int argc, char **argv)
{
struct trust_cache cache;
bool headeronly = false, onlyhash = false;
- int entrynum = -1;
+ uint32_t entrynum = -1;
const char *errstr = NULL;
int ch;
@@ -53,7 +48,7 @@ tcinfo(int argc, char **argv)
headeronly = true;
break;
case 'e':
- entrynum = strtonum(optarg, 1, INT_MAX, &errstr);
+ entrynum = strtonum(optarg, 1, UINT32_MAX, &errstr);
if (errstr != NULL) {
fprintf(stderr, "entry number is %s: %s\n", errstr, optarg);
exit(1);
@@ -68,9 +63,8 @@ tcinfo(int argc, char **argv)
argc -= optind;
argv += optind;
- if (argc == 0) {
+ if (argc == 0)
return -1;
- }
cache = opentrustcache(argv[0]);
@@ -78,7 +72,7 @@ tcinfo(int argc, char **argv)
print_header(cache);
if (!headeronly) {
if (onlyhash) {
- for (int i = 0; i < cache.num_entries; i++) {
+ for (uint32_t i = 0; i < cache.num_entries; i++) {
if (cache.version == 0)
print_hash(cache.hashes[i], true);
else
@@ -120,7 +114,7 @@ print_header(struct trust_cache cache)
void
print_entries(struct trust_cache cache)
{
- for (int i = 0; i < cache.num_entries; i++) {
+ for (uint32_t i = 0; i < cache.num_entries; i++) {
if (cache.version == 0)
print_hash(cache.hashes[i], true);
else if (cache.version == 1)
@@ -143,9 +137,12 @@ print_entry(struct trust_cache_entry1 entry)
case CS_TRUST_CACHE_AMFID|CS_TRUST_CACHE_ANE:
printf(" CS_TRUST_CACHE_AMFID|CS_TRUST_CACHE_ANE ");
break;
- default:
+ case 0:
printf(" [none] ");
break;
+ default:
+ printf(" [%i] ", entry.flags);
+ break;
}
printf("[%i]\n", entry.hash_type);
@@ -154,7 +151,7 @@ print_entry(struct trust_cache_entry1 entry)
void
print_hash(uint8_t cdhash[CS_CDHASH_LEN], bool newline)
{
- for (int j = 0; j < CS_CDHASH_LEN; j++) {
+ for (size_t j = 0; j < CS_CDHASH_LEN; j++) {
printf("%02x", cdhash[j]);
}
if (newline)
diff --git a/remove.c b/remove.c
new file mode 100644
index 0000000..442a9e2
--- /dev/null
+++ b/remove.c
@@ -0,0 +1,120 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Cameron Katri. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAMERON KATRI AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CAMERON KATRI OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "trustcache.h"
+#include "uuid/uuid.h"
+
+int
+tcremove(int argc, char **argv)
+{
+ bool keepuuid = false;
+ int numremoved = 0;
+
+ int ch;
+ while ((ch = getopt(argc, argv, "k")) != -1) {
+ switch (ch) {
+ case 'k':
+ keepuuid = true;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ return -1;
+
+ FILE *f = NULL;
+ struct trust_cache cache = opentrustcache(argv[0]);
+
+ if (!keepuuid)
+ uuid_generate(cache.uuid);
+
+ uint8_t hash[CS_CDHASH_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+ for (int i = 1; i < argc; i++) {
+ if (strlen(argv[i]) != 40) {
+ fprintf(stderr, "%s is not a valid CDHash\n", argv[i]);
+ exit(1);
+ }
+ for (size_t j = 0; j < CS_CDHASH_LEN; j++)
+ sscanf(argv[i] + 2 * j, "%02hhx", &hash[j]);
+
+ uint32_t j = 0;
+ while (j < cache.num_entries) {
+ if (cache.version == 0) {
+ if (memcmp(cache.hashes[j], hash, CS_CDHASH_LEN) == 0) {
+ memmove(&cache.hashes[j], &cache.hashes[j + 1], (cache.num_entries - j - 1) * sizeof(trust_cache_hash0));
+ cache.num_entries--;
+ numremoved++;
+ continue;
+ }
+ } else if (cache.version == 1) {
+ if (memcmp(cache.entries[j].cdhash, hash, CS_CDHASH_LEN) == 0) {
+ memmove(&cache.entries[j], &cache.entries[j + 1], (cache.num_entries - j - 1) * sizeof(struct trust_cache_entry1));
+ cache.num_entries--;
+ numremoved++;
+ continue;
+ }
+ }
+ j++;
+ }
+ for (size_t j = 0; j < CS_CDHASH_LEN; j++)
+ hash[j] = 0;
+ }
+
+ if ((f = fopen(argv[0], "wb")) == NULL) {
+ fprintf(stderr, "%s: %s\n", argv[0], strerror(errno));
+ return 1;
+ }
+
+ cache.version = htole32(cache.version);
+ cache.num_entries = htole32(cache.num_entries);
+ fwrite(&cache, sizeof(struct trust_cache) - sizeof(struct trust_cache_entry1*), 1, f);
+ cache.version = le32toh(cache.version);
+ cache.num_entries = le32toh(cache.num_entries);
+
+ for (uint32_t i = 0; i < cache.num_entries; i++) {
+ if (cache.version == 0)
+ fwrite(&cache.hashes[i], sizeof(trust_cache_hash0), 1, f);
+ else if (cache.version == 1)
+ fwrite(&cache.entries[i], sizeof(struct trust_cache_entry1), 1, f);
+ }
+
+ printf("Removed %i %s\n", numremoved, numremoved == 1 ? "entry" : "entries");
+
+ return 0;
+}
diff --git a/tc.1 b/tc.1
index 19df3de..030eaf1 100644
--- a/tc.1
+++ b/tc.1
@@ -31,6 +31,7 @@
.Sh SYNOPSIS
.Nm
.Cm append
+.Op Fl f Ar flags
.Op Fl u Ar uuid | 0
.Ar infile
.Ar
@@ -46,6 +47,11 @@
.Op Fl h
.Op Fl e Ar entrynum
.Ar file
+.Nm
+.Cm remove
+.Op Fl k
+.Ar file
+.Ar hash ...
.Sh DESCRIPTION
The
.Nm
@@ -56,6 +62,7 @@ The following commands are supported by
.Bl -tag -width create
.It Xo
.Cm append
+.Op Fl f Ar flags
.Op Fl u Ar uuid | 0
.Ar infile
.Ar
@@ -68,6 +75,10 @@ is used to specify a custom uuid to be used.
If it is
.Ar 0 ,
the uuid will be left the same, otherwise, it will be regenerated.
+If
+.Fl f
+is specified, any new entries with have the flags specified at
+.Ar flags .
.It Xo
.Cm create
.Op Fl u Ar uuid
@@ -107,6 +118,18 @@ is given, only the header will be printed.
If
.Ar entrynum
is specified, only that entry will be printed.
+.It Xo
+.Cm remove
+.Op Fl k
+.Ar file
+.Ar hash ...
+.Xc
+Remove each specified hash from
+.Ar file .
+If
+.Fl k
+is specified, the uuid will not be regenerated.
+The number of removed entries will be printed.
.El
.Sh EXIT STATUS
.Ex -std
diff --git a/tc.c b/tc.c
index f6cc759..6142057 100644
--- a/tc.c
+++ b/tc.c
@@ -41,9 +41,10 @@ main(int argc, char **argv)
{
if (argc < 2) {
help:
- fprintf(stderr, "Usage: tc append [-u uuid | 0] infile file ...\n"
+ fprintf(stderr, "Usage: tc append [-f flags] [-u uuid | 0] infile file ...\n"
" tc create [-u uuid] [-v version] outfile file ...\n"
- " tc info [-c] [-h] [-e entrynum] file\n\n"
+ " tc info [-c] [-h] [-e entrynum] file\n"
+ " tc remove [-k] file hash ...\n\n"
"See tc(1) for more information\n");
exit(1);
}
@@ -56,6 +57,8 @@ help:
ret = tccreate(argc - 1, argv + 1);
else if (strcmp(argv[1], "append") == 0)
ret = tcappend(argc - 1, argv + 1);
+ else if (strcmp(argv[1], "remove") == 0)
+ ret = tcremove(argc - 1, argv + 1);
else
fprintf(stderr, "Unknown subcommand %s\n", argv[1]);
diff --git a/trustcache.h b/trustcache.h
index 1f8a3cd..5b75459 100644
--- a/trustcache.h
+++ b/trustcache.h
@@ -1,6 +1,7 @@
#ifndef _TRUSTCACHE_H_
#define _TRUSTCACHE_H_
+#include <stdbool.h>
#include <sys/types.h>
#if __APPLE__
@@ -44,8 +45,14 @@ struct trust_cache cache_from_tree(const char *path, uint32_t version);
int tcinfo(int argc, char **argv);
int tccreate(int argc, char **argv);
int tcappend(int argc, char **argv);
+int tcremove(int argc, char **argv);
int ent_cmp(const void * vp1, const void * vp2);
int hash_cmp(const void * vp1, const void * vp2);
+void print_header(struct trust_cache cache);
+void print_hash(uint8_t cdhash[CS_CDHASH_LEN], bool newline);
+void print_entry(struct trust_cache_entry1 entry);
+void print_entries(struct trust_cache cache);
+
#endif