|
96 | 96 | int AMDServiceConnectionReceive(ServiceConnRef con, void * data, size_t size);
|
97 | 97 | uint64_t AMDServiceConnectionReceiveMessage(ServiceConnRef con, CFPropertyListRef message, CFPropertyListFormat *format);
|
98 | 98 | uint64_t AMDServiceConnectionSendMessage(ServiceConnRef con, CFPropertyListRef message, CFPropertyListFormat format);
|
| 99 | +CFArrayRef AMDeviceCopyProvisioningProfiles(AMDeviceRef device); |
| 100 | +int AMDeviceInstallProvisioningProfile(AMDeviceRef device, void *profile); |
| 101 | +int AMDeviceRemoveProvisioningProfile(AMDeviceRef device, CFStringRef uuid); |
| 102 | +CFStringRef MISProfileGetValue(void *profile, CFStringRef key); |
| 103 | +CFDictionaryRef MISProfileCopyPayload(void *profile); |
| 104 | +void *MISProfileCreateWithData(int zero, CFDataRef data); |
| 105 | +int MISProfileWriteToFile(void *profile, CFStringRef dest_path); |
99 | 106 |
|
100 | 107 | bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, debugserver_only = false, detect_only = false, install = true, uninstall = false, no_wifi = false;
|
101 | 108 | bool faster_path_search = false;
|
|
117 | 124 | char *list_root = NULL;
|
118 | 125 | const char * custom_script_path = NULL;
|
119 | 126 | char *symbols_download_directory = NULL;
|
| 127 | +char *profile_uuid = NULL; |
| 128 | +char *profile_path = NULL; |
120 | 129 | int _timeout = 0;
|
121 | 130 | int _detectDeadlockTimeout = 0;
|
122 | 131 | bool _json_output = false;
|
@@ -1844,6 +1853,143 @@ void get_battery_level(AMDeviceRef device)
|
1844 | 1853 | check_error(AMDeviceDisconnect(device));
|
1845 | 1854 | }
|
1846 | 1855 |
|
| 1856 | +void replace_dict_date_with_absolute_time(CFMutableDictionaryRef dict, CFStringRef key) { |
| 1857 | + CFDateRef date = CFDictionaryGetValue(dict, key); |
| 1858 | + CFAbsoluteTime absolute_date = CFDateGetAbsoluteTime(date); |
| 1859 | + CFNumberRef absolute_date_ref = CFNumberCreate(NULL, kCFNumberDoubleType, &absolute_date); |
| 1860 | + CFDictionaryReplaceValue(dict, key, absolute_date_ref); |
| 1861 | + CFRelease(absolute_date_ref); |
| 1862 | +} |
| 1863 | + |
| 1864 | +void list_provisioning_profiles(AMDeviceRef device) { |
| 1865 | + connect_and_start_session(device); |
| 1866 | + CFArrayRef device_provisioning_profiles = AMDeviceCopyProvisioningProfiles(device); |
| 1867 | + |
| 1868 | + CFIndex provisioning_profiles_count = CFArrayGetCount(device_provisioning_profiles); |
| 1869 | + CFMutableArrayRef serializable_provisioning_profiles = |
| 1870 | + CFArrayCreateMutable(NULL, provisioning_profiles_count, &kCFTypeArrayCallBacks); |
| 1871 | + |
| 1872 | + for (CFIndex i = 0; i < provisioning_profiles_count; i++) { |
| 1873 | + void *device_provisioning_profile = |
| 1874 | + (void *)CFArrayGetValueAtIndex(device_provisioning_profiles, i); |
| 1875 | + CFMutableDictionaryRef serializable_provisioning_profile; |
| 1876 | + |
| 1877 | + if (verbose) { |
| 1878 | + // Verbose output; We selectively omit keys from profile. |
| 1879 | + CFDictionaryRef immutable_profile_dict = |
| 1880 | + MISProfileCopyPayload(device_provisioning_profile); |
| 1881 | + serializable_provisioning_profile = |
| 1882 | + CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, immutable_profile_dict); |
| 1883 | + CFRelease(immutable_profile_dict); |
| 1884 | + |
| 1885 | + // Remove binary values from the output since they aren't readable and add a whole lot |
| 1886 | + // of noise to the output. |
| 1887 | + CFDictionaryRemoveValue(serializable_provisioning_profile, |
| 1888 | + CFSTR("DER-Encoded-Profile")); |
| 1889 | + CFDictionaryRemoveValue(serializable_provisioning_profile, |
| 1890 | + CFSTR("DeveloperCertificates")); |
| 1891 | + } else { |
| 1892 | + // Normal output; We selectively include keys from profile. |
| 1893 | + CFStringRef keys[] = {CFSTR("Name"), CFSTR("UUID"), CFSTR("ExpirationDate")}; |
| 1894 | + CFIndex size = sizeof(keys) / sizeof(CFStringRef); |
| 1895 | + serializable_provisioning_profile = |
| 1896 | + CFDictionaryCreateMutable(kCFAllocatorDefault, size, &kCFTypeDictionaryKeyCallBacks, |
| 1897 | + &kCFTypeDictionaryValueCallBacks); |
| 1898 | + for (CFIndex i = 0; i < size; i++) { |
| 1899 | + CFStringRef key = keys[i]; |
| 1900 | + CFStringRef value = MISProfileGetValue(device_provisioning_profile, key); |
| 1901 | + CFDictionaryAddValue(serializable_provisioning_profile, key, value); |
| 1902 | + } |
| 1903 | + } |
| 1904 | + |
| 1905 | + if (_json_output) { |
| 1906 | + // JSON output can't have CFDate objects so convert dates into CFAbsoluteTime's. |
| 1907 | + replace_dict_date_with_absolute_time(serializable_provisioning_profile, |
| 1908 | + CFSTR("ExpirationDate")); |
| 1909 | + replace_dict_date_with_absolute_time(serializable_provisioning_profile, |
| 1910 | + CFSTR("CreationDate")); |
| 1911 | + } |
| 1912 | + |
| 1913 | + CFArrayAppendValue(serializable_provisioning_profiles, serializable_provisioning_profile); |
| 1914 | + CFRelease(serializable_provisioning_profile); |
| 1915 | + } |
| 1916 | + CFRelease(device_provisioning_profiles); |
| 1917 | + |
| 1918 | + if (_json_output) { |
| 1919 | + NSLogJSON(@{ |
| 1920 | + @"Event" : @"ListProvisioningProfiles", |
| 1921 | + @"Profiles" : (NSArray *)serializable_provisioning_profiles |
| 1922 | + }); |
| 1923 | + } else { |
| 1924 | + NSLogOut(@"%@", serializable_provisioning_profiles); |
| 1925 | + } |
| 1926 | + CFRelease(serializable_provisioning_profiles); |
| 1927 | +} |
| 1928 | + |
| 1929 | +void install_provisioning_profile(AMDeviceRef device) { |
| 1930 | + if (!profile_path) { |
| 1931 | + on_error(@"no path to provisioning profile specified"); |
| 1932 | + } |
| 1933 | + |
| 1934 | + size_t file_size = 0; |
| 1935 | + void *file_content = read_file_to_memory(profile_path, &file_size); |
| 1936 | + CFDataRef profile_data = CFDataCreate(NULL, file_content, file_size); |
| 1937 | + void *profile = MISProfileCreateWithData(0, profile_data); |
| 1938 | + connect_and_start_session(device); |
| 1939 | + check_error(AMDeviceInstallProvisioningProfile(device, profile)); |
| 1940 | + |
| 1941 | + free(file_content); |
| 1942 | + CFRelease(profile_data); |
| 1943 | + CFRelease(profile); |
| 1944 | +} |
| 1945 | + |
| 1946 | +void uninstall_provisioning_profile(AMDeviceRef device) { |
| 1947 | + if (!profile_uuid) { |
| 1948 | + on_error(@"no profile UUID specified via --profile-uuid"); |
| 1949 | + } |
| 1950 | + |
| 1951 | + CFStringRef uuid = CFStringCreateWithCString(NULL, profile_uuid, kCFStringEncodingUTF8); |
| 1952 | + connect_and_start_session(device); |
| 1953 | + check_error(AMDeviceRemoveProvisioningProfile(device, uuid)); |
| 1954 | + CFRelease(uuid); |
| 1955 | +} |
| 1956 | + |
| 1957 | +void download_provisioning_profile(AMDeviceRef device) { |
| 1958 | + if (!profile_uuid) { |
| 1959 | + on_error(@"no profile UUID specified via --profile-uuid"); |
| 1960 | + } else if (!profile_path) { |
| 1961 | + on_error(@"no download path specified"); |
| 1962 | + } |
| 1963 | + |
| 1964 | + connect_and_start_session(device); |
| 1965 | + CFArrayRef device_provisioning_profiles = AMDeviceCopyProvisioningProfiles(device); |
| 1966 | + CFIndex provisioning_profiles_count = CFArrayGetCount(device_provisioning_profiles); |
| 1967 | + CFStringRef uuid = CFStringCreateWithCString(NULL, profile_uuid, kCFStringEncodingUTF8); |
| 1968 | + bool found_matching_uuid = false; |
| 1969 | + |
| 1970 | + for (CFIndex i = 0; i < provisioning_profiles_count; i++) { |
| 1971 | + void *profile = (void *)CFArrayGetValueAtIndex(device_provisioning_profiles, i); |
| 1972 | + CFStringRef other_uuid = MISProfileGetValue(profile, CFSTR("UUID")); |
| 1973 | + found_matching_uuid = CFStringCompare(uuid, other_uuid, 0) == kCFCompareEqualTo; |
| 1974 | + |
| 1975 | + if (found_matching_uuid) { |
| 1976 | + NSLogVerbose(@"Writing %@ to %s", MISProfileGetValue(profile, CFSTR("Name")), |
| 1977 | + profile_path); |
| 1978 | + CFStringRef dst_path = |
| 1979 | + CFStringCreateWithCString(NULL, profile_path, kCFStringEncodingUTF8); |
| 1980 | + check_error(MISProfileWriteToFile(profile, dst_path)); |
| 1981 | + CFRelease(dst_path); |
| 1982 | + break; |
| 1983 | + } |
| 1984 | + } |
| 1985 | + |
| 1986 | + CFRelease(uuid); |
| 1987 | + CFRelease(device_provisioning_profiles); |
| 1988 | + if (!found_matching_uuid) { |
| 1989 | + on_error(@"Did not find provisioning profile with UUID %x on device", profile_uuid); |
| 1990 | + } |
| 1991 | +} |
| 1992 | + |
1847 | 1993 | void list_bundle_id(AMDeviceRef device)
|
1848 | 1994 | {
|
1849 | 1995 | connect_and_start_session(device);
|
@@ -2446,6 +2592,14 @@ void handle_device(AMDeviceRef device) {
|
2446 | 2592 | get_battery_level(device);
|
2447 | 2593 | } else if (strcmp("symbols", command) == 0) {
|
2448 | 2594 | download_device_symbols(device);
|
| 2595 | + } else if (strcmp("list_profiles", command) == 0) { |
| 2596 | + list_provisioning_profiles(device); |
| 2597 | + } else if (strcmp("install_profile", command) == 0) { |
| 2598 | + install_provisioning_profile(device); |
| 2599 | + } else if (strcmp("uninstall_profile", command) == 0) { |
| 2600 | + uninstall_provisioning_profile(device); |
| 2601 | + } else if (strcmp("download_profile", command) == 0) { |
| 2602 | + download_provisioning_profile(device); |
2449 | 2603 | }
|
2450 | 2604 | exit(0);
|
2451 | 2605 | }
|
@@ -2707,6 +2861,11 @@ void usage(const char* app) {
|
2707 | 2861 | @" --custom-script <script> path to custom python script to execute in lldb\n"
|
2708 | 2862 | @" --custom-command <command> specify additional lldb commands to execute\n"
|
2709 | 2863 | @" --faster-path-search use alternative logic to find the device support paths faster\n",
|
| 2864 | + @" -P, --list_profiles list all provisioning profiles on device\n" |
| 2865 | + @" --profile-uuid <uuid> the UUID of the provisioning profile to target, use with other profile commands\n" |
| 2866 | + @" --profile-download <path> download a provisioning profile (requires --profile-uuid)\n" |
| 2867 | + @" --profile-install <file> install a provisioning profile\n" |
| 2868 | + @" --profile-uninstall uninstall a provisioning profile (requires --profile-uuid <UUID>)\n", |
2710 | 2869 | [NSString stringWithUTF8String:app]);
|
2711 | 2870 | }
|
2712 | 2871 |
|
@@ -2764,14 +2923,19 @@ int main(int argc, char *argv[]) {
|
2764 | 2923 | { "non-recursively", no_argument, NULL, 'F'},
|
2765 | 2924 | { "key", optional_argument, NULL, 'k' },
|
2766 | 2925 | { "symbols", required_argument, NULL, 'S' },
|
| 2926 | + { "list_profiles", no_argument, NULL, 'P' }, |
2767 | 2927 | { "custom-script", required_argument, NULL, 1001},
|
2768 | 2928 | { "custom-command", required_argument, NULL, 1002},
|
2769 | 2929 | { "faster-path-search", no_argument, NULL, 1003},
|
| 2930 | + { "profile-install", required_argument, NULL, 1004}, |
| 2931 | + { "profile-uninstall", no_argument, NULL, 1005}, |
| 2932 | + { "profile-download", required_argument, NULL, 1006}, |
| 2933 | + { "profile-uuid", required_argument, NULL, 1007}, |
2770 | 2934 | { NULL, 0, NULL, 0 },
|
2771 | 2935 | };
|
2772 | 2936 | int ch;
|
2773 | 2937 |
|
2774 |
| - while ((ch = getopt_long(argc, argv, "VmcdvunrILefFD:R:X:i:b:a:t:p:1:2:o:l:w:9BWjNs:OE:CA:k:S:", longopts, NULL)) != -1) |
| 2938 | + while ((ch = getopt_long(argc, argv, "VmcdvunrILefFD:R:X:i:b:a:t:p:1:2:o:l:w:9BWjNs:OE:CA:k:S:P", longopts, NULL)) != -1) |
2775 | 2939 | {
|
2776 | 2940 | switch (ch) {
|
2777 | 2941 | case 'm':
|
@@ -2925,6 +3089,27 @@ int main(int argc, char *argv[]) {
|
2925 | 3089 | case 1003:
|
2926 | 3090 | faster_path_search = true;
|
2927 | 3091 | break;
|
| 3092 | + case 1004: |
| 3093 | + command_only = true; |
| 3094 | + command = "install_profile"; |
| 3095 | + profile_path = optarg; |
| 3096 | + break; |
| 3097 | + case 1005: |
| 3098 | + command_only = true; |
| 3099 | + command = "uninstall_profile"; |
| 3100 | + break; |
| 3101 | + case 1006: |
| 3102 | + command_only = true; |
| 3103 | + command = "download_profile"; |
| 3104 | + profile_path = optarg; |
| 3105 | + break; |
| 3106 | + case 1007: |
| 3107 | + profile_uuid = optarg; |
| 3108 | + break; |
| 3109 | + case 'P': |
| 3110 | + command_only = true; |
| 3111 | + command = "list_profiles"; |
| 3112 | + break; |
2928 | 3113 | case 'k':
|
2929 | 3114 | if (!keys) keys = [[NSMutableArray alloc] init];
|
2930 | 3115 | [keys addObject: [NSString stringWithUTF8String:optarg]];
|
|
0 commit comments