1 #include <dispatch/dispatch.h>
2 #include <os/assumes.h>
14 #include "commoncrypto.h"
16 const int kSHA256NullTerminatedBuffLen
= 65;
17 static const char hex
[] = "0123456789abcdef";
19 /* Functions for SHA256_File_XATTRs */
20 #define SHA256_Data(d, s, b) Digest_Data(kCCDigestSHA256, d, s, b)
21 char *Digest_Data(CCDigestAlg algorithm
, void *data
, size_t size
, char *buf
);
22 void Quicksort(char **array
, int num
);
24 /* Generic version of libmd's *_File() functions. */
26 Digest_File(CCDigestAlg algorithm
, const char *filename
, char *buf
)
29 __block CCDigestCtx ctx
;
30 dispatch_queue_t queue
;
31 dispatch_semaphore_t sema
;
33 __block
int s_error
= 0;
34 uint8_t digest
[32]; // SHA256 is the biggest
37 /* dispatch_io_create_with_path requires an absolute path */
38 fd
= open(filename
, O_RDONLY
);
43 (void)fcntl(fd
, F_NOCACHE
, 1);
45 (void)os_assumes_zero(CCDigestInit(algorithm
, &ctx
));
47 queue
= dispatch_queue_create("com.apple.mtree.io", NULL
);
49 sema
= dispatch_semaphore_create(0);
52 io
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, queue
, ^(int error
) {
57 (void)dispatch_semaphore_signal(sema
);
60 dispatch_io_read(io
, 0, SIZE_MAX
, queue
, ^(__unused
bool done
, dispatch_data_t data
, int error
) {
62 (void)dispatch_data_apply(data
, ^(__unused dispatch_data_t region
, __unused
size_t offset
, const void *buffer
, size_t size
) {
63 (void)os_assumes_zero(CCDigestUpdate(&ctx
, buffer
, size
));
72 dispatch_release(io
); // it will close on its own
74 (void)dispatch_semaphore_wait(sema
, DISPATCH_TIME_FOREVER
);
76 dispatch_release(queue
);
77 dispatch_release(sema
);
84 /* Finalize and convert to hex. */
85 (void)os_assumes_zero(CCDigestFinal(&ctx
, digest
));
86 length
= CCDigestOutputSize(&ctx
);
87 os_assert(length
<= sizeof(digest
));
88 for (i
= 0; i
< length
; i
++) {
89 buf
[i
+i
] = hex
[digest
[i
] >> 4];
90 buf
[i
+i
+1] = hex
[digest
[i
] & 0x0f];
97 char *SHA256_Path_XATTRs(char *path
, char *buf
)
99 char *xattrsSummary
= NULL
;
100 int options
= XATTR_SHOWCOMPRESSION
| XATTR_NOFOLLOW
;
101 ssize_t nameBufSize
= listxattr(path
, NULL
, 0, options
);
102 if (nameBufSize
> 0) {
103 char *nameBuf
= malloc(nameBufSize
);
105 listxattr(path
, nameBuf
, nameBufSize
, options
);
107 size_t xattrsLen
= 1;
108 size_t xattrIndex
= 0;
109 char **xattrs
= malloc(xattrsLen
* sizeof(char *));
110 char *nextName
= nameBuf
;
111 while (nextName
< nameBuf
+ nameBufSize
)
113 char *name
= nextName
;
114 if (xattrIndex
== xattrsLen
) {
116 xattrs
= realloc(xattrs
, xattrsLen
* sizeof(char *));
118 xattrs
[xattrIndex
++] = name
;
119 nextName
+= strlen(name
) + 1;
122 // sort the xattr array as they're not guaranteed to come in the same order
123 qsort_b(xattrs
, xattrIndex
, sizeof(char *), ^(const void *l
, const void *r
) {
124 char *left
= *(char **)l
;
125 char *right
= *(char **)r
;
126 return strcmp(left
, right
);
129 // gather the data for the xattrs
130 bool didAddXATTR
= false;
131 int xattrBufLen
= kSHA256NullTerminatedBuffLen
;
132 void *xattrBuf
= malloc(xattrBufLen
); // resized if necessary
135 char *oldSummary
= NULL
;
136 for (int i
= 0; i
< xattrIndex
; i
++) {
137 char *name
= xattrs
[i
];
138 ssize_t xlen
= getxattr(path
, name
, NULL
, 0, 0, options
);
139 if (xlen
> xattrBufLen
) {
141 xattrBuf
= realloc(xattrBuf
, xattrBufLen
);
143 bzero(xattrBuf
, xattrBufLen
);
144 result
= getxattr(path
, name
, xattrBuf
, xattrBufLen
, 0, options
);
146 err(1, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name
, path
);
148 digest
= SHA256_Data(xattrBuf
, xattrBufLen
, buf
);
150 err(1, "%s", xattrsSummary
);
154 asprintf(&xattrsSummary
, "%s:%s", name
, digest
);
156 oldSummary
= xattrsSummary
;
157 asprintf(&xattrsSummary
, "%s, %s:%s", oldSummary
, name
, digest
);
166 digest
= SHA256_Data(xattrsSummary
, strlen(xattrsSummary
) * sizeof(char), buf
);
168 err(1, "%s", xattrsSummary
);
176 char *SHA256_Path_ACL(char *path
, char *buf
)
182 struct attrlist list
= {
183 .bitmapcount
= ATTR_BIT_MAP_COUNT
,
184 .commonattr
= ATTR_CMN_RETURNED_ATTRS
| ATTR_CMN_EXTENDED_SECURITY
,
189 attribute_set_t returned_attrs
;
191 char buf
[8192]; // current acls are up to 3116 bytes, but they may increase in the future
192 } __attribute__((aligned(4), packed
));
194 struct ACLBuf aclBuf
;
196 result
= getattrlist(path
, &list
, &aclBuf
, sizeof(aclBuf
), FSOPT_NOFOLLOW
);
199 err(1, "SHA256_Path_ACL: getattrlist");
201 // if the path does not have an acl, return none
202 if ( ( ! ( aclBuf
.returned_attrs
.commonattr
& ATTR_CMN_EXTENDED_SECURITY
) )
203 || ( aclBuf
.acl
.attr_length
== 0 ) ) {
207 data
= ((char*)&aclBuf
.acl
) + aclBuf
.acl
.attr_dataoffset
;
209 digest
= SHA256_Data(data
, aclBuf
.acl
.attr_length
, buf
);
211 err(1, "SHA256_Path_ACL: SHA256_Data");
216 /* Functions for Digest_Path_* */
218 Digest_Data(CCDigestAlg algorithm
, void *data
, size_t size
, char *buf
) {
220 uint8_t digest
[32]; // SHA256 is the biggest
224 (void)os_assumes_zero(CCDigestInit(algorithm
, &ctx
));
225 (void)os_assumes_zero(CCDigestUpdate(&ctx
, data
, size
));
227 /* Finalize and convert to hex. */
228 (void)os_assumes_zero(CCDigestFinal(&ctx
, digest
));
229 length
= CCDigestOutputSize(&ctx
);
230 os_assert(length
<= sizeof(digest
));
231 for (i
= 0; i
< length
; i
++) {
232 buf
[i
+i
] = hex
[digest
[i
] >> 4];
233 buf
[i
+i
+1] = hex
[digest
[i
] & 0x0f];