summaryrefslogtreecommitdiffstats
path: root/src/restore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/restore.c')
-rw-r--r--src/restore.c290
1 files changed, 128 insertions, 162 deletions
diff --git a/src/restore.c b/src/restore.c
index fd23d85..d13a28a 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -19,17 +19,18 @@
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#include <arpa/inet.h> 22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
23#include <errno.h> 25#include <errno.h>
24#include <string.h> 26#include <string.h>
25#include <stdlib.h> 27#include <stdlib.h>
26#include <glib.h>
27#include <plist/plist.h> 28#include <plist/plist.h>
28 29
29#include "property_list_service.h" 30#include "property_list_service.h"
30#include "restore.h" 31#include "restore.h"
31#include "idevice.h" 32#include "idevice.h"
32#include "debug.h" 33#include "common/debug.h"
33 34
34#define RESULT_SUCCESS 0 35#define RESULT_SUCCESS 0
35#define RESULT_FAILURE 1 36#define RESULT_FAILURE 1
@@ -43,7 +44,7 @@
43 * 44 *
44 * @return RESULT_SUCCESS when the result is 'Success', 45 * @return RESULT_SUCCESS when the result is 'Success',
45 * RESULT_FAILURE when the result is 'Failure', 46 * RESULT_FAILURE when the result is 'Failure',
46 * or a negative value if an error occured during evaluation. 47 * or a negative value if an error occurred during evaluation.
47 */ 48 */
48static int restored_check_result(plist_t dict) 49static int restored_check_result(plist_t dict)
49{ 50{
@@ -87,40 +88,49 @@ static void plist_dict_add_label(plist_t plist, const char *label)
87{ 88{
88 if (plist && label) { 89 if (plist && label) {
89 if (plist_get_node_type(plist) == PLIST_DICT) 90 if (plist_get_node_type(plist) == PLIST_DICT)
90 plist_dict_insert_item(plist, "Label", plist_new_string(label)); 91 plist_dict_set_item(plist, "Label", plist_new_string(label));
91 } 92 }
92} 93}
93 94
94/** 95static restored_error_t restored_error(property_list_service_error_t err)
95 * Closes the restored client session if one is running and frees up the 96{
96 * restored_client struct. 97 switch (err) {
97 * 98 case PROPERTY_LIST_SERVICE_E_SUCCESS:
98 * @param client The restore client 99 return RESTORE_E_SUCCESS;
99 * 100 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
100 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL 101 return RESTORE_E_INVALID_ARG;
101 */ 102 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
103 return RESTORE_E_PLIST_ERROR;
104 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
105 return RESTORE_E_MUX_ERROR;
106 case PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT:
107 return RESTORE_E_RECEIVE_TIMEOUT;
108 default:
109 break;
110 }
111 return RESTORE_E_UNKNOWN_ERROR;
112}
113
102restored_error_t restored_client_free(restored_client_t client) 114restored_error_t restored_client_free(restored_client_t client)
103{ 115{
104 if (!client) 116 if (!client)
105 return RESTORE_E_INVALID_ARG; 117 return RESTORE_E_INVALID_ARG;
106 118
107 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; 119 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
108 120
109 if (client->parent) { 121 if (client->parent) {
110 restored_goodbye(client); 122 restored_goodbye(client);
111 123
112 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) { 124 ret = restored_error(property_list_service_client_free(client->parent));
113 ret = RESTORE_E_SUCCESS;
114 }
115 } 125 }
116 126
117 if (client->uuid) { 127 if (client->udid) {
118 free(client->uuid); 128 free(client->udid);
119 } 129 }
120 if (client->label) { 130 if (client->label) {
121 free(client->label); 131 free(client->label);
122 } 132 }
123 133
124 if (client->info) { 134 if (client->info) {
125 plist_free(client->info); 135 plist_free(client->info);
126 } 136 }
@@ -129,13 +139,6 @@ restored_error_t restored_client_free(restored_client_t client)
129 return ret; 139 return ret;
130} 140}
131 141
132/**
133 * Sets the label to send for requests to restored.
134 *
135 * @param client The restore client
136 * @param label The label to set or NULL to disable sending a label
137 *
138 */
139void restored_client_set_label(restored_client_t client, const char *label) 142void restored_client_set_label(restored_client_t client, const char *label)
140{ 143{
141 if (client) { 144 if (client) {
@@ -146,71 +149,22 @@ void restored_client_set_label(restored_client_t client, const char *label)
146 } 149 }
147} 150}
148 151
149/**
150 * Receives a plist from restored.
151 *
152 * @param client The restored client
153 * @param plist The plist to store the received data
154 *
155 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
156 * plist is NULL
157 */
158restored_error_t restored_receive(restored_client_t client, plist_t *plist) 152restored_error_t restored_receive(restored_client_t client, plist_t *plist)
159{ 153{
160 if (!client || !plist || (plist && *plist)) 154 if (!client || !plist || (plist && *plist))
161 return RESTORE_E_INVALID_ARG; 155 return RESTORE_E_INVALID_ARG;
162
163 restored_error_t ret = RESTORE_E_SUCCESS;
164 property_list_service_error_t err;
165
166 err = property_list_service_receive_plist(client->parent, plist);
167 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
168 ret = RESTORE_E_UNKNOWN_ERROR;
169 }
170 156
171 if (!*plist) 157 return restored_error(property_list_service_receive_plist(client->parent, plist));
172 ret = RESTORE_E_PLIST_ERROR;
173
174 return ret;
175} 158}
176 159
177/**
178 * Sends a plist to restored.
179 *
180 * @note This function is low-level and should only be used if you need to send
181 * a new type of message.
182 *
183 * @param client The restored client
184 * @param plist The plist to send
185 *
186 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client or
187 * plist is NULL
188 */
189restored_error_t restored_send(restored_client_t client, plist_t plist) 160restored_error_t restored_send(restored_client_t client, plist_t plist)
190{ 161{
191 if (!client || !plist) 162 if (!client || !plist)
192 return RESTORE_E_INVALID_ARG; 163 return RESTORE_E_INVALID_ARG;
193 164
194 restored_error_t ret = RESTORE_E_SUCCESS; 165 return restored_error(property_list_service_send_xml_plist(client->parent, plist));
195 idevice_error_t err;
196
197 err = property_list_service_send_xml_plist(client->parent, plist);
198 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
199 ret = RESTORE_E_UNKNOWN_ERROR;
200 }
201 return ret;
202} 166}
203 167
204/**
205 * Query the type of the service daemon. Depending on whether the device is
206 * queried in normal mode or restore mode, different types will be returned.
207 *
208 * @param client The restored client
209 * @param type The type returned by the service daemon. Pass NULL to ignore.
210 * @param version The restore protocol version. Pass NULL to ignore.
211 *
212 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
213 */
214restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) 168restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version)
215{ 169{
216 if (!client) 170 if (!client)
@@ -220,7 +174,7 @@ restored_error_t restored_query_type(restored_client_t client, char **type, uint
220 174
221 plist_t dict = plist_new_dict(); 175 plist_t dict = plist_new_dict();
222 plist_dict_add_label(dict, client->label); 176 plist_dict_add_label(dict, client->label);
223 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); 177 plist_dict_set_item(dict,"Request", plist_new_string("QueryType"));
224 178
225 debug_info("called"); 179 debug_info("called");
226 ret = restored_send(client, dict); 180 ret = restored_send(client, dict);
@@ -229,25 +183,25 @@ restored_error_t restored_query_type(restored_client_t client, char **type, uint
229 dict = NULL; 183 dict = NULL;
230 184
231 ret = restored_receive(client, &dict); 185 ret = restored_receive(client, &dict);
232 186
233 if (RESTORE_E_SUCCESS != ret) 187 if (RESTORE_E_SUCCESS != ret)
234 return ret; 188 return ret;
235 189
236 ret = RESTORE_E_UNKNOWN_ERROR; 190 ret = RESTORE_E_UNKNOWN_ERROR;
237 if (restored_check_result(dict) == RESULT_SUCCESS) { 191 plist_t type_node = plist_dict_get_item(dict, "Type");
192 if (type_node && (plist_get_node_type(type_node) == PLIST_STRING)) {
193 char* typestr = NULL;
194
238 /* save our device information info */ 195 /* save our device information info */
239 client->info = dict; 196 client->info = dict;
240 197
198 plist_get_string_val(type_node, &typestr);
199 debug_info("success with type %s", typestr);
241 /* return the type if requested */ 200 /* return the type if requested */
242 if (type) { 201 if (type) {
243 plist_t type_node = plist_dict_get_item(dict, "Type"); 202 *type = typestr;
244 if (type_node && PLIST_STRING == plist_get_node_type(type_node)) { 203 } else {
245 plist_get_string_val(type_node, type); 204 free(typestr);
246 debug_info("success with type %s", *type);
247 ret = RESTORE_E_SUCCESS;
248 } else {
249 return RESTORE_E_UNKNOWN_ERROR;
250 }
251 } 205 }
252 206
253 /* fetch the restore protocol version */ 207 /* fetch the restore protocol version */
@@ -256,87 +210,121 @@ restored_error_t restored_query_type(restored_client_t client, char **type, uint
256 if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { 210 if (version_node && PLIST_UINT == plist_get_node_type(version_node)) {
257 plist_get_uint_val(version_node, version); 211 plist_get_uint_val(version_node, version);
258 debug_info("restored protocol version %llu", *version); 212 debug_info("restored protocol version %llu", *version);
259 ret = RESTORE_E_SUCCESS;
260 } else { 213 } else {
261 return RESTORE_E_UNKNOWN_ERROR; 214 return RESTORE_E_UNKNOWN_ERROR;
262 } 215 }
263 } 216 }
264 ret = RESTORE_E_SUCCESS; 217 ret = RESTORE_E_SUCCESS;
218 } else {
219 debug_info("hmm. QueryType response does not contain a type?!");
220 debug_plist(dict);
221 plist_free(dict);
265 } 222 }
266 223
267 return ret; 224 return ret;
268} 225}
269 226
270/** 227restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value)
271 * Retrieves a value from information plist specified by a key.
272 *
273 * @param client An initialized restored client.
274 * @param key The key name to request or NULL to query for all keys
275 * @param value A plist node representing the result value node
276 *
277 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found
278 */
279restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value)
280{ 228{
229 if (!client || !key)
230 return RESTORE_E_INVALID_ARG;
231
232 plist_t dict = NULL;
233 restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;
234
235 /* setup request plist */
236 dict = plist_new_dict();
237 plist_dict_add_label(dict, client->label);
238 if (key) {
239 plist_dict_set_item(dict,"QueryKey", plist_new_string(key));
240 }
241 plist_dict_set_item(dict,"Request", plist_new_string("QueryValue"));
242
243 /* send to device */
244 ret = restored_send(client, dict);
245
246 plist_free(dict);
247 dict = NULL;
248
249 if (ret != RESTORE_E_SUCCESS)
250 return ret;
251
252 /* Now get device's answer */
253 ret = restored_receive(client, &dict);
254 if (ret != RESTORE_E_SUCCESS)
255 return ret;
256
257 plist_t value_node = plist_dict_get_item(dict, key);
258 if (value_node) {
259 debug_info("has a value");
260 *value = plist_copy(value_node);
261 } else {
262 ret = RESTORE_E_PLIST_ERROR;
263 }
264
265 plist_free(dict);
266 return ret;
267}
268
269restored_error_t restored_get_value(restored_client_t client, const char *key, plist_t *value)
270{
271 plist_t item;
272
281 if (!client || !value || (value && *value)) 273 if (!client || !value || (value && *value))
282 return RESTORE_E_INVALID_ARG; 274 return RESTORE_E_INVALID_ARG;
283 275
284 if (!client->info) 276 if (!client->info)
285 return RESTORE_E_NOT_ENOUGH_DATA; 277 return RESTORE_E_NOT_ENOUGH_DATA;
286 278
287 restored_error_t ret = RESTORE_E_SUCCESS;
288 plist_t item = NULL;
289
290 if (!key) { 279 if (!key) {
291 *value = plist_copy(client->info); 280 *value = plist_copy(client->info);
292 return RESTORE_E_SUCCESS; 281 return RESTORE_E_SUCCESS;
293 } else {
294 item = plist_dict_get_item(client->info, key);
295 } 282 }
296 283
297 if (item) { 284 item = plist_dict_get_item(client->info, key);
298 *value = plist_copy(item); 285 if (!item) {
299 } else { 286 return RESTORE_E_PLIST_ERROR;
300 ret = RESTORE_E_PLIST_ERROR;
301 } 287 }
302 288
303 return ret; 289 *value = plist_copy(item);
290
291 return RESTORE_E_SUCCESS;
304} 292}
305 293
306/**
307 * Creates a new restored client for the device.
308 *
309 * @param device The device to create a restored client for
310 * @param client The pointer to the location of the new restored_client
311 * @param label The label to use for communication. Usually the program name.
312 *
313 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
314 */
315restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) 294restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
316{ 295{
317 if (!client) 296 if (!client)
318 return RESTORE_E_INVALID_ARG; 297 return RESTORE_E_INVALID_ARG;
319 298
320 restored_error_t ret = RESTORE_E_SUCCESS; 299 restored_error_t ret = RESTORE_E_SUCCESS;
300 idevice_error_t idev_ret;
301
302 static struct lockdownd_service_descriptor service = {
303 .port = 0xf27e,
304 .ssl_enabled = 0
305 };
321 306
322 property_list_service_client_t plistclient = NULL; 307 property_list_service_client_t plistclient = NULL;
323 if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { 308 ret = restored_error(property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient));
324 debug_info("could not connect to restored (device %s)", device->uuid); 309 if (ret != RESTORE_E_SUCCESS) {
325 return RESTORE_E_MUX_ERROR; 310 debug_info("could not connect to restored (device %s)", device->udid);
311 return ret;
326 } 312 }
327 313
328 restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private)); 314 restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
329 client_loc->parent = plistclient; 315 client_loc->parent = plistclient;
330 client_loc->uuid = NULL; 316 client_loc->udid = NULL;
331 client_loc->label = NULL; 317 client_loc->label = NULL;
318 client_loc->info = NULL;
332 if (label != NULL) 319 if (label != NULL)
333 client_loc->label = strdup(label); 320 client_loc->label = strdup(label);
334 321
335 ret = idevice_get_uuid(device, &client_loc->uuid); 322 idev_ret = idevice_get_udid(device, &client_loc->udid);
336 if (RESTORE_E_SUCCESS != ret) { 323 if (IDEVICE_E_SUCCESS != idev_ret) {
337 debug_info("failed to get device uuid."); 324 debug_info("failed to get device udid.");
325 ret = RESTORE_E_UNKNOWN_ERROR;
338 } 326 }
339 debug_info("device uuid: %s", client_loc->uuid); 327 debug_info("device udid: %s", client_loc->udid);
340 328
341 if (RESTORE_E_SUCCESS == ret) { 329 if (RESTORE_E_SUCCESS == ret) {
342 *client = client_loc; 330 *client = client_loc;
@@ -347,14 +335,6 @@ restored_error_t restored_client_new(idevice_t device, restored_client_t *client
347 return ret; 335 return ret;
348} 336}
349 337
350/**
351 * Sends the Goodbye request to restored signaling the end of communication.
352 *
353 * @param client The restore client
354 *
355 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
356 * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request
357 */
358restored_error_t restored_goodbye(restored_client_t client) 338restored_error_t restored_goodbye(restored_client_t client)
359{ 339{
360 if (!client) 340 if (!client)
@@ -364,7 +344,7 @@ restored_error_t restored_goodbye(restored_client_t client)
364 344
365 plist_t dict = plist_new_dict(); 345 plist_t dict = plist_new_dict();
366 plist_dict_add_label(dict, client->label); 346 plist_dict_add_label(dict, client->label);
367 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); 347 plist_dict_set_item(dict,"Request", plist_new_string("Goodbye"));
368 348
369 debug_info("called"); 349 debug_info("called");
370 350
@@ -387,15 +367,7 @@ restored_error_t restored_goodbye(restored_client_t client)
387 return ret; 367 return ret;
388} 368}
389 369
390/** 370restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version)
391 * Requests to start a restore and retrieve it's port on success.
392 *
393 * @param client The restored client
394 *
395 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
396 * is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails
397 */
398restored_error_t restored_start_restore(restored_client_t client)
399{ 371{
400 if (!client) 372 if (!client)
401 return RESTORE_E_INVALID_ARG; 373 return RESTORE_E_INVALID_ARG;
@@ -405,8 +377,11 @@ restored_error_t restored_start_restore(restored_client_t client)
405 377
406 dict = plist_new_dict(); 378 dict = plist_new_dict();
407 plist_dict_add_label(dict, client->label); 379 plist_dict_add_label(dict, client->label);
408 plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore")); 380 plist_dict_set_item(dict,"Request", plist_new_string("StartRestore"));
409 plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(2)); 381 if (options) {
382 plist_dict_set_item(dict, "RestoreOptions", plist_copy(options));
383 }
384 plist_dict_set_item(dict,"RestoreProtocolVersion", plist_new_uint(version));
410 385
411 /* send to device */ 386 /* send to device */
412 ret = restored_send(client, dict); 387 ret = restored_send(client, dict);
@@ -416,14 +391,6 @@ restored_error_t restored_start_restore(restored_client_t client)
416 return ret; 391 return ret;
417} 392}
418 393
419/**
420 * Requests device to reboot.
421 *
422 * @param client The restored client
423 *
424 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
425 * is NULL
426 */
427restored_error_t restored_reboot(restored_client_t client) 394restored_error_t restored_reboot(restored_client_t client)
428{ 395{
429 if (!client) 396 if (!client)
@@ -434,7 +401,7 @@ restored_error_t restored_reboot(restored_client_t client)
434 401
435 dict = plist_new_dict(); 402 dict = plist_new_dict();
436 plist_dict_add_label(dict, client->label); 403 plist_dict_add_label(dict, client->label);
437 plist_dict_insert_item(dict,"Request", plist_new_string("Reboot")); 404 plist_dict_set_item(dict,"Request", plist_new_string("Reboot"));
438 405
439 /* send to device */ 406 /* send to device */
440 ret = restored_send(client, dict); 407 ret = restored_send(client, dict);
@@ -455,4 +422,3 @@ restored_error_t restored_reboot(restored_client_t client)
455 dict = NULL; 422 dict = NULL;
456 return ret; 423 return ret;
457} 424}
458