diff options
Diffstat (limited to 'src/mobile_image_mounter.c')
-rw-r--r-- | src/mobile_image_mounter.c | 514 |
1 files changed, 416 insertions, 98 deletions
diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c index 367bee0..6df50c4 100644 --- a/src/mobile_image_mounter.c +++ b/src/mobile_image_mounter.c | |||
@@ -2,23 +2,26 @@ | |||
2 | * mobile_image_mounter.c | 2 | * mobile_image_mounter.c |
3 | * com.apple.mobile.mobile_image_mounter service implementation. | 3 | * com.apple.mobile.mobile_image_mounter service implementation. |
4 | * | 4 | * |
5 | * Copyright (c) 2010 Nikias Bassen, All Rights Reserved. | 5 | * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved. |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or | 7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public | 8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | 9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. | 10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * This library is distributed in the hope that it will be useful, | 12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. | 15 | * Lesser General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU Lesser General Public | 17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, write to the Free Software | 18 | * License along with this library; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #ifdef HAVE_CONFIG_H | ||
23 | #include <config.h> | ||
24 | #endif | ||
22 | #include <string.h> | 25 | #include <string.h> |
23 | #include <stdlib.h> | 26 | #include <stdlib.h> |
24 | #include <unistd.h> | 27 | #include <unistd.h> |
@@ -26,7 +29,7 @@ | |||
26 | 29 | ||
27 | #include "mobile_image_mounter.h" | 30 | #include "mobile_image_mounter.h" |
28 | #include "property_list_service.h" | 31 | #include "property_list_service.h" |
29 | #include "debug.h" | 32 | #include "common/debug.h" |
30 | 33 | ||
31 | /** | 34 | /** |
32 | * Locks a mobile_image_mounter client, used for thread safety. | 35 | * Locks a mobile_image_mounter client, used for thread safety. |
@@ -35,17 +38,17 @@ | |||
35 | */ | 38 | */ |
36 | static void mobile_image_mounter_lock(mobile_image_mounter_client_t client) | 39 | static void mobile_image_mounter_lock(mobile_image_mounter_client_t client) |
37 | { | 40 | { |
38 | g_mutex_lock(client->mutex); | 41 | mutex_lock(&client->mutex); |
39 | } | 42 | } |
40 | 43 | ||
41 | /** | 44 | /** |
42 | * Unlocks a mobile_image_mounter client, used for thread safety. | 45 | * Unlocks a mobile_image_mounter client, used for thread safety. |
43 | * | 46 | * |
44 | * @param client mobile_image_mounter client to unlock | 47 | * @param client mobile_image_mounter client to unlock |
45 | */ | 48 | */ |
46 | static void mobile_image_mounter_unlock(mobile_image_mounter_client_t client) | 49 | static void mobile_image_mounter_unlock(mobile_image_mounter_client_t client) |
47 | { | 50 | { |
48 | g_mutex_unlock(client->mutex); | 51 | mutex_unlock(&client->mutex); |
49 | } | 52 | } |
50 | 53 | ||
51 | /** | 54 | /** |
@@ -75,51 +78,30 @@ static mobile_image_mounter_error_t mobile_image_mounter_error(property_list_ser | |||
75 | return MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; | 78 | return MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; |
76 | } | 79 | } |
77 | 80 | ||
78 | /** | 81 | mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client) |
79 | * Connects to the mobile_image_mounter service on the specified device. | ||
80 | * | ||
81 | * @param device The device to connect to. | ||
82 | * @param port Destination port (usually given by lockdownd_start_service). | ||
83 | * @param client Pointer that will be set to a newly allocated | ||
84 | * mobile_image_mounter_client_t upon successful return. | ||
85 | * | ||
86 | * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, | ||
87 | * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if device is NULL, | ||
88 | * or MOBILE_IMAGE_MOUNTER_E_CONN_FAILED if the connection to the | ||
89 | * device could not be established. | ||
90 | */ | ||
91 | mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, uint16_t port, mobile_image_mounter_client_t *client) | ||
92 | { | 82 | { |
93 | /* makes sure thread environment is available */ | ||
94 | if (!g_thread_supported()) | ||
95 | g_thread_init(NULL); | ||
96 | |||
97 | if (!device) | ||
98 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
99 | |||
100 | property_list_service_client_t plistclient = NULL; | 83 | property_list_service_client_t plistclient = NULL; |
101 | if (property_list_service_client_new(device, port, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { | 84 | mobile_image_mounter_error_t err = mobile_image_mounter_error(property_list_service_client_new(device, service, &plistclient)); |
102 | return MOBILE_IMAGE_MOUNTER_E_CONN_FAILED; | 85 | if (err != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { |
86 | return err; | ||
103 | } | 87 | } |
104 | 88 | ||
105 | mobile_image_mounter_client_t client_loc = (mobile_image_mounter_client_t) malloc(sizeof(struct mobile_image_mounter_client_private)); | 89 | mobile_image_mounter_client_t client_loc = (mobile_image_mounter_client_t) malloc(sizeof(struct mobile_image_mounter_client_private)); |
106 | client_loc->parent = plistclient; | 90 | client_loc->parent = plistclient; |
107 | 91 | ||
108 | client_loc->mutex = g_mutex_new(); | 92 | mutex_init(&client_loc->mutex); |
109 | 93 | ||
110 | *client = client_loc; | 94 | *client = client_loc; |
111 | return MOBILE_IMAGE_MOUNTER_E_SUCCESS; | 95 | return MOBILE_IMAGE_MOUNTER_E_SUCCESS; |
112 | } | 96 | } |
113 | 97 | ||
114 | /** | 98 | mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t * client, const char* label) |
115 | * Disconnects a mobile_image_mounter client from the device and frees up the | 99 | { |
116 | * mobile_image_mounter client data. | 100 | mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; |
117 | * | 101 | service_client_factory_start_service(device, MOBILE_IMAGE_MOUNTER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobile_image_mounter_new), &err); |
118 | * @param client The mobile_image_mounter client to disconnect and free. | 102 | return err; |
119 | * | 103 | } |
120 | * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, | 104 | |
121 | * or MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is NULL. | ||
122 | */ | ||
123 | mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) | 105 | mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) |
124 | { | 106 | { |
125 | if (!client) | 107 | if (!client) |
@@ -127,27 +109,12 @@ mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_clie | |||
127 | 109 | ||
128 | property_list_service_client_free(client->parent); | 110 | property_list_service_client_free(client->parent); |
129 | client->parent = NULL; | 111 | client->parent = NULL; |
130 | if (client->mutex) { | 112 | mutex_destroy(&client->mutex); |
131 | g_mutex_free(client->mutex); | ||
132 | } | ||
133 | free(client); | 113 | free(client); |
134 | 114 | ||
135 | return MOBILE_IMAGE_MOUNTER_E_SUCCESS; | 115 | return MOBILE_IMAGE_MOUNTER_E_SUCCESS; |
136 | } | 116 | } |
137 | 117 | ||
138 | /** | ||
139 | * Tells if the image of ImageType is already mounted. | ||
140 | * | ||
141 | * @param client The client use | ||
142 | * @param image_type The type of the image to look up | ||
143 | * @param result Pointer to a plist that will receive the result of the | ||
144 | * operation. | ||
145 | * | ||
146 | * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the | ||
147 | * operation has failed. Check the resulting plist for further information. | ||
148 | * | ||
149 | * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, or an error code on error | ||
150 | */ | ||
151 | mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) | 118 | mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result) |
152 | { | 119 | { |
153 | if (!client || !image_type || !result) { | 120 | if (!client || !image_type || !result) { |
@@ -156,8 +123,8 @@ mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_moun | |||
156 | mobile_image_mounter_lock(client); | 123 | mobile_image_mounter_lock(client); |
157 | 124 | ||
158 | plist_t dict = plist_new_dict(); | 125 | plist_t dict = plist_new_dict(); |
159 | plist_dict_insert_item(dict,"Command", plist_new_string("LookupImage")); | 126 | plist_dict_set_item(dict,"Command", plist_new_string("LookupImage")); |
160 | plist_dict_insert_item(dict,"ImageType", plist_new_string(image_type)); | 127 | plist_dict_set_item(dict,"ImageType", plist_new_string(image_type)); |
161 | 128 | ||
162 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | 129 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); |
163 | plist_free(dict); | 130 | plist_free(dict); |
@@ -177,39 +144,139 @@ leave_unlock: | |||
177 | return res; | 144 | return res; |
178 | } | 145 | } |
179 | 146 | ||
180 | /** | 147 | static mobile_image_mounter_error_t process_result(plist_t result, const char *expected_status) |
181 | * Mounts an image on the device. | 148 | { |
182 | * | 149 | mobile_image_mounter_error_t res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; |
183 | * @param client The connected mobile_image_mounter client. | 150 | char* strval = NULL; |
184 | * @param image_path The absolute path of the image to mount. The image must | 151 | plist_t node; |
185 | * be present before calling this function. | 152 | |
186 | * @param image_signature Pointer to a buffer holding the images' signature | 153 | node = plist_dict_get_item(result, "Error"); |
187 | * @param signature_length Length of the signature image_signature points to | 154 | if (node && plist_get_node_type(node) == PLIST_STRING) { |
188 | * @param image_type Type of image to mount | 155 | plist_get_string_val(node, &strval); |
189 | * @param result Pointer to a plist that will receive the result of the | 156 | } |
190 | * operation. | 157 | if (strval) { |
191 | * | 158 | if (!strcmp(strval, "DeviceLocked")) { |
192 | * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the | 159 | debug_info("Device is locked, can't mount"); |
193 | * operation has failed. Check the resulting plist for further information. | 160 | res = MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED; |
194 | * Note that there is no unmounting function. The mount persists until the | 161 | } else { |
195 | * device is rebooted. | 162 | debug_info("Unhandled error '%s' received", strval); |
196 | * | 163 | } |
197 | * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, | 164 | free(strval); |
198 | * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if on ore more parameters are | 165 | return res; |
199 | * invalid, or another error code otherwise. | 166 | } |
200 | */ | 167 | |
201 | mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *image_signature, uint16_t signature_length, const char *image_type, plist_t *result) | 168 | node = plist_dict_get_item(result, "Status"); |
169 | if (node && plist_get_node_type(node) == PLIST_STRING) { | ||
170 | plist_get_string_val(node, &strval); | ||
171 | } | ||
172 | if (!strval) { | ||
173 | debug_info("Error: Unexpected response received!"); | ||
174 | } else if (strcmp(strval, expected_status) == 0) { | ||
175 | res = MOBILE_IMAGE_MOUNTER_E_SUCCESS; | ||
176 | } else { | ||
177 | debug_info("Error: didn't get %s but %s", expected_status, strval); | ||
178 | } | ||
179 | free(strval); | ||
180 | |||
181 | return res; | ||
182 | } | ||
183 | |||
184 | mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, const unsigned char *signature, unsigned int signature_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata) | ||
185 | { | ||
186 | if (!client || !image_type || (image_size == 0) || !upload_cb) { | ||
187 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
188 | } | ||
189 | mobile_image_mounter_lock(client); | ||
190 | plist_t result = NULL; | ||
191 | |||
192 | plist_t dict = plist_new_dict(); | ||
193 | plist_dict_set_item(dict, "Command", plist_new_string("ReceiveBytes")); | ||
194 | if (signature && signature_size != 0) | ||
195 | plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); | ||
196 | plist_dict_set_item(dict, "ImageSize", plist_new_uint(image_size)); | ||
197 | plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); | ||
198 | |||
199 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
200 | plist_free(dict); | ||
201 | |||
202 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
203 | debug_info("Error sending XML plist to device!"); | ||
204 | goto leave_unlock; | ||
205 | } | ||
206 | |||
207 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
208 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
209 | debug_info("Error receiving response from device!"); | ||
210 | goto leave_unlock; | ||
211 | } | ||
212 | res = process_result(result, "ReceiveBytesAck"); | ||
213 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
214 | goto leave_unlock; | ||
215 | } | ||
216 | |||
217 | size_t tx = 0; | ||
218 | size_t bufsize = 65536; | ||
219 | unsigned char *buf = (unsigned char*)malloc(bufsize); | ||
220 | if (!buf) { | ||
221 | debug_info("Out of memory"); | ||
222 | res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; | ||
223 | goto leave_unlock; | ||
224 | } | ||
225 | debug_info("uploading image (%d bytes)", (int)image_size); | ||
226 | while (tx < image_size) { | ||
227 | size_t remaining = image_size - tx; | ||
228 | size_t amount = (remaining < bufsize) ? remaining : bufsize; | ||
229 | ssize_t r = upload_cb(buf, amount, userdata); | ||
230 | if (r < 0) { | ||
231 | debug_info("upload_cb returned %d", (int)r); | ||
232 | break; | ||
233 | } | ||
234 | uint32_t sent = 0; | ||
235 | if (service_send(client->parent->parent, (const char*)buf, (uint32_t)r, &sent) != SERVICE_E_SUCCESS) { | ||
236 | debug_info("service_send failed"); | ||
237 | break; | ||
238 | } | ||
239 | tx += r; | ||
240 | } | ||
241 | free(buf); | ||
242 | if (tx < image_size) { | ||
243 | debug_info("Error: failed to upload image"); | ||
244 | res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; | ||
245 | goto leave_unlock; | ||
246 | } | ||
247 | debug_info("image uploaded"); | ||
248 | |||
249 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
250 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
251 | debug_info("Error receiving response from device!"); | ||
252 | goto leave_unlock; | ||
253 | } | ||
254 | res = process_result(result, "Complete"); | ||
255 | |||
256 | leave_unlock: | ||
257 | mobile_image_mounter_unlock(client); | ||
258 | if (result) | ||
259 | plist_free(result); | ||
260 | return res; | ||
261 | |||
262 | } | ||
263 | |||
264 | mobile_image_mounter_error_t mobile_image_mounter_mount_image_with_options(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t options, plist_t *result) | ||
202 | { | 265 | { |
203 | if (!client || !image_path || !image_signature || (signature_length == 0) || !image_type || !result) { | 266 | if (!client || !image_path || !image_type || !result) { |
204 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | 267 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; |
205 | } | 268 | } |
206 | mobile_image_mounter_lock(client); | 269 | mobile_image_mounter_lock(client); |
207 | 270 | ||
208 | plist_t dict = plist_new_dict(); | 271 | plist_t dict = plist_new_dict(); |
209 | plist_dict_insert_item(dict, "Command", plist_new_string("MountImage")); | 272 | plist_dict_set_item(dict, "Command", plist_new_string("MountImage")); |
210 | plist_dict_insert_item(dict, "ImagePath", plist_new_string(image_path)); | 273 | plist_dict_set_item(dict, "ImagePath", plist_new_string(image_path)); |
211 | plist_dict_insert_item(dict, "ImageSignature", plist_new_data(image_signature, signature_length)); | 274 | if (signature && signature_size != 0) |
212 | plist_dict_insert_item(dict, "ImageType", plist_new_string(image_type)); | 275 | plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); |
276 | plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); | ||
277 | if (PLIST_IS_DICT(options)) { | ||
278 | plist_dict_merge(&dict, options); | ||
279 | } | ||
213 | 280 | ||
214 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | 281 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); |
215 | plist_free(dict); | 282 | plist_free(dict); |
@@ -229,17 +296,56 @@ leave_unlock: | |||
229 | return res; | 296 | return res; |
230 | } | 297 | } |
231 | 298 | ||
232 | /** | 299 | mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const unsigned char *signature, unsigned int signature_size, const char *image_type, plist_t *result) |
233 | * Hangs up the connection to the mobile_image_mounter service. | 300 | { |
234 | * This functions has to be called before freeing up a mobile_image_mounter | 301 | return mobile_image_mounter_mount_image_with_options(client, image_path, signature, signature_size, image_type, NULL, result); |
235 | * instance. If not, errors appear in the device's syslog. | 302 | } |
236 | * | 303 | |
237 | * @param client The client to hang up | 304 | mobile_image_mounter_error_t mobile_image_mounter_unmount_image(mobile_image_mounter_client_t client, const char *mount_path) |
238 | * | 305 | { |
239 | * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, | 306 | if (!client || !mount_path) { |
240 | * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is invalid, | 307 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; |
241 | * or another error code otherwise. | 308 | } |
242 | */ | 309 | mobile_image_mounter_lock(client); |
310 | |||
311 | plist_t dict = plist_new_dict(); | ||
312 | plist_dict_set_item(dict, "Command", plist_new_string("UnmountImage")); | ||
313 | plist_dict_set_item(dict, "MountPath", plist_new_string(mount_path)); | ||
314 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
315 | plist_free(dict); | ||
316 | |||
317 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
318 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
319 | goto leave_unlock; | ||
320 | } | ||
321 | |||
322 | plist_t result = NULL; | ||
323 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
324 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
325 | debug_info("%s: Error receiving response from device!", __func__); | ||
326 | } else { | ||
327 | plist_t p_error = plist_dict_get_item(result, "Error"); | ||
328 | if (p_error) { | ||
329 | plist_t p_detailed = plist_dict_get_item(result, "DetailedError"); | ||
330 | const char* detailederr = (p_detailed) ? plist_get_string_ptr(p_detailed, NULL) : ""; | ||
331 | const char* errstr = plist_get_string_ptr(p_error, NULL); | ||
332 | if (errstr && !strcmp(errstr, "UnknownCommand")) { | ||
333 | res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; | ||
334 | } else if (errstr && !strcmp(errstr, "DeviceLocked")) { | ||
335 | res = MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED; | ||
336 | } else if (strstr(detailederr, "no matching entry")) { | ||
337 | res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; | ||
338 | } else { | ||
339 | res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | leave_unlock: | ||
345 | mobile_image_mounter_unlock(client); | ||
346 | return res; | ||
347 | } | ||
348 | |||
243 | mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) | 349 | mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) |
244 | { | 350 | { |
245 | if (!client) { | 351 | if (!client) { |
@@ -248,7 +354,7 @@ mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_cl | |||
248 | mobile_image_mounter_lock(client); | 354 | mobile_image_mounter_lock(client); |
249 | 355 | ||
250 | plist_t dict = plist_new_dict(); | 356 | plist_t dict = plist_new_dict(); |
251 | plist_dict_insert_item(dict, "Command", plist_new_string("Hangup")); | 357 | plist_dict_set_item(dict, "Command", plist_new_string("Hangup")); |
252 | 358 | ||
253 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | 359 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); |
254 | plist_free(dict); | 360 | plist_free(dict); |
@@ -272,3 +378,215 @@ leave_unlock: | |||
272 | mobile_image_mounter_unlock(client); | 378 | mobile_image_mounter_unlock(client); |
273 | return res; | 379 | return res; |
274 | } | 380 | } |
381 | |||
382 | mobile_image_mounter_error_t mobile_image_mounter_query_developer_mode_status(mobile_image_mounter_client_t client, plist_t *result) | ||
383 | { | ||
384 | if (!client || !result) { | ||
385 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
386 | } | ||
387 | mobile_image_mounter_lock(client); | ||
388 | |||
389 | plist_t dict = plist_new_dict(); | ||
390 | plist_dict_set_item(dict, "Command", plist_new_string("QueryDeveloperModeStatus")); | ||
391 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
392 | plist_free(dict); | ||
393 | |||
394 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
395 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
396 | goto leave_unlock; | ||
397 | } | ||
398 | |||
399 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, result)); | ||
400 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
401 | debug_info("%s: Error receiving response from device!", __func__); | ||
402 | } | ||
403 | |||
404 | leave_unlock: | ||
405 | mobile_image_mounter_unlock(client); | ||
406 | return res; | ||
407 | } | ||
408 | |||
409 | mobile_image_mounter_error_t mobile_image_mounter_query_nonce(mobile_image_mounter_client_t client, const char* image_type, unsigned char** nonce, unsigned int* nonce_size) | ||
410 | { | ||
411 | if (!client || !nonce || !nonce_size) { | ||
412 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
413 | } | ||
414 | mobile_image_mounter_lock(client); | ||
415 | |||
416 | plist_t dict = plist_new_dict(); | ||
417 | plist_dict_set_item(dict, "Command", plist_new_string("QueryNonce")); | ||
418 | if (image_type) { | ||
419 | plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); | ||
420 | } | ||
421 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
422 | plist_free(dict); | ||
423 | |||
424 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
425 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
426 | goto leave_unlock; | ||
427 | } | ||
428 | |||
429 | plist_t result = NULL; | ||
430 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
431 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
432 | debug_info("%s: Error receiving response from device!", __func__); | ||
433 | } else { | ||
434 | plist_t p_nonce = plist_dict_get_item(result, "PersonalizationNonce"); | ||
435 | if (!p_nonce) { | ||
436 | res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; | ||
437 | } else { | ||
438 | uint64_t nonce_size_ = 0; | ||
439 | plist_get_data_val(p_nonce, (char**)nonce, &nonce_size_); | ||
440 | if (*nonce) { | ||
441 | *nonce_size = (unsigned int)nonce_size_; | ||
442 | } else { | ||
443 | res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | plist_free(result); | ||
448 | |||
449 | leave_unlock: | ||
450 | mobile_image_mounter_unlock(client); | ||
451 | return res; | ||
452 | } | ||
453 | |||
454 | mobile_image_mounter_error_t mobile_image_mounter_query_personalization_identifiers(mobile_image_mounter_client_t client, const char* image_type, plist_t *result) | ||
455 | { | ||
456 | if (!client || !result) { | ||
457 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
458 | } | ||
459 | mobile_image_mounter_lock(client); | ||
460 | |||
461 | plist_t dict = plist_new_dict(); | ||
462 | plist_dict_set_item(dict, "Command", plist_new_string("QueryPersonalizationIdentifiers")); | ||
463 | if (image_type) { | ||
464 | plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); | ||
465 | } | ||
466 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
467 | plist_free(dict); | ||
468 | |||
469 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
470 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
471 | goto leave_unlock; | ||
472 | } | ||
473 | |||
474 | plist_t _result = NULL; | ||
475 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &_result)); | ||
476 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
477 | debug_info("%s: Error receiving response from device!", __func__); | ||
478 | } | ||
479 | *result = plist_copy(plist_dict_get_item(_result, "PersonalizationIdentifiers")); | ||
480 | if (!*result) { | ||
481 | debug_info("%s: Response did not contain PersonalizationIdentifiers!", __func__); | ||
482 | res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; | ||
483 | } | ||
484 | |||
485 | leave_unlock: | ||
486 | mobile_image_mounter_unlock(client); | ||
487 | return res; | ||
488 | } | ||
489 | |||
490 | mobile_image_mounter_error_t mobile_image_mounter_query_personalization_manifest(mobile_image_mounter_client_t client, const char* image_type, const unsigned char* signature, unsigned int signature_size, unsigned char** manifest, unsigned int* manifest_size) | ||
491 | { | ||
492 | if (!client || !image_type || !signature || !signature_size || !manifest || !manifest_size) { | ||
493 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
494 | } | ||
495 | mobile_image_mounter_lock(client); | ||
496 | |||
497 | plist_t dict = plist_new_dict(); | ||
498 | plist_dict_set_item(dict, "Command", plist_new_string("QueryPersonalizationManifest")); | ||
499 | plist_dict_set_item(dict, "PersonalizedImageType", plist_new_string(image_type)); | ||
500 | plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); | ||
501 | plist_dict_set_item(dict, "ImageSignature", plist_new_data((char*)signature, signature_size)); | ||
502 | |||
503 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
504 | plist_free(dict); | ||
505 | |||
506 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
507 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
508 | goto leave_unlock; | ||
509 | } | ||
510 | |||
511 | plist_t result = NULL; | ||
512 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
513 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
514 | debug_info("%s: Error receiving response from device!", __func__); | ||
515 | } else { | ||
516 | plist_t p_manifest = plist_dict_get_item(result, "ImageSignature"); | ||
517 | if (!p_manifest) { | ||
518 | res = MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED; | ||
519 | } else { | ||
520 | uint64_t manifest_size_ = 0; | ||
521 | plist_get_data_val(p_manifest, (char**)manifest, &manifest_size_); | ||
522 | if (*manifest) { | ||
523 | *manifest_size = (unsigned int)manifest_size_; | ||
524 | } else { | ||
525 | res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | plist_free(result); | ||
530 | |||
531 | leave_unlock: | ||
532 | mobile_image_mounter_unlock(client); | ||
533 | return res; | ||
534 | } | ||
535 | |||
536 | mobile_image_mounter_error_t mobile_image_mounter_roll_personalization_nonce(mobile_image_mounter_client_t client) | ||
537 | { | ||
538 | if (!client) { | ||
539 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
540 | } | ||
541 | mobile_image_mounter_lock(client); | ||
542 | |||
543 | plist_t dict = plist_new_dict(); | ||
544 | plist_dict_set_item(dict, "Command", plist_new_string("RollPersonalizationNonce")); | ||
545 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
546 | plist_free(dict); | ||
547 | |||
548 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
549 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
550 | goto leave_unlock; | ||
551 | } | ||
552 | |||
553 | plist_t result = NULL; | ||
554 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
555 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
556 | debug_info("%s: Error receiving response from device!", __func__); | ||
557 | } | ||
558 | plist_free(result); | ||
559 | |||
560 | leave_unlock: | ||
561 | mobile_image_mounter_unlock(client); | ||
562 | return res; | ||
563 | } | ||
564 | |||
565 | mobile_image_mounter_error_t mobile_image_mounter_roll_cryptex_nonce(mobile_image_mounter_client_t client) | ||
566 | { | ||
567 | if (!client) { | ||
568 | return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; | ||
569 | } | ||
570 | mobile_image_mounter_lock(client); | ||
571 | |||
572 | plist_t dict = plist_new_dict(); | ||
573 | plist_dict_set_item(dict, "Command", plist_new_string("RollCryptexNonce")); | ||
574 | mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); | ||
575 | plist_free(dict); | ||
576 | |||
577 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
578 | debug_info("%s: Error sending XML plist to device!", __func__); | ||
579 | goto leave_unlock; | ||
580 | } | ||
581 | |||
582 | plist_t result = NULL; | ||
583 | res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result)); | ||
584 | if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { | ||
585 | debug_info("%s: Error receiving response from device!", __func__); | ||
586 | } | ||
587 | plist_free(result); | ||
588 | |||
589 | leave_unlock: | ||
590 | mobile_image_mounter_unlock(client); | ||
591 | return res; | ||
592 | } | ||