]> git.saurik.com Git - apple/file_cmds.git/blobdiff - mtree/commoncrypto.c
file_cmds-264.50.1.tar.gz
[apple/file_cmds.git] / mtree / commoncrypto.c
index 0dda1f04dfc4b2b560d41b193b2ef757f54b3519..88efada8db3785118aec86c32505ec4d6fa6ad96 100644 (file)
@@ -2,14 +2,29 @@
 #include <os/assumes.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <stdbool.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/attr.h>
+#include <unistd.h>
 
 #include "commoncrypto.h"
 
+const int kSHA256NullTerminatedBuffLen = 65;
+static const char hex[] = "0123456789abcdef";
+
+/* Functions for SHA256_File_XATTRs */
+#define SHA256_Data(d, s, b)    Digest_Data(kCCDigestSHA256, d, s, b)
+char *Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf);
+void Quicksort(char **array, int num);
+
 /* Generic version of libmd's *_File() functions. */
 char *
 Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
 {
-       static const char hex[] = "0123456789abcdef";
        int fd;
        __block CCDigestCtx ctx;
        dispatch_queue_t queue;
@@ -75,6 +90,150 @@ Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
                buf[i+i+1] = hex[digest[i] & 0x0f];
        }
        buf[i+i] = '\0';
+       
+       return buf;
+}
+
+char *SHA256_Path_XATTRs(char *path, char *buf)
+{
+       char *xattrsSummary = NULL;
+       int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
+       ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+       if (nameBufSize > 0) {
+               char *nameBuf = malloc(nameBufSize);
+               
+               listxattr(path, nameBuf, nameBufSize, options);
+               
+               size_t xattrsLen = 1;
+               size_t xattrIndex = 0;
+               char **xattrs = malloc(xattrsLen * sizeof(char *));
+               char *nextName = nameBuf;
+               while (nextName < nameBuf + nameBufSize)
+               {
+                       char *name = nextName;
+                       if (xattrIndex == xattrsLen) {
+                               xattrsLen *= 2;
+                               xattrs = realloc(xattrs, xattrsLen * sizeof(char *));
+                       }
+                       xattrs[xattrIndex++] = name;
+                       nextName += strlen(name) + 1;
+               }
+               
+               // sort the xattr array as they're not guaranteed to come in the same order
+               qsort_b(xattrs, xattrIndex, sizeof(char *), ^(const void *l, const void *r) {
+                       char *left = *(char **)l;
+                       char *right = *(char **)r;
+                       return strcmp(left, right);
+               });
+               
+               // gather the data for the xattrs
+               bool didAddXATTR = false;
+               int xattrBufLen = kSHA256NullTerminatedBuffLen;
+               void *xattrBuf = malloc(xattrBufLen); // resized if necessary
+               char *digest;
+               ssize_t result = 0;
+               char *oldSummary = NULL;
+               for (int i = 0; i < xattrIndex; i++) {
+                       char *name = xattrs[i];
+                       ssize_t xlen = getxattr(path, name, NULL, 0, 0, options);
+                       if (xlen > xattrBufLen) {
+                               xattrBufLen = xlen;
+                               xattrBuf = realloc(xattrBuf, xattrBufLen);
+                       }
+                       bzero(xattrBuf, xattrBufLen);
+                       result = getxattr(path, name, xattrBuf, xattrBufLen, 0, options);
+                       if (result < 0)
+                               err(1, "SHA256_Path_XATTRs: getxattr");
+                       
+                       digest = SHA256_Data(xattrBuf, xattrBufLen, buf);
+                       if (!digest)
+                               err(1, "%s", xattrsSummary);
+                       if (!didAddXATTR)
+                       {
+                               didAddXATTR = true;
+                               asprintf(&xattrsSummary, "%s:%s", name, digest);
+                       } else {
+                               oldSummary = xattrsSummary;
+                               asprintf(&xattrsSummary, "%s, %s:%s", oldSummary, name, digest);
+                               free(oldSummary);
+                       }
+               }
+               
+               free(xattrBuf);
+               free(nameBuf);
+               free(xattrs);
+               
+               digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
+               if (!digest)
+                       err(1, "%s", xattrsSummary);
+               
+               free(xattrsSummary);
+               return digest;
+       }
+       return kNone;
+}
+
+char *SHA256_Path_ACL(char *path, char *buf)
+{
+       int result              = 0;
+       char *data              = NULL;
+       char *digest            = NULL;
+       
+       struct attrlist list = {
+               .bitmapcount    = ATTR_BIT_MAP_COUNT,
+               .commonattr     = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_EXTENDED_SECURITY,
+       };
+       
+       struct ACLBuf {
+               uint32_t                len;
+               attribute_set_t         returned_attrs;
+               attrreference_t         acl;
+               char                    buf[8192]; // current acls are up to 3116 bytes, but they may increase in the future
+       } __attribute__((aligned(4), packed));
+       
+       struct ACLBuf aclBuf;
+       
+       result = getattrlist(path, &list, &aclBuf, sizeof(aclBuf), FSOPT_NOFOLLOW);
+       
+       if (result)
+               err(1, "SHA256_Path_ACL: getattrlist");
+       
+       // if the path does not have an acl, return none
+       if ( ( ! ( aclBuf.returned_attrs.commonattr & ATTR_CMN_EXTENDED_SECURITY ) )
+           || ( aclBuf.acl.attr_length == 0 ) ) {
+               return kNone;
+       }
+       
+       data = ((char*)&aclBuf.acl) + aclBuf.acl.attr_dataoffset;
+       
+       digest = SHA256_Data(data, aclBuf.acl.attr_length, buf);
+       if (!digest)
+               err(1, "SHA256_Path_ACL: SHA256_Data");
+       
+       return digest;
+}
 
+/* Functions for Digest_Path_* */
+char *
+Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf) {
+       
+       uint8_t digest[32]; // SHA256 is the biggest
+       CCDigestCtx ctx;
+       size_t i, length;
+       
+       (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+       (void)os_assumes_zero(CCDigestUpdate(&ctx, data, size));
+       
+       /* Finalize and convert to hex. */
+       (void)os_assumes_zero(CCDigestFinal(&ctx, digest));
+       length = CCDigestOutputSize(&ctx);
+       os_assert(length <= sizeof(digest));
+       for (i = 0; i < length; i++) {
+               buf[i+i] = hex[digest[i] >> 4];
+               buf[i+i+1] = hex[digest[i] & 0x0f];
+       }
+       buf[i+i] = '\0';
+       
        return buf;
 }
+