| ... | @@ -11,75 +11,81 @@ pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void { | ... | @@ -11,75 +11,81 @@ pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void { |
| 11 | cb.bytes.clearRetainingCapacity(); | 11 | cb.bytes.clearRetainingCapacity(); |
| 12 | cb.map.clearRetainingCapacity(); | 12 | cb.map.clearRetainingCapacity(); |
| 13 | | 13 | |
| 14 | const keychainPaths = [2][]const u8{ | 14 | const keychain_paths = [2][]const u8{ |
| 15 | "/System/Library/Keychains/SystemRootCertificates.keychain", | 15 | "/System/Library/Keychains/SystemRootCertificates.keychain", |
| 16 | "/Library/Keychains/System.keychain", | 16 | "/Library/Keychains/System.keychain", |
| 17 | }; | 17 | }; |
| 18 | | 18 | |
| 19 | for (keychainPaths) |keychainPath| { | 19 | for (keychain_paths) |keychain_path| { |
| 20 | const file = try fs.openFileAbsolute(keychainPath, .{}); | 20 | const bytes = std.fs.cwd().readFileAlloc(keychain_path, gpa, .limited(std.math.maxInt(u32))) catch |err| switch (err) { |
| 21 | defer file.close(); | 21 | error.StreamTooLong => return error.FileTooBig, |
| 22 | | 22 | else => |e| return e, |
| 23 | const bytes = try file.readToEndAlloc(gpa, std.math.maxInt(u32)); | 23 | }; |
| 24 | defer gpa.free(bytes); | 24 | defer gpa.free(bytes); |
| 25 | | 25 | |
| 26 | var reader: std.Io.Reader = .fixed(bytes); | 26 | var reader: std.Io.Reader = .fixed(bytes); |
| | 27 | scanReader(cb, gpa, &reader) catch |err| switch (err) { |
| | 28 | error.ReadFailed => unreachable, // prebuffered |
| | 29 | else => |e| return e, |
| | 30 | }; |
| | 31 | } |
| 27 | | 32 | |
| 28 | const db_header = try reader.takeStruct(ApplDbHeader, .big); | 33 | cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); |
| 29 | assert(mem.eql(u8, &db_header.signature, "kych")); | 34 | } |
| 30 | | 35 | |
| 31 | reader.seek = db_header.schema_offset; | 36 | fn scanReader(cb: *Bundle, gpa: Allocator, reader: *std.Io.Reader) !void { |
| | 37 | const db_header = try reader.takeStruct(ApplDbHeader, .big); |
| | 38 | assert(mem.eql(u8, &db_header.signature, "kych")); |
| 32 | | 39 | |
| 33 | const db_schema = try reader.takeStruct(ApplDbSchema, .big); | 40 | reader.seek = db_header.schema_offset; |
| 34 | | 41 | |
| 35 | var table_list = try gpa.alloc(u32, db_schema.table_count); | 42 | const db_schema = try reader.takeStruct(ApplDbSchema, .big); |
| 36 | defer gpa.free(table_list); | | |
| 37 | | 43 | |
| 38 | var table_idx: u32 = 0; | 44 | var table_list = try gpa.alloc(u32, db_schema.table_count); |
| 39 | while (table_idx < table_list.len) : (table_idx += 1) { | 45 | defer gpa.free(table_list); |
| 40 | table_list[table_idx] = try reader.takeInt(u32, .big); | | |
| 41 | } | | |
| 42 | | 46 | |
| 43 | const now_sec = std.time.timestamp(); | 47 | var table_idx: u32 = 0; |
| | 48 | while (table_idx < table_list.len) : (table_idx += 1) { |
| | 49 | table_list[table_idx] = try reader.takeInt(u32, .big); |
| | 50 | } |
| 44 | | 51 | |
| 45 | for (table_list) |table_offset| { | 52 | const now_sec = std.time.timestamp(); |
| 46 | reader.seek = db_header.schema_offset + table_offset; | | |
| 47 | | 53 | |
| 48 | const table_header = try reader.takeStruct(TableHeader, .big); | 54 | for (table_list) |table_offset| { |
| | 55 | reader.seek = db_header.schema_offset + table_offset; |
| 49 | | 56 | |
| 50 | if (@as(std.c.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) { | 57 | const table_header = try reader.takeStruct(TableHeader, .big); |
| 51 | continue; | | |
| 52 | } | | |
| 53 | | 58 | |
| 54 | var record_list = try gpa.alloc(u32, table_header.record_count); | 59 | if (@as(std.c.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) { |
| 55 | defer gpa.free(record_list); | 60 | continue; |
| | 61 | } |
| | 62 | |
| | 63 | var record_list = try gpa.alloc(u32, table_header.record_count); |
| | 64 | defer gpa.free(record_list); |
| 56 | | 65 | |
| 57 | var record_idx: u32 = 0; | 66 | var record_idx: u32 = 0; |
| 58 | while (record_idx < record_list.len) : (record_idx += 1) { | 67 | while (record_idx < record_list.len) : (record_idx += 1) { |
| 59 | record_list[record_idx] = try reader.takeInt(u32, .big); | 68 | record_list[record_idx] = try reader.takeInt(u32, .big); |
| 60 | } | 69 | } |
| 61 | | 70 | |
| 62 | for (record_list) |record_offset| { | 71 | for (record_list) |record_offset| { |
| 63 | // An offset of zero means that the record is not present. | 72 | // An offset of zero means that the record is not present. |
| 64 | // An offset that is not 4-byte-aligned is invalid. | 73 | // An offset that is not 4-byte-aligned is invalid. |
| 65 | if (record_offset == 0 or record_offset % 4 != 0) continue; | 74 | if (record_offset == 0 or record_offset % 4 != 0) continue; |
| 66 | | 75 | |
| 67 | reader.seek = db_header.schema_offset + table_offset + record_offset; | 76 | reader.seek = db_header.schema_offset + table_offset + record_offset; |
| 68 | | 77 | |
| 69 | const cert_header = try reader.takeStruct(X509CertHeader, .big); | 78 | const cert_header = try reader.takeStruct(X509CertHeader, .big); |
| 70 | | 79 | |
| 71 | if (cert_header.cert_size == 0) continue; | 80 | if (cert_header.cert_size == 0) continue; |
| 72 | | 81 | |
| 73 | const cert_start = @as(u32, @intCast(cb.bytes.items.len)); | 82 | const cert_start: u32 = @intCast(cb.bytes.items.len); |
| 74 | const dest_buf = try cb.bytes.addManyAsSlice(gpa, cert_header.cert_size); | 83 | const dest_buf = try cb.bytes.addManyAsSlice(gpa, cert_header.cert_size); |
| 75 | try reader.readSliceAll(dest_buf); | 84 | try reader.readSliceAll(dest_buf); |
| 76 | | 85 | |
| 77 | try cb.parseCert(gpa, cert_start, now_sec); | 86 | try cb.parseCert(gpa, cert_start, now_sec); |
| 78 | } | | |
| 79 | } | 87 | } |
| 80 | } | 88 | } |
| 81 | | | |
| 82 | cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); | | |
| 83 | } | 89 | } |
| 84 | | 90 | |
| 85 | const ApplDbHeader = extern struct { | 91 | const ApplDbHeader = extern struct { |