]> git.cameronkatri.com Git - trustcache.git/commitdiff
Add tc remove and append -f flags
authorCameron Katri <me@cameronkatri.com>
Sun, 22 May 2022 03:44:49 +0000 (23:44 -0400)
committerCameron Katri <me@cameronkatri.com>
Sun, 22 May 2022 03:44:49 +0000 (23:44 -0400)
Also fix some conflicting types to hopefully prevent possible overflows.

.gitignore
Makefile
README.txt
append.c
create.c
info.c
remove.c [new file with mode: 0644]
tc.1
tc.c
trustcache.h

index 4c3a7958a80d8b0a1154e39fe91e7c0dfc1cf98b..93ac639c824d575360dc489ee368889581ddf3bb 100644 (file)
@@ -2,3 +2,4 @@ a.out
 *.o
 *.bin
 tc
+.vscode
index 364764d719321dc722aa510e910c24ac850d8a42..fb2bd372f3053a1648873d8311074db475cf0733 100644 (file)
--- 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
 
index 2e55a09211083b50210550efd82db328912758b4..295f66fcfaa0aba2ae607cd13ea3701f0656efd7 100644 (file)
@@ -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.
 
index 475200ea0f71a8bb1a02e46e01338536a71f1736..a5cd031116ad954064a2b03040f25c7d821c0c92 100644 (file)
--- 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>
 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)
index a19d7f3ee57d15722baf6d39c368cf61ca0e9573..955c833972d29ddc4729a397ec6953684d61a82c 100644 (file)
--- 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 c676586ee0a93f774a1c189714a4670ea865bd59..8de924c475d45b9125ce2849f7dad928e47449d1 100644 (file)
--- a/info.c
+++ b/info.c
  */
 
 #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 (file)
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 19df3de2dc38dfb0909678d5f54020b74e948b37..030eaf1282c9e50556db65d81ded1a56cfa11904 100644 (file)
--- 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
 .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 f6cc759477aef26c161e51aebd198d5d45e9578b..6142057c32d1a1cf58f94cc6f90b89a880f2169d 100644 (file)
--- 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]);
 
index 1f8a3cd7c66a2c2971cbe9f7714abd0b1fc45601..5b75459237fcf7f692ee45acbc8628e0bcdec685 100644 (file)
@@ -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