summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2013-08-18 05:28:53 +0200
committerGravatar Martin Szulecki2013-09-17 11:43:33 +0200
commitec720cc1c30ac3f9b7996575e835565f60ce2b3e (patch)
treef92476e06ce36ab56348544fb9ae614ec10d904c
parent36e636a727ecbae7083878ceb493b26046a47179 (diff)
downloadlibimobiledevice-ec720cc1c30ac3f9b7996575e835565f60ce2b3e.tar.gz
libimobiledevice-ec720cc1c30ac3f9b7996575e835565f60ce2b3e.tar.bz2
Refactor userpref logic to use plist format and implement trust dialog handling
iOS 7 introduced a new pairing workflow which increases security by showing a trust dialog to the user before pairing with the host is allowed. The userpref system was refactored to use the native plist format, too. Configuration files of the native implementations are used on each platform. Former configuration files are no longer in use and can be deleted.
-rw-r--r--common/userpref.c684
-rw-r--r--common/userpref.h36
-rw-r--r--include/libimobiledevice/lockdown.h5
-rw-r--r--src/idevice.c2
-rw-r--r--src/lockdown.c257
-rw-r--r--src/lockdown.h4
6 files changed, 579 insertions, 409 deletions
diff --git a/common/userpref.c b/common/userpref.c
index 23fe583..41ce9b9 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -58,14 +58,6 @@
58#include "debug.h" 58#include "debug.h"
59#include "utils.h" 59#include "utils.h"
60 60
61#define LIBIMOBILEDEVICE_CONF_DIR "libimobiledevice"
62#define LIBIMOBILEDEVICE_CONF_FILE "libimobiledevicerc"
63
64#define LIBIMOBILEDEVICE_ROOT_PRIVKEY "RootPrivateKey.pem"
65#define LIBIMOBILEDEVICE_HOST_PRIVKEY "HostPrivateKey.pem"
66#define LIBIMOBILEDEVICE_ROOT_CERTIF "RootCertificate.pem"
67#define LIBIMOBILEDEVICE_HOST_CERTIF "HostCertificate.pem"
68
69#ifdef WIN32 61#ifdef WIN32
70#define DIR_SEP '\\' 62#define DIR_SEP '\\'
71#define DIR_SEP_S "\\" 63#define DIR_SEP_S "\\"
@@ -74,6 +66,19 @@
74#define DIR_SEP_S "/" 66#define DIR_SEP_S "/"
75#endif 67#endif
76 68
69#define USERPREF_CONFIG_EXTENSION ".plist"
70
71#ifndef __APPLE__
72#define USERPREF_CONFIG_DIR "libimobiledevice"
73#else
74#ifdef WIN32
75#define USERPREF_CONFIG_DIR "Apple"DIR_SEP_S"Lockdown"
76#else
77#define USERPREF_CONFIG_DIR "lockdown"
78#endif
79#endif
80#define USERPREF_CONFIG_FILE "SystemConfiguration"USERPREF_CONFIG_EXTENSION
81
77static char *__config_dir = NULL; 82static char *__config_dir = NULL;
78 83
79#ifdef WIN32 84#ifdef WIN32
@@ -172,7 +177,7 @@ static const char *userpref_get_config_dir()
172 LPITEMIDLIST pidl = NULL; 177 LPITEMIDLIST pidl = NULL;
173 BOOL b = FALSE; 178 BOOL b = FALSE;
174 179
175 hr = SHGetSpecialFolderLocation (NULL, CSIDL_LOCAL_APPDATA, &pidl); 180 hr = SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_APPDATA, &pidl);
176 if (hr == S_OK) { 181 if (hr == S_OK) {
177 b = SHGetPathFromIDListW (pidl, path); 182 b = SHGetPathFromIDListW (pidl, path);
178 if (b) { 183 if (b) {
@@ -183,6 +188,10 @@ static const char *userpref_get_config_dir()
183 188
184 use_dot_config = 0; 189 use_dot_config = 0;
185#else 190#else
191#ifdef __APPLE__
192 base_config_dir = strdup("/var/db");
193 use_dot_config = 0;
194#else
186 const char *cdir = getenv("XDG_CONFIG_HOME"); 195 const char *cdir = getenv("XDG_CONFIG_HOME");
187 if (!cdir) { 196 if (!cdir) {
188 cdir = getenv("HOME"); 197 cdir = getenv("HOME");
@@ -200,11 +209,12 @@ static const char *userpref_get_config_dir()
200 use_dot_config = 0; 209 use_dot_config = 0;
201 } 210 }
202#endif 211#endif
212#endif
203 213
204 if (use_dot_config) 214 if (use_dot_config)
205 __config_dir = string_concat(base_config_dir, DIR_SEP_S, ".config", DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR, NULL); 215 __config_dir = string_concat(base_config_dir, DIR_SEP_S, ".config", DIR_SEP_S, USERPREF_CONFIG_DIR, NULL);
206 else 216 else
207 __config_dir = string_concat(base_config_dir, DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR, NULL); 217 __config_dir = string_concat(base_config_dir, DIR_SEP_S, USERPREF_CONFIG_DIR, NULL);
208 218
209 if (__config_dir) { 219 if (__config_dir) {
210 int i = strlen(__config_dir)-1; 220 int i = strlen(__config_dir)-1;
@@ -215,6 +225,8 @@ static const char *userpref_get_config_dir()
215 225
216 free(base_config_dir); 226 free(base_config_dir);
217 227
228 debug_info("initialized config_dir to %s", __config_dir);
229
218 return __config_dir; 230 return __config_dir;
219} 231}
220 232
@@ -250,131 +262,6 @@ static int mkdir_with_parents(const char *dir, int mode)
250 return res; 262 return res;
251} 263}
252 264
253static int config_write(const char *cfgfile, plist_t dict)
254{
255 if (!cfgfile || !dict || (plist_get_node_type(dict) != PLIST_DICT)) {
256 return -1;
257 }
258 int res = -1;
259
260#if 1 // old style config
261 plist_t hostid = plist_dict_get_item(dict, "HostID");
262 if (hostid && (plist_get_node_type(hostid) == PLIST_STRING)) {
263 char *hostidstr = NULL;
264 plist_get_string_val(hostid, &hostidstr);
265 if (hostidstr) {
266 FILE *fd = fopen(cfgfile, "wb");
267 if (fd) {
268 fprintf(fd, "\n[Global]\nHostID=%s\n", hostidstr);
269 fclose(fd);
270 res = 0;
271 } else {
272 debug_info("could not open '%s' for writing: %s", cfgfile, strerror(errno));
273 }
274 free(hostidstr);
275 }
276 }
277#endif
278#if 0
279 char *xml = NULL;
280 uint32_t length = 0;
281
282 plist_to_xml(dict, &xml, &length);
283 if (!xml) {
284 return res;
285 }
286
287 FILE *fd = fopen(cfgfile, "wb");
288 if (!fd) {
289 free(xml);
290 return res;
291 }
292
293 if (fwrite(xml, 1, length, fd) == length) {
294 res = 0;
295 } else {
296 fprintf(stderr, "%s: ERROR: failed to write configuration to '%s'\n", __func__, cfgfile);
297 }
298 fclose(fd);
299
300 free(xml);
301#endif
302 return res;
303}
304
305static int config_read(const char *cfgfile, plist_t *dict)
306{
307 if (!cfgfile || !dict) {
308 return -1;
309 }
310
311 int res = -1;
312 FILE *fd = fopen(cfgfile, "rb");
313 if (!fd) {
314 debug_info("could not open '%s' for reading: %s", cfgfile, strerror(errno));
315 return -1;
316 }
317
318 fseek(fd, 0, SEEK_END);
319 unsigned long int size = ftell(fd);
320 fseek(fd, 0, SEEK_SET);
321 unsigned char *contents = NULL;
322
323 contents = malloc(size);
324 if (fread(contents, 1, size, fd) != size) {
325 free(contents);
326 fclose(fd);
327 return -1;
328 }
329 plist_t plist = NULL;
330
331 if (!memcmp(contents, "bplist00", 8)) {
332 plist_from_bin((const char*)contents, (uint32_t)size, &plist);
333 fclose(fd);
334 } else {
335 if (memchr(contents, '<', size)) {
336 plist_from_xml((const char*)contents, (uint32_t)size, &plist);
337 }
338 if (plist) {
339 fclose(fd);
340 } else {
341 // try parsing old format config file
342 char line[256];
343 fseek(fd, 0, SEEK_SET);
344 while (fgets(line, 256, fd)) {
345 char *p = &line[0];
346 size_t llen = strlen(p)-1;
347 while ((llen > 0) && ((p[llen] == '\n') || (p[llen] == '\r'))) {
348 p[llen] = '\0';
349 llen--;
350 }
351 if (llen == 0) continue;
352 while ((p[0] == '\n') || (p[0] == '\r')) {
353 p++;
354 }
355 if (!strncmp(p, "HostID=", 7)) {
356 plist = plist_new_dict();
357 plist_dict_insert_item(plist, "HostID", plist_new_string(p+7));
358 break;
359 }
360 }
361 fclose(fd);
362#if 0
363 if (plist) {
364 // write new format config
365 config_write(cfgfile, plist);
366 }
367#endif
368 }
369 }
370 free(contents);
371 if (plist) {
372 *dict = plist;
373 res = 0;
374 }
375 return res;
376}
377
378/** 265/**
379 * Creates a freedesktop compatible configuration directory. 266 * Creates a freedesktop compatible configuration directory.
380 */ 267 */
@@ -398,12 +285,12 @@ static int get_rand(int min, int max)
398 * 285 *
399 * @return A null terminated string containing a valid HostID. 286 * @return A null terminated string containing a valid HostID.
400 */ 287 */
401static char *userpref_generate_host_id() 288static char *userpref_generate_host_id(int index)
402{ 289{
403 /* HostID's are just UUID's, and UUID's are 36 characters long */ 290 /* HostID's are just UUID's, and UUID's are 36 characters long */
404 char *hostid = (char *) malloc(sizeof(char) * 37); 291 char *hostid = (char *) malloc(sizeof(char) * 37);
405 const char *chars = "ABCDEF0123456789"; 292 const char *chars = "ABCDEF0123456789";
406 srand(time(NULL)); 293 srand(time(NULL) - index);
407 int i = 0; 294 int i = 0;
408 295
409 for (i = 0; i < 36; i++) { 296 for (i = 0; i < 36; i++) {
@@ -420,88 +307,193 @@ static char *userpref_generate_host_id()
420} 307}
421 308
422/** 309/**
423 * Store HostID in config file. 310 * Generates a valid BUID for this system (which is actually a UUID).
424 * 311 *
425 * @param host_id A null terminated string containing a valid HostID. 312 * @return A null terminated string containing a valid BUID.
426 */ 313 */
427static int userpref_set_host_id(const char *host_id) 314static char *userpref_generate_system_buid()
428{ 315{
429 const char *config_path; 316 return userpref_generate_host_id(1);
430 char *config_file; 317}
431 318
432 if (!host_id) 319static int internal_set_value(const char *config_file, const char *key, plist_t value)
320{
321 if (!config_file)
433 return 0; 322 return 0;
434 323
435 /* Make sure config directory exists */ 324 /* read file into plist */
436 userpref_create_config_dir();
437
438 config_path = userpref_get_config_dir();
439 config_file = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_CONF_FILE)+1);
440 strcpy(config_file, config_path);
441 strcat(config_file, DIR_SEP_S);
442 strcat(config_file, LIBIMOBILEDEVICE_CONF_FILE);
443
444 /* Now parse file to get the HostID */
445 plist_t config = NULL; 325 plist_t config = NULL;
446 config_read(config_file, &config); 326
327 plist_read_from_filename(&config, config_file);
447 if (!config) { 328 if (!config) {
448 config = plist_new_dict(); 329 config = plist_new_dict();
449 plist_dict_insert_item(config, "HostID", plist_new_string(host_id)); 330 plist_dict_insert_item(config, key, value);
450 } else { 331 } else {
451 plist_t n = plist_dict_get_item(config, "HostID"); 332 plist_t n = plist_dict_get_item(config, key);
452 if (n) { 333 if (n) {
453 plist_set_string_val(n, host_id); 334 plist_dict_remove_item(config, key);
454 } else {
455 plist_dict_insert_item(config, "HostID", plist_new_string(host_id));
456 } 335 }
336 plist_dict_insert_item(config, key, value);
337 remove(config_file);
338 }
339
340 /* store in config file */
341 char *value_string = NULL;
342 if (plist_get_node_type(value) == PLIST_STRING) {
343 plist_get_string_val(value, &value_string);
344 debug_info("setting key %s to %s in config_file %s", key, value_string, config_file);
345 } else {
346 debug_info("setting key %s in config_file %s", key, config_file);
457 } 347 }
458 348
459 /* Store in config file */ 349 plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
460 debug_info("setting hostID to %s", host_id);
461 350
462 config_write(config_file, config);
463 plist_free(config); 351 plist_free(config);
464 352
465 free(config_file);
466 return 1; 353 return 1;
467} 354}
468 355
469/** 356int userpref_set_value(const char *key, plist_t value)
470 * Reads the HostID from a previously generated configuration file.
471 *
472 * @note It is the responsibility of the calling function to free the returned host_id
473 *
474 * @return The string containing the HostID or NULL
475 */
476void userpref_get_host_id(char **host_id)
477{ 357{
478 const char *config_path; 358 const char *config_path = NULL;
479 char *config_file; 359 char *config_file = NULL;
360
361 /* Make sure config directory exists */
362 userpref_create_config_dir();
480 363
481 config_path = userpref_get_config_dir(); 364 config_path = userpref_get_config_dir();
482 config_file = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_CONF_FILE)+1); 365 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
483 strcpy(config_file, config_path); 366
484 strcat(config_file, DIR_SEP_S); 367 int result = internal_set_value(config_file, key, value);
485 strcat(config_file, LIBIMOBILEDEVICE_CONF_FILE); 368
369 free(config_file);
370
371 return result;
372}
373
374int userpref_device_record_set_value(const char *udid, const char *key, plist_t value)
375{
376 const char *config_path = NULL;
377 char *config_file = NULL;
378
379 /* Make sure config directory exists */
380 userpref_create_config_dir();
486 381
487 /* now parse file to get the HostID */ 382 config_path = userpref_get_config_dir();
383 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
384
385 int result = internal_set_value(config_file, key, value);
386
387 free(config_file);
388
389 return result;
390}
391
392static int internal_get_value(const char* config_file, const char *key, plist_t *value)
393{
394 *value = NULL;
395
396 /* now parse file to get the SystemBUID */
488 plist_t config = NULL; 397 plist_t config = NULL;
489 if (config_read(config_file, &config) == 0) { 398 if (plist_read_from_filename(&config, config_file)) {
490 plist_t n_host_id = plist_dict_get_item(config, "HostID"); 399 debug_info("reading key %s from config_file %s", key, config_file);
491 if (n_host_id && (plist_get_node_type(n_host_id) == PLIST_STRING)) { 400 plist_t n = plist_dict_get_item(config, key);
492 plist_get_string_val(n_host_id, host_id); 401 if (n) {
402 *value = plist_copy(n);
403 plist_free(n);
404 n = NULL;
493 } 405 }
494 } 406 }
495 plist_free(config); 407 plist_free(config);
408
409 return 1;
410}
411
412int userpref_get_value(const char *key, plist_t *value)
413{
414 const char *config_path = NULL;
415 char *config_file = NULL;
416
417 config_path = userpref_get_config_dir();
418 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
419
420 int result = internal_get_value(config_file, key, value);
421
422 free(config_file);
423
424 return result;
425}
426
427int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value)
428{
429 const char *config_path = NULL;
430 char *config_file = NULL;
431
432 config_path = userpref_get_config_dir();
433 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
434
435 int result = internal_get_value(config_file, key, value);
436
496 free(config_file); 437 free(config_file);
497 438
439 return result;
440}
441
442/**
443 * Store SystemBUID in config file.
444 *
445 * @param host_id A null terminated string containing a valid SystemBUID.
446 */
447static int userpref_set_system_buid(const char *system_buid)
448{
449 return userpref_set_value(USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));
450}
451
452/**
453 * Reads the BUID from a previously generated configuration file.
454 *
455 * @note It is the responsibility of the calling function to free the returned system_buid
456 *
457 * @return The string containing the BUID or NULL
458 */
459void userpref_get_system_buid(char **system_buid)
460{
461 plist_t value = NULL;
462
463 userpref_get_value(USERPREF_SYSTEM_BUID_KEY, &value);
464
465 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
466 plist_get_string_val(value, system_buid);
467 debug_info("got %s %s", USERPREF_SYSTEM_BUID_KEY, *system_buid);
468 }
469
470 if (!*system_buid) {
471 /* no config, generate system_buid */
472 debug_info("no previous %s found", USERPREF_SYSTEM_BUID_KEY);
473 *system_buid = userpref_generate_system_buid();
474 userpref_set_system_buid(*system_buid);
475 }
476
477 debug_info("using %s as %s", *system_buid, USERPREF_SYSTEM_BUID_KEY);
478}
479
480void userpref_device_record_get_host_id(const char *udid, char **host_id)
481{
482 plist_t value = NULL;
483
484 userpref_device_record_get_value(udid, USERPREF_HOST_ID_KEY, &value);
485
486 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
487 plist_get_string_val(value, host_id);
488 }
489
498 if (!*host_id) { 490 if (!*host_id) {
499 /* no config, generate host_id */ 491 /* no config, generate host_id */
500 *host_id = userpref_generate_host_id(); 492 *host_id = userpref_generate_host_id(0);
501 userpref_set_host_id(*host_id); 493 userpref_device_record_set_value(udid, USERPREF_HOST_ID_KEY, plist_new_string(*host_id));
502 } 494 }
503 495
504 debug_info("Using %s as HostID", *host_id); 496 debug_info("using %s as %s", *host_id, USERPREF_HOST_ID_KEY);
505} 497}
506 498
507/** 499/**
@@ -512,26 +504,24 @@ void userpref_get_host_id(char **host_id)
512 * @return 1 if the device has been connected previously to this configuration 504 * @return 1 if the device has been connected previously to this configuration
513 * or 0 otherwise. 505 * or 0 otherwise.
514 */ 506 */
515int userpref_has_device_public_key(const char *udid) 507int userpref_has_device_record(const char *udid)
516{ 508{
517 int ret = 0; 509 int ret = 0;
518 const char *config_path; 510 const char *config_path = NULL;
519 char *config_file; 511 char *config_file = NULL;
520 struct stat st; 512 struct stat st;
521 513
522 if (!udid) return 0; 514 if (!udid) return 0;
523 515
524 /* first get config file */ 516 /* first get config file */
525 config_path = userpref_get_config_dir(); 517 config_path = userpref_get_config_dir();
526 config_file = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1); 518 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
527 strcpy(config_file, config_path);
528 strcat(config_file, DIR_SEP_S);
529 strcat(config_file, udid);
530 strcat(config_file, ".pem");
531 519
532 if ((stat(config_file, &st) == 0) && S_ISREG(st.st_mode)) 520 if ((stat(config_file, &st) == 0) && S_ISREG(st.st_mode))
533 ret = 1; 521 ret = 1;
522
534 free(config_file); 523 free(config_file);
524
535 return ret; 525 return ret;
536} 526}
537 527
@@ -557,7 +547,7 @@ userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
557 void *next; 547 void *next;
558 }; 548 };
559 DIR *config_dir; 549 DIR *config_dir;
560 const char *config_path; 550 const char *config_path = NULL;
561 struct slist_t *udids = NULL; 551 struct slist_t *udids = NULL;
562 unsigned int i; 552 unsigned int i;
563 unsigned int found = 0; 553 unsigned int found = 0;
@@ -577,8 +567,8 @@ userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
577 struct dirent *entry; 567 struct dirent *entry;
578 struct slist_t *listp = udids; 568 struct slist_t *listp = udids;
579 while ((entry = readdir(config_dir))) { 569 while ((entry = readdir(config_dir))) {
580 char *ext = strstr(entry->d_name, ".pem"); 570 char *ext = strstr(entry->d_name, USERPREF_CONFIG_EXTENSION);
581 if (ext && ((ext - entry->d_name) == 40) && (strlen(entry->d_name) == 44)) { 571 if (ext && ((ext - entry->d_name) == 40) && (strlen(entry->d_name) == (40 + strlen(ext)))) {
582 struct slist_t *ne = (struct slist_t*)malloc(sizeof(struct slist_t)); 572 struct slist_t *ne = (struct slist_t*)malloc(sizeof(struct slist_t));
583 ne->name = (char*)malloc(41); 573 ne->name = (char*)malloc(41);
584 strncpy(ne->name, entry->d_name, 40); 574 strncpy(ne->name, entry->d_name, 40);
@@ -614,75 +604,77 @@ userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
614} 604}
615 605
616/** 606/**
617 * Mark the device (as represented by the key) as having connected to this 607 * Mark the device as having connected to this configuration.
618 * configuration.
619 * 608 *
620 * @param udid The device UDID as given by the device 609 * @param udid The device UDID as given by the device
621 * @param public_key The public key given by the device 610 * @param device_record The device record with full configuration
622 * 611 *
623 * @return 1 on success and 0 if no public key is given or if it has already 612 * @return 1 on success and 0 if no device record is given or if it has already
624 * been marked as connected previously. 613 * been marked as connected previously.
625 */ 614 */
626userpref_error_t userpref_set_device_public_key(const char *udid, key_data_t public_key) 615userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record)
627{ 616{
628 if (NULL == public_key.data)
629 return USERPREF_E_INVALID_ARG;
630
631 if (userpref_has_device_public_key(udid))
632 return USERPREF_E_SUCCESS;
633
634 /* ensure config directory exists */ 617 /* ensure config directory exists */
635 userpref_create_config_dir(); 618 userpref_create_config_dir();
636 619
637 /* build file path */ 620 /* build file path */
638 const char *config_path = userpref_get_config_dir(); 621 const char *config_path = userpref_get_config_dir();
639 char *pem = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1); 622 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
640 strcpy(pem, config_path); 623
641 strcat(pem, DIR_SEP_S); 624 remove(device_record_file);
642 strcat(pem, udid);
643 strcat(pem, ".pem");
644 625
645 /* store file */ 626 /* store file */
646 FILE *pFile = fopen(pem, "wb"); 627 if (!plist_write_to_filename(device_record, device_record_file, PLIST_FORMAT_XML)) {
647 if (pFile) { 628 debug_info("could not open '%s' for writing: %s", device_record_file, strerror(errno));
648 fwrite(public_key.data, 1, public_key.size, pFile); 629 }
649 fclose(pFile); 630 free(device_record_file);
650 } else { 631
651 debug_info("could not open '%s' for writing: %s", pem, strerror(errno)); 632 return USERPREF_E_SUCCESS;
633}
634
635userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record)
636{
637 /* ensure config directory exists */
638 userpref_create_config_dir();
639
640 /* build file path */
641 const char *config_path = userpref_get_config_dir();
642 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
643
644 /* read file */
645 if (!plist_read_from_filename(device_record, device_record_file)) {
646 debug_info("could not open '%s' for reading: %s", device_record_file, strerror(errno));
652 } 647 }
653 free(pem); 648 free(device_record_file);
654 649
655 return USERPREF_E_SUCCESS; 650 return USERPREF_E_SUCCESS;
656} 651}
657 652
658/** 653/**
659 * Remove the public key stored for the device with udid from this host. 654 * Remove the pairing record stored for a device from this host.
660 * 655 *
661 * @param udid The udid of the device 656 * @param udid The udid of the device
662 * 657 *
663 * @return USERPREF_E_SUCCESS on success. 658 * @return USERPREF_E_SUCCESS on success.
664 */ 659 */
665userpref_error_t userpref_remove_device_public_key(const char *udid) 660userpref_error_t userpref_remove_device_record(const char *udid)
666{ 661{
667 if (!userpref_has_device_public_key(udid)) 662 if (!userpref_has_device_record(udid))
668 return USERPREF_E_SUCCESS; 663 return USERPREF_E_SUCCESS;
669 664
670 /* build file path */ 665 /* build file path */
671 const char *config_path = userpref_get_config_dir(); 666 const char *config_path = userpref_get_config_dir();
672 char *pem = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1); 667 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
673 strcpy(pem, config_path);
674 strcat(pem, DIR_SEP_S);
675 strcat(pem, udid);
676 strcat(pem, ".pem");
677 668
678 /* remove file */ 669 /* remove file */
679 remove(pem); 670 remove(device_record_file);
680 671
681 free(pem); 672 free(device_record_file);
682 673
683 return USERPREF_E_SUCCESS; 674 return USERPREF_E_SUCCESS;
684} 675}
685 676
677#if 0
686/** 678/**
687 * Private function which reads the given file into a key_data_t structure. 679 * Private function which reads the given file into a key_data_t structure.
688 * 680 *
@@ -696,7 +688,7 @@ static int userpref_get_file_contents(const char *file, key_data_t * data)
696 int success = 0; 688 int success = 0;
697 unsigned long int size = 0; 689 unsigned long int size = 0;
698 unsigned char *content = NULL; 690 unsigned char *content = NULL;
699 const char *config_path; 691 const char *config_path = NULL;
700 char *filepath; 692 char *filepath;
701 FILE *fd; 693 FILE *fd;
702 694
@@ -705,10 +697,7 @@ static int userpref_get_file_contents(const char *file, key_data_t * data)
705 697
706 /* Read file */ 698 /* Read file */
707 config_path = userpref_get_config_dir(); 699 config_path = userpref_get_config_dir();
708 filepath = (char*)malloc(strlen(config_path)+1+strlen(file)+1); 700 filepath = string_concat(config_path, DIR_SEP_S, file, NULL);
709 strcpy(filepath, config_path);
710 strcat(filepath, DIR_SEP_S);
711 strcat(filepath, file);
712 701
713 fd = fopen(filepath, "rb"); 702 fd = fopen(filepath, "rb");
714 if (fd) { 703 if (fd) {
@@ -746,13 +735,14 @@ static int userpref_get_file_contents(const char *file, key_data_t * data)
746 735
747 return success; 736 return success;
748} 737}
738#endif
749 739
750/** 740/**
751 * Private function which generate private keys and certificates. 741 * Private function which generate private keys and certificates.
752 * 742 *
753 * @return 1 if keys were successfully generated, 0 otherwise 743 * @return 1 if keys were successfully generated, 0 otherwise
754 */ 744 */
755static userpref_error_t userpref_gen_keys_and_cert(void) 745static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udid)
756{ 746{
757 userpref_error_t ret = USERPREF_E_SSL_ERROR; 747 userpref_error_t ret = USERPREF_E_SSL_ERROR;
758 748
@@ -761,7 +751,7 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
761 key_data_t host_key_pem = { NULL, 0 }; 751 key_data_t host_key_pem = { NULL, 0 };
762 key_data_t host_cert_pem = { NULL, 0 }; 752 key_data_t host_cert_pem = { NULL, 0 };
763 753
764 debug_info("Generating keys and certificates"); 754 debug_info("generating keys and certificates");
765#ifdef HAVE_OPENSSL 755#ifdef HAVE_OPENSSL
766 RSA* root_keypair = RSA_generate_key(2048, 65537, NULL, NULL); 756 RSA* root_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
767 RSA* host_keypair = RSA_generate_key(2048, 65537, NULL, NULL); 757 RSA* host_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
@@ -880,7 +870,7 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
880 gnutls_global_deinit(); 870 gnutls_global_deinit();
881 gnutls_global_init(); 871 gnutls_global_init();
882 872
883 //use less secure random to speed up key generation 873 /* use less secure random to speed up key generation */
884 gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM); 874 gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM);
885 875
886 gnutls_x509_privkey_init(&root_privkey); 876 gnutls_x509_privkey_init(&root_privkey);
@@ -940,7 +930,7 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
940 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size); 930 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size);
941 host_cert_pem.size = host_cert_export_size; 931 host_cert_pem.size = host_cert_export_size;
942 932
943 //restore gnutls env 933 /* restore gnutls env */
944 gnutls_global_deinit(); 934 gnutls_global_deinit();
945 gnutls_global_init(); 935 gnutls_global_init();
946#endif 936#endif
@@ -949,7 +939,7 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
949 ret = USERPREF_E_SUCCESS; 939 ret = USERPREF_E_SUCCESS;
950 940
951 /* store values in config file */ 941 /* store values in config file */
952 userpref_set_keys_and_certs( &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem); 942 userpref_device_record_set_keys_and_certs(udid, &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem);
953 943
954 if (root_key_pem.data) 944 if (root_key_pem.data)
955 free(root_key_pem.data); 945 free(root_key_pem.data);
@@ -966,15 +956,15 @@ static userpref_error_t userpref_gen_keys_and_cert(void)
966/** 956/**
967 * Private function which import the given key into a gnutls structure. 957 * Private function which import the given key into a gnutls structure.
968 * 958 *
969 * @param key_name The filename of the private key to import. 959 * @param name The name of the private key to import.
970 * @param key the gnutls key structure. 960 * @param key the gnutls key structure.
971 * 961 *
972 * @return 1 if the key was successfully imported. 962 * @return 1 if the key was successfully imported.
973 */ 963 */
974#ifdef HAVE_OPENSSL 964#ifdef HAVE_OPENSSL
975static userpref_error_t userpref_import_key(const char* key_name, key_data_t* key) 965static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, key_data_t* key)
976#else 966#else
977static userpref_error_t userpref_import_key(const char* key_name, gnutls_x509_privkey_t key) 967static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, gnutls_x509_privkey_t key)
978#endif 968#endif
979{ 969{
980#ifdef HAVE_OPENSSL 970#ifdef HAVE_OPENSSL
@@ -982,37 +972,49 @@ static userpref_error_t userpref_import_key(const char* key_name, gnutls_x509_pr
982 return USERPREF_E_SUCCESS; 972 return USERPREF_E_SUCCESS;
983#endif 973#endif
984 userpref_error_t ret = USERPREF_E_INVALID_CONF; 974 userpref_error_t ret = USERPREF_E_INVALID_CONF;
985 key_data_t pem_key = { NULL, 0 }; 975 char* buffer = NULL;
986 if (userpref_get_file_contents(key_name, &pem_key)) { 976 uint64_t length = 0;
977
978 plist_t crt = NULL;
979 if (userpref_device_record_get_value(udid, name, &crt)) {
980 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
981 plist_get_data_val(crt, &buffer, &length);
987#ifdef HAVE_OPENSSL 982#ifdef HAVE_OPENSSL
988 key->data = (unsigned char*)malloc(pem_key.size); 983 key->data = (unsigned char*)malloc(length);
989 memcpy(key->data, pem_key.data, pem_key.size); 984 memcpy(key->data, buffer, length);
990 key->size = pem_key.size; 985 key->size = length;
991 ret = USERPREF_E_SUCCESS;
992#else
993 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM))
994 ret = USERPREF_E_SUCCESS; 986 ret = USERPREF_E_SUCCESS;
995 else 987#else
996 ret = USERPREF_E_SSL_ERROR; 988 key_data_t pem = { buffer, length };
989 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM))
990 ret = USERPREF_E_SUCCESS;
991 else
992 ret = USERPREF_E_SSL_ERROR;
997#endif 993#endif
994 }
998 } 995 }
999 if (pem_key.data) 996
1000 free(pem_key.data); 997 if (crt)
998 plist_free(crt);
999
1000 if (buffer)
1001 free(buffer);
1002
1001 return ret; 1003 return ret;
1002} 1004}
1003 1005
1004/** 1006/**
1005 * Private function which import the given certificate into a gnutls structure. 1007 * Private function which import the given certificate into a gnutls structure.
1006 * 1008 *
1007 * @param crt_name The filename of the certificate to import. 1009 * @param name The name of the certificate to import.
1008 * @param cert the gnutls certificate structure. 1010 * @param cert the gnutls certificate structure.
1009 * 1011 *
1010 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported. 1012 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
1011 */ 1013 */
1012#ifdef HAVE_OPENSSL 1014#ifdef HAVE_OPENSSL
1013static userpref_error_t userpref_import_crt(const char* crt_name, key_data_t* cert) 1015static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, key_data_t* cert)
1014#else 1016#else
1015static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_crt_t cert) 1017static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, gnutls_x509_crt_t cert)
1016#endif 1018#endif
1017{ 1019{
1018#ifdef HAVE_OPENSSL 1020#ifdef HAVE_OPENSSL
@@ -1020,23 +1022,34 @@ static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_cr
1020 return USERPREF_E_SUCCESS; 1022 return USERPREF_E_SUCCESS;
1021#endif 1023#endif
1022 userpref_error_t ret = USERPREF_E_INVALID_CONF; 1024 userpref_error_t ret = USERPREF_E_INVALID_CONF;
1023 key_data_t pem_cert = { NULL, 0 }; 1025 char* buffer = NULL;
1026 uint64_t length = 0;
1024 1027
1025 if (userpref_get_file_contents(crt_name, &pem_cert)) { 1028 plist_t crt = NULL;
1029 if (userpref_device_record_get_value(udid, name, &crt)) {
1030 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
1031 plist_get_data_val(crt, &buffer, &length);
1026#ifdef HAVE_OPENSSL 1032#ifdef HAVE_OPENSSL
1027 cert->data = (unsigned char*)malloc(pem_cert.size); 1033 cert->data = (unsigned char*)malloc(length);
1028 memcpy(cert->data, pem_cert.data, pem_cert.size); 1034 memcpy(cert->data, buffer, length);
1029 cert->size = pem_cert.size; 1035 cert->size = length;
1030 ret = USERPREF_E_SUCCESS;
1031#else
1032 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM))
1033 ret = USERPREF_E_SUCCESS; 1036 ret = USERPREF_E_SUCCESS;
1034 else 1037#else
1035 ret = USERPREF_E_SSL_ERROR; 1038 key_data_t pem = { buffer, length };
1039 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
1040 ret = USERPREF_E_SUCCESS;
1041 else
1042 ret = USERPREF_E_SSL_ERROR;
1036#endif 1043#endif
1044 }
1037 } 1045 }
1038 if (pem_cert.data) 1046
1039 free(pem_cert.data); 1047 if (crt)
1048 plist_free(crt);
1049
1050 if (buffer)
1051 free(buffer);
1052
1040 return ret; 1053 return ret;
1041} 1054}
1042 1055
@@ -1054,41 +1067,40 @@ static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_cr
1054 * @return 1 if the keys and certificates were successfully retrieved, 0 otherwise 1067 * @return 1 if the keys and certificates were successfully retrieved, 0 otherwise
1055 */ 1068 */
1056#ifdef HAVE_OPENSSL 1069#ifdef HAVE_OPENSSL
1057userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt) 1070userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt)
1058#else 1071#else
1059userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt) 1072userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
1060#endif 1073#endif
1061{ 1074{
1062 userpref_error_t ret = USERPREF_E_SUCCESS; 1075 userpref_error_t ret = USERPREF_E_SUCCESS;
1063 1076
1064 if (ret == USERPREF_E_SUCCESS) 1077 if (ret == USERPREF_E_SUCCESS)
1065 ret = userpref_import_key(LIBIMOBILEDEVICE_ROOT_PRIVKEY, root_privkey); 1078 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1066 1079
1067 if (ret == USERPREF_E_SUCCESS) 1080 if (ret == USERPREF_E_SUCCESS)
1068 ret = userpref_import_key(LIBIMOBILEDEVICE_HOST_PRIVKEY, host_privkey); 1081 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1069 1082
1070 if (ret == USERPREF_E_SUCCESS) 1083 if (ret == USERPREF_E_SUCCESS)
1071 ret = userpref_import_crt(LIBIMOBILEDEVICE_ROOT_CERTIF, root_crt); 1084 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt);
1072 1085
1073 if (ret == USERPREF_E_SUCCESS) 1086 if (ret == USERPREF_E_SUCCESS)
1074 ret = userpref_import_crt(LIBIMOBILEDEVICE_HOST_CERTIF, host_crt); 1087 ret = userpref_device_record_import_crt(udid, USERPREF_HOST_CERTIFICATE_KEY, host_crt);
1075 1088
1076 if (USERPREF_E_SUCCESS != ret) { 1089 if (USERPREF_E_SUCCESS != ret) {
1077 //we had problem reading or importing root cert 1090 /* we had problem reading or importing root cert, try with new ones */
1078 //try with a new ones. 1091 ret = userpref_device_record_gen_keys_and_cert(udid);
1079 ret = userpref_gen_keys_and_cert();
1080 1092
1081 if (ret == USERPREF_E_SUCCESS) 1093 if (ret == USERPREF_E_SUCCESS)
1082 ret = userpref_import_key(LIBIMOBILEDEVICE_ROOT_PRIVKEY, root_privkey); 1094 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1083 1095
1084 if (ret == USERPREF_E_SUCCESS) 1096 if (ret == USERPREF_E_SUCCESS)
1085 ret = userpref_import_key(LIBIMOBILEDEVICE_HOST_PRIVKEY, host_privkey); 1097 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1086 1098
1087 if (ret == USERPREF_E_SUCCESS) 1099 if (ret == USERPREF_E_SUCCESS)
1088 ret = userpref_import_crt(LIBIMOBILEDEVICE_ROOT_CERTIF, root_crt); 1100 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt);
1089 1101
1090 if (ret == USERPREF_E_SUCCESS) 1102 if (ret == USERPREF_E_SUCCESS)
1091 ret = userpref_import_crt(LIBIMOBILEDEVICE_HOST_CERTIF, host_crt); 1103 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, host_crt);
1092 } 1104 }
1093 1105
1094 return ret; 1106 return ret;
@@ -1102,14 +1114,36 @@ userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey,
1102 * 1114 *
1103 * @return 1 if the certificates were successfully retrieved, 0 otherwise 1115 * @return 1 if the certificates were successfully retrieved, 0 otherwise
1104 */ 1116 */
1105userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert) 1117userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert)
1106{ 1118{
1107 if (!pem_root_cert || !pem_host_cert) 1119 if (!udid || !pem_root_cert || !pem_host_cert)
1108 return USERPREF_E_INVALID_ARG; 1120 return USERPREF_E_INVALID_ARG;
1109 1121
1110 if (userpref_get_file_contents(LIBIMOBILEDEVICE_ROOT_CERTIF, pem_root_cert) && userpref_get_file_contents(LIBIMOBILEDEVICE_HOST_CERTIF, pem_host_cert)) 1122 char* buffer = NULL;
1123 uint64_t length = 0;
1124 plist_t root_cert = NULL;
1125 plist_t host_cert = NULL;
1126 if (userpref_device_record_get_value(udid, USERPREF_HOST_CERTIFICATE_KEY, &host_cert) &&
1127 userpref_device_record_get_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert)) {
1128 if (host_cert && plist_get_node_type(host_cert) == PLIST_DATA) {
1129 plist_get_data_val(host_cert, &buffer, &length);
1130 pem_host_cert->data = (unsigned char*)malloc(length);
1131 memcpy(pem_host_cert->data, buffer, length);
1132 pem_host_cert->size = length;
1133 free(buffer);
1134 buffer = NULL;
1135 }
1136 if (root_cert && plist_get_node_type(root_cert) == PLIST_DATA) {
1137 plist_get_data_val(root_cert, &buffer, &length);
1138 pem_root_cert->data = (unsigned char*)malloc(length);
1139 memcpy(pem_root_cert->data, buffer, length);
1140 pem_root_cert->size = length;
1141 free(buffer);
1142 buffer = NULL;
1143 }
1144
1111 return USERPREF_E_SUCCESS; 1145 return USERPREF_E_SUCCESS;
1112 else { 1146 } else {
1113 if (pem_root_cert->data) { 1147 if (pem_root_cert->data) {
1114 free(pem_root_cert->data); 1148 free(pem_root_cert->data);
1115 pem_root_cert->size = 0; 1149 pem_root_cert->size = 0;
@@ -1119,7 +1153,9 @@ userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t
1119 pem_host_cert->size = 0; 1153 pem_host_cert->size = 0;
1120 } 1154 }
1121 } 1155 }
1156
1122 debug_info("configuration invalid"); 1157 debug_info("configuration invalid");
1158
1123 return USERPREF_E_INVALID_CONF; 1159 return USERPREF_E_INVALID_CONF;
1124} 1160}
1125 1161
@@ -1135,81 +1171,27 @@ userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t
1135 * 1171 *
1136 * @return 1 on success and 0 otherwise. 1172 * @return 1 on success and 0 otherwise.
1137 */ 1173 */
1138userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert) 1174userpref_error_t userpref_device_record_set_keys_and_certs(const char* udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert)
1139{ 1175{
1140 FILE *pFile;
1141 char *pem;
1142 const char *config_path;
1143 userpref_error_t ret = USERPREF_E_SUCCESS; 1176 userpref_error_t ret = USERPREF_E_SUCCESS;
1144 1177
1145 debug_info("saving keys and certs"); 1178 debug_info("saving keys and certs for udid %s", udid);
1146 1179
1147 if (!root_key || !host_key || !root_cert || !host_cert) { 1180 if (!root_key || !host_key || !root_cert || !host_cert) {
1148 debug_info("missing key or cert (root_key=%p, host_key=%p, root=cert=%p, host_cert=%p", root_key, host_key, root_cert, host_cert); 1181 debug_info("missing key or cert (root_key=%p, host_key=%p, root=cert=%p, host_cert=%p", root_key, host_key, root_cert, host_cert);
1149 return USERPREF_E_INVALID_ARG; 1182 return USERPREF_E_INVALID_ARG;
1150 } 1183 }
1151 1184
1152 /* Make sure config directory exists */ 1185 /* now write keys and certificates to disk */
1153 userpref_create_config_dir(); 1186 if (userpref_device_record_set_value(udid, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_key->data, host_key->size)) &&
1154 1187 userpref_device_record_set_value(udid, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)host_cert->data, host_cert->size)) &&
1155 config_path = userpref_get_config_dir(); 1188 userpref_device_record_set_value(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_key->data, root_key->size)) &&
1156 1189 userpref_device_record_set_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)root_cert->data, root_cert->size)))
1157 /* Now write keys and certificates to disk */ 1190 {
1158 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_ROOT_PRIVKEY)+1); 1191 ret = USERPREF_E_SUCCESS;
1159 strcpy(pem, config_path);
1160 strcat(pem, DIR_SEP_S);
1161 strcat(pem, LIBIMOBILEDEVICE_ROOT_PRIVKEY);
1162 pFile = fopen(pem, "wb");
1163 if (pFile) {
1164 fwrite(root_key->data, 1, root_key->size, pFile);
1165 fclose(pFile);
1166 } else {
1167 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1168 ret = USERPREF_E_WRITE_ERROR;
1169 }
1170 free(pem);
1171
1172 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_HOST_PRIVKEY)+1);
1173 strcpy(pem, config_path);
1174 strcat(pem, DIR_SEP_S);
1175 strcat(pem, LIBIMOBILEDEVICE_HOST_PRIVKEY);
1176 pFile = fopen(pem, "wb");
1177 if (pFile) {
1178 fwrite(host_key->data, 1, host_key->size, pFile);
1179 fclose(pFile);
1180 } else {
1181 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1182 ret = USERPREF_E_WRITE_ERROR;
1183 }
1184 free(pem);
1185
1186 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_ROOT_CERTIF)+1);
1187 strcpy(pem, config_path);
1188 strcat(pem, DIR_SEP_S);
1189 strcat(pem, LIBIMOBILEDEVICE_ROOT_CERTIF);
1190 pFile = fopen(pem, "wb");
1191 if (pFile) {
1192 fwrite(root_cert->data, 1, root_cert->size, pFile);
1193 fclose(pFile);
1194 } else {
1195 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1196 ret = USERPREF_E_WRITE_ERROR;
1197 }
1198 free(pem);
1199
1200 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_HOST_CERTIF)+1);
1201 strcpy(pem, config_path);
1202 strcat(pem, DIR_SEP_S);
1203 strcat(pem, LIBIMOBILEDEVICE_HOST_CERTIF);
1204 pFile = fopen(pem, "wb");
1205 if (pFile) {
1206 fwrite(host_cert->data, 1, host_cert->size, pFile);
1207 fclose(pFile);
1208 } else { 1192 } else {
1209 debug_info("could not open '%s' for writing: %s", pem, strerror(errno)); 1193 ret = 1;
1210 ret = USERPREF_E_WRITE_ERROR;
1211 } 1194 }
1212 free(pem);
1213 1195
1214 return ret; 1196 return ret;
1215} 1197}
diff --git a/common/userpref.h b/common/userpref.h
index 14db985..f59e5fe 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -37,6 +37,17 @@ typedef gnutls_datum_t key_data_t;
37#endif 37#endif
38 38
39#include <stdint.h> 39#include <stdint.h>
40#include <plist/plist.h>
41
42#define USERPREF_DEVICE_CERTIFICATE_KEY "DeviceCertificate"
43#define USERPREF_ESCROW_BAG_KEY "EscrowBag"
44#define USERPREF_HOST_CERTIFICATE_KEY "HostCertificate"
45#define USERPREF_ROOT_CERTIFICATE_KEY "RootCertificate"
46#define USERPREF_HOST_PRIVATE_KEY_KEY "HostPrivateKey"
47#define USERPREF_ROOT_PRIVATE_KEY_KEY "RootPrivateKey"
48#define USERPREF_HOST_ID_KEY "HostID"
49#define USERPREF_SYSTEM_BUID_KEY "SystemBUID"
50#define USERPREF_WIFI_MAC_ADDRESS_KEY "WiFiMACAddress"
40 51
41#ifndef LIBIMOBILEDEVICE_INTERNAL 52#ifndef LIBIMOBILEDEVICE_INTERNAL
42#ifdef WIN32 53#ifdef WIN32
@@ -58,16 +69,25 @@ typedef gnutls_datum_t key_data_t;
58typedef int16_t userpref_error_t; 69typedef int16_t userpref_error_t;
59 70
60#ifdef HAVE_OPENSSL 71#ifdef HAVE_OPENSSL
61LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt); 72LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt);
62#else 73#else
63LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt); 74LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt);
64#endif 75#endif
65LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert); 76LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_set_keys_and_certs(const char *udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert);
66LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert); 77LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert);
67LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_public_key(const char *udid, key_data_t public_key); 78
68userpref_error_t userpref_remove_device_public_key(const char *udid); 79LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record);
69LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_public_key(const char *udid); 80userpref_error_t userpref_remove_device_record(const char *udid);
81LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_record(const char *udid);
82
70userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count); 83userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count);
71void userpref_get_host_id(char **host_id); 84void userpref_device_record_get_host_id(const char *udid, char **host_id);
85void userpref_get_system_buid(char **system_buid);
86
87userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record);
88int userpref_get_value(const char *key, plist_t *value);
89int userpref_set_value(const char *key, plist_t value);
90int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value);
91int userpref_device_record_set_value(const char *udid, const char *key, plist_t value);
72 92
73#endif 93#endif
diff --git a/include/libimobiledevice/lockdown.h b/include/libimobiledevice/lockdown.h
index 8d1b324..233c796 100644
--- a/include/libimobiledevice/lockdown.h
+++ b/include/libimobiledevice/lockdown.h
@@ -52,6 +52,8 @@ extern "C" {
52#define LOCKDOWN_E_INVALID_HOST_ID -16 52#define LOCKDOWN_E_INVALID_HOST_ID -16
53#define LOCKDOWN_E_INVALID_SERVICE -17 53#define LOCKDOWN_E_INVALID_SERVICE -17
54#define LOCKDOWN_E_INVALID_ACTIVATION_RECORD -18 54#define LOCKDOWN_E_INVALID_ACTIVATION_RECORD -18
55#define LOCKDOWN_E_PAIRING_DIALOG_PENDING -20
56#define LOCKDOWN_E_USER_DENIED_PAIRING -21
55 57
56#define LOCKDOWN_E_UNKNOWN_ERROR -256 58#define LOCKDOWN_E_UNKNOWN_ERROR -256
57/*@}*/ 59/*@}*/
@@ -65,8 +67,9 @@ typedef lockdownd_client_private *lockdownd_client_t; /**< The client handle. */
65struct lockdownd_pair_record { 67struct lockdownd_pair_record {
66 char *device_certificate; /**< The device certificate */ 68 char *device_certificate; /**< The device certificate */
67 char *host_certificate; /**< The host certificate */ 69 char *host_certificate; /**< The host certificate */
68 char *host_id; /**< A unique HostID for the host computer */
69 char *root_certificate; /**< The root certificate */ 70 char *root_certificate; /**< The root certificate */
71 char *host_id; /**< A unique HostID for the host computer */
72 char *system_buid; /**< A unique system id */
70}; 73};
71/** A pair record holding device, host and root certificates along the host_id */ 74/** A pair record holding device, host and root certificates along the host_id */
72typedef struct lockdownd_pair_record *lockdownd_pair_record_t; 75typedef struct lockdownd_pair_record *lockdownd_pair_record_t;
diff --git a/src/idevice.c b/src/idevice.c
index c605da3..4a6f544 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -668,7 +668,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
668 key_data_t root_cert = { NULL, 0 }; 668 key_data_t root_cert = { NULL, 0 };
669 key_data_t root_privkey = { NULL, 0 }; 669 key_data_t root_privkey = { NULL, 0 };
670 670
671 userpref_error_t uerr = userpref_get_keys_and_certs(&root_privkey, &root_cert, NULL, NULL); 671 userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, &root_privkey, &root_cert, NULL, NULL);
672 if (uerr != USERPREF_E_SUCCESS) { 672 if (uerr != USERPREF_E_SUCCESS) {
673 debug_info("Error %d when loading keys and certificates! %d", uerr); 673 debug_info("Error %d when loading keys and certificates! %d", uerr);
674 } 674 }
diff --git a/src/lockdown.c b/src/lockdown.c
index b07366b..7c516c1 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -30,6 +30,7 @@
30#define __USE_GNU 1 30#define __USE_GNU 1
31#include <stdio.h> 31#include <stdio.h>
32#include <ctype.h> 32#include <ctype.h>
33#include <unistd.h>
33#ifdef HAVE_OPENSSL 34#ifdef HAVE_OPENSSL
34#include <openssl/pem.h> 35#include <openssl/pem.h>
35#include <openssl/x509.h> 36#include <openssl/x509.h>
@@ -47,6 +48,11 @@
47#include "common/userpref.h" 48#include "common/userpref.h"
48#include "asprintf.h" 49#include "asprintf.h"
49 50
51#ifdef WIN32
52#include <windows.h>
53#define sleep(x) Sleep(x*1000)
54#endif
55
50#define RESULT_SUCCESS 0 56#define RESULT_SUCCESS 0
51#define RESULT_FAILURE 1 57#define RESULT_FAILURE 1
52 58
@@ -209,28 +215,18 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *
209 return ret; 215 return ret;
210} 216}
211 217
212/** 218static lockdownd_error_t lockdownd_client_free_simple(lockdownd_client_t client)
213 * Closes the lockdownd client session if one is running and frees up the
214 * lockdownd_client struct.
215 *
216 * @param client The lockdown client
217 *
218 * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
219 */
220lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
221{ 219{
222 if (!client) 220 if (!client)
223 return LOCKDOWN_E_INVALID_ARG; 221 return LOCKDOWN_E_INVALID_ARG;
222
224 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 223 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
225 224
226 if (client->session_id) { 225 if (client->session_id) {
227 lockdownd_stop_session(client, client->session_id);
228 free(client->session_id); 226 free(client->session_id);
229 } 227 }
230 228
231 if (client->parent) { 229 if (client->parent) {
232 lockdownd_goodbye(client);
233
234 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) { 230 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
235 ret = LOCKDOWN_E_SUCCESS; 231 ret = LOCKDOWN_E_SUCCESS;
236 } 232 }
@@ -244,6 +240,36 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
244 } 240 }
245 241
246 free(client); 242 free(client);
243
244 return ret;
245}
246
247/**
248 * Closes the lockdownd client session if one is running and frees up the
249 * lockdownd_client struct.
250 *
251 * @param client The lockdown client
252 *
253 * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
254 */
255lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
256{
257 if (!client)
258 return LOCKDOWN_E_INVALID_ARG;
259
260 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
261
262
263 if (client->session_id) {
264 lockdownd_stop_session(client, client->session_id);
265 }
266
267 if (client->parent) {
268 lockdownd_goodbye(client);
269 }
270
271 ret = lockdownd_client_free_simple(client);
272
247 return ret; 273 return ret;
248} 274}
249 275
@@ -674,6 +700,33 @@ lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *cli
674 return LOCKDOWN_E_SUCCESS; 700 return LOCKDOWN_E_SUCCESS;
675} 701}
676 702
703static lockdownd_error_t lockdownd_client_reconnect(idevice_t device, lockdownd_client_t *client, const char *label)
704{
705 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
706 int attempts = 3;
707 char *udid = NULL;
708
709 /* free resources of lockownd_client */
710 ret = lockdownd_client_free_simple(*client);
711 *client = NULL;
712
713 /* try to reconnect */
714 do {
715 debug_info("reconnecting to udid %s, %d remaining attempts", udid, attempts);
716 ret = lockdownd_client_new(device, client, label);
717 if (ret == LOCKDOWN_E_SUCCESS) {
718 debug_info("reconnected to lockdownd with err %d", ret);
719 break;
720 }
721 sleep(1);
722 } while(attempts--);
723
724 free(udid);
725 udid = NULL;
726
727 return ret;
728}
729
677/** 730/**
678 * Creates a new lockdownd client for the device and starts initial handshake. 731 * Creates a new lockdownd client for the device and starts initial handshake.
679 * The handshake consists out of query_type, validate_pair, pair and 732 * The handshake consists out of query_type, validate_pair, pair and
@@ -698,8 +751,10 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
698 751
699 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 752 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
700 lockdownd_client_t client_loc = NULL; 753 lockdownd_client_t client_loc = NULL;
754 char *system_buid = NULL;
701 char *host_id = NULL; 755 char *host_id = NULL;
702 char *type = NULL; 756 char *type = NULL;
757 int product_version_major = 0;
703 758
704 ret = lockdownd_client_new(device, &client_loc, label); 759 ret = lockdownd_client_new(device, &client_loc, label);
705 if (LOCKDOWN_E_SUCCESS != ret) { 760 if (LOCKDOWN_E_SUCCESS != ret) {
@@ -719,22 +774,55 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
719 free(type); 774 free(type);
720 } 775 }
721 776
722 userpref_get_host_id(&host_id); 777 /* get product version */
778 plist_t product_version_node = NULL;
779 char* product_version = NULL;
780 lockdownd_get_value(client_loc, NULL, "ProductVersion", &product_version_node);
781 if (product_version_node && plist_get_node_type(product_version_node) == PLIST_STRING) {
782 plist_get_string_val(product_version_node, &product_version);
783 product_version_major = strtol(product_version, NULL, 10);
784 }
785
786 if (product_version_major >= 7) {
787 userpref_get_system_buid(&system_buid);
788
789 /* set our BUID for the trust dialog so the next pairing can succeed */
790 lockdownd_set_value(client_loc, NULL, "UntrustedHostBUID", plist_new_string(system_buid));
791 free(system_buid);
792 system_buid = NULL;
793 }
794
795 userpref_device_record_get_host_id(client_loc->udid, &host_id);
723 if (LOCKDOWN_E_SUCCESS == ret && !host_id) { 796 if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
724 ret = LOCKDOWN_E_INVALID_CONF; 797 ret = LOCKDOWN_E_INVALID_CONF;
725 } 798 }
726 799
727 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->udid)) 800 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_record(client_loc->udid)) {
801 /* attempt pairing */
728 ret = lockdownd_pair(client_loc, NULL); 802 ret = lockdownd_pair(client_loc, NULL);
729 803
804 if (ret == LOCKDOWN_E_SUCCESS && product_version_major >= 7) {
805 /* the trust dialog was dissmissed, thus the device will reconnect after pairing */
806 lockdownd_client_reconnect(device, &client_loc, label);
807 }
808 }
809
730 /* in any case, we need to validate pairing to receive trusted host status */ 810 /* in any case, we need to validate pairing to receive trusted host status */
731 ret = lockdownd_validate_pair(client_loc, NULL); 811 ret = lockdownd_validate_pair(client_loc, NULL);
732 812
733 /* if not paired yet, let's do it now */ 813 /* if not paired yet, let's do it now */
734 if (LOCKDOWN_E_INVALID_HOST_ID == ret) { 814 if (LOCKDOWN_E_INVALID_HOST_ID == ret) {
735 ret = lockdownd_pair(client_loc, NULL); 815 ret = lockdownd_pair(client_loc, NULL);
816
817 if (ret == LOCKDOWN_E_SUCCESS && product_version_major >= 7) {
818 /* the trust dialog was dissmissed, thus the device will reconnect after pairing */
819 lockdownd_client_reconnect(device, &client_loc, label);
820 }
821
736 if (LOCKDOWN_E_SUCCESS == ret) { 822 if (LOCKDOWN_E_SUCCESS == ret) {
737 ret = lockdownd_validate_pair(client_loc, NULL); 823 ret = lockdownd_validate_pair(client_loc, NULL);
824 } else if (LOCKDOWN_E_PAIRING_DIALOG_PENDING == ret) {
825 debug_info("Device shows the pairing dialog.");
738 } 826 }
739 } 827 }
740 828
@@ -772,19 +860,13 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor
772 if (!pair_record) 860 if (!pair_record)
773 return NULL; 861 return NULL;
774 862
775 char *host_id_loc = pair_record->host_id;
776
777 /* setup request plist */ 863 /* setup request plist */
778 plist_t dict = plist_new_dict(); 864 plist_t dict = plist_new_dict();
779 plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate))); 865 plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate)));
780 plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate))); 866 plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate)));
781 if (!pair_record->host_id) 867 plist_dict_insert_item(dict, "HostID", plist_new_string(pair_record->host_id));
782 userpref_get_host_id(&host_id_loc);
783 plist_dict_insert_item(dict, "HostID", plist_new_string(host_id_loc));
784 plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate))); 868 plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate)));
785 869 plist_dict_insert_item(dict, "SystemBUID", plist_new_string(pair_record->system_buid));
786 if (!pair_record->host_id)
787 free(host_id_loc);
788 870
789 return dict; 871 return dict;
790} 872}
@@ -800,7 +882,7 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor
800 * 882 *
801 * @return LOCKDOWN_E_SUCCESS on success 883 * @return LOCKDOWN_E_SUCCESS on success
802 */ 884 */
803static lockdownd_error_t generate_pair_record_plist(key_data_t public_key, char *host_id, plist_t *pair_record_plist) 885static lockdownd_error_t generate_pair_record_plist(const char *udid, char* system_buid, char *host_id, key_data_t public_key, plist_t *pair_record_plist)
804{ 886{
805 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 887 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
806 888
@@ -808,25 +890,18 @@ static lockdownd_error_t generate_pair_record_plist(key_data_t public_key, char
808 key_data_t host_cert = { NULL, 0 }; 890 key_data_t host_cert = { NULL, 0 };
809 key_data_t root_cert = { NULL, 0 }; 891 key_data_t root_cert = { NULL, 0 };
810 892
811 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); 893 ret = lockdownd_gen_pair_cert_for_udid(udid, public_key, &device_cert, &host_cert, &root_cert);
812 if (ret != LOCKDOWN_E_SUCCESS) { 894 if (ret != LOCKDOWN_E_SUCCESS) {
813 return ret; 895 return ret;
814 } 896 }
815 897
816 char *host_id_loc = host_id;
817
818 if (!host_id)
819 userpref_get_host_id(&host_id_loc);
820
821 /* setup request plist */ 898 /* setup request plist */
822 *pair_record_plist = plist_new_dict(); 899 *pair_record_plist = plist_new_dict();
823 plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); 900 plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
824 plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); 901 plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
825 plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id_loc)); 902 plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id));
826 plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); 903 plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
827 904 plist_dict_insert_item(*pair_record_plist, "SystemBUID", plist_new_string(system_buid));
828 if (!host_id)
829 free(host_id_loc);
830 905
831 if (device_cert.data) 906 if (device_cert.data)
832 free(device_cert.data); 907 free(device_cert.data);
@@ -863,8 +938,10 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
863 plist_t dict_record = NULL; 938 plist_t dict_record = NULL;
864 key_data_t public_key = { NULL, 0 }; 939 key_data_t public_key = { NULL, 0 };
865 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */ 940 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */
941 char* host_id = NULL;
942 char* system_buid = NULL;
866 943
867 if (pair_record && pair_record->host_id) { 944 if (pair_record && pair_record->system_buid && pair_record->host_id) {
868 /* valid pair_record passed? */ 945 /* valid pair_record passed? */
869 if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) { 946 if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) {
870 return LOCKDOWN_E_PLIST_ERROR; 947 return LOCKDOWN_E_PLIST_ERROR;
@@ -883,34 +960,73 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
883 return ret; 960 return ret;
884 } 961 }
885 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data); 962 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);
963
886 /* get libimobiledevice pair_record */ 964 /* get libimobiledevice pair_record */
887 ret = generate_pair_record_plist(public_key, NULL, &dict_record); 965 userpref_get_system_buid(&system_buid);
966 userpref_device_record_get_host_id(client->udid, &host_id);
967 userpref_device_record_set_value(client->udid, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));
968
969 ret = generate_pair_record_plist(client->udid, system_buid, host_id, public_key, &dict_record);
970
971 if (host_id)
972 free(host_id);
973 if (system_buid)
974 free(system_buid);
975
888 if (ret != LOCKDOWN_E_SUCCESS) { 976 if (ret != LOCKDOWN_E_SUCCESS) {
977 if (public_key.data)
978 free(public_key.data);
889 if (dict_record) 979 if (dict_record)
890 plist_free(dict_record); 980 plist_free(dict_record);
891 return ret; 981 return ret;
892 } 982 }
893 } 983 }
894 984
895 /* Setup Pair request plist */ 985 if (!strcmp("Pair", verb)) {
986 /* get wifi mac */
987 plist_t wifi_mac_node = NULL;
988 lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_mac_node);
989
990 /* save wifi mac address in config */
991 if (wifi_mac_node) {
992 userpref_device_record_set_value(client->udid, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_mac_node));
993 plist_free(wifi_mac_node);
994 wifi_mac_node = NULL;
995 }
996 }
997
998 /* setup pair request plist */
896 dict = plist_new_dict(); 999 dict = plist_new_dict();
897 plist_dict_add_label(dict, client->label); 1000 plist_dict_add_label(dict, client->label);
898 plist_dict_insert_item(dict,"PairRecord", dict_record); 1001 plist_dict_insert_item(dict, "PairRecord", plist_copy(dict_record));
899 plist_dict_insert_item(dict, "Request", plist_new_string(verb)); 1002 plist_dict_insert_item(dict, "Request", plist_new_string(verb));
1003 plist_dict_insert_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION));
1004
1005 plist_t options = plist_new_dict();
1006 plist_dict_insert_item(options, "ExtendedPairingErrors", plist_new_bool(1));
1007 plist_dict_insert_item(dict, "PairingOptions", options);
900 1008
901 /* send to device */ 1009 /* send to device */
902 ret = lockdownd_send(client, dict); 1010 ret = lockdownd_send(client, dict);
903 plist_free(dict); 1011 plist_free(dict);
904 dict = NULL; 1012 dict = NULL;
905 1013
906 if (ret != LOCKDOWN_E_SUCCESS) 1014 if (ret != LOCKDOWN_E_SUCCESS) {
1015 if (public_key.data)
1016 free(public_key.data);
1017 plist_free(dict_record);
907 return ret; 1018 return ret;
1019 }
908 1020
909 /* Now get device's answer */ 1021 /* Now get device's answer */
910 ret = lockdownd_receive(client, &dict); 1022 ret = lockdownd_receive(client, &dict);
911 1023
912 if (ret != LOCKDOWN_E_SUCCESS) 1024 if (ret != LOCKDOWN_E_SUCCESS) {
1025 if (public_key.data)
1026 free(public_key.data);
1027 plist_free(dict_record);
913 return ret; 1028 return ret;
1029 }
914 1030
915 if (strcmp(verb, "Unpair") == 0) { 1031 if (strcmp(verb, "Unpair") == 0) {
916 /* workaround for Unpair giving back ValidatePair, 1032 /* workaround for Unpair giving back ValidatePair,
@@ -928,13 +1044,25 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
928 if (ret == LOCKDOWN_E_SUCCESS) { 1044 if (ret == LOCKDOWN_E_SUCCESS) {
929 debug_info("%s success", verb); 1045 debug_info("%s success", verb);
930 if (!pairing_mode) { 1046 if (!pairing_mode) {
1047 debug_info("internal pairing mode");
931 if (!strcmp("Unpair", verb)) { 1048 if (!strcmp("Unpair", verb)) {
932 /* remove public key from config */ 1049 /* remove public key from config */
933 userpref_remove_device_public_key(client->udid); 1050 userpref_remove_device_record(client->udid);
934 } else { 1051 } else {
935 /* store public key in config */ 1052 if (!strcmp("Pair", verb)) {
936 userpref_set_device_public_key(client->udid, public_key); 1053 debug_info("getting EscrowBag from response");
1054
1055 /* add returned escrow bag if available */
1056 plist_t escrow_bag = plist_dict_get_item(dict, "EscrowBag");
1057 if (escrow_bag && plist_get_node_type(escrow_bag) == PLIST_DATA) {
1058 userpref_device_record_set_value(client->udid, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag));
1059 plist_free(escrow_bag);
1060 escrow_bag = NULL;
1061 }
1062 }
937 } 1063 }
1064 } else {
1065 debug_info("external pairing mode");
938 } 1066 }
939 } else { 1067 } else {
940 debug_info("%s failure", verb); 1068 debug_info("%s failure", verb);
@@ -950,6 +1078,10 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
950 ret = LOCKDOWN_E_PASSWORD_PROTECTED; 1078 ret = LOCKDOWN_E_PASSWORD_PROTECTED;
951 } else if (!strcmp(value, "InvalidHostID")) { 1079 } else if (!strcmp(value, "InvalidHostID")) {
952 ret = LOCKDOWN_E_INVALID_HOST_ID; 1080 ret = LOCKDOWN_E_INVALID_HOST_ID;
1081 } else if (!strcmp(value, "UserDeniedPairing")) {
1082 ret = LOCKDOWN_E_USER_DENIED_PAIRING;
1083 } else if (!strcmp(value, "PairingDialogResponsePending")) {
1084 ret = LOCKDOWN_E_PAIRING_DIALOG_PENDING;
953 } 1085 }
954 free(value); 1086 free(value);
955 } 1087 }
@@ -958,10 +1090,18 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
958 error_node = NULL; 1090 error_node = NULL;
959 } 1091 }
960 } 1092 }
1093
1094 if (dict_record) {
1095 plist_free(dict_record);
1096 dict_record = NULL;
1097 }
1098
961 plist_free(dict); 1099 plist_free(dict);
962 dict = NULL; 1100 dict = NULL;
1101
963 if (public_key.data) 1102 if (public_key.data)
964 free(public_key.data); 1103 free(public_key.data);
1104
965 return ret; 1105 return ret;
966} 1106}
967 1107
@@ -1115,11 +1255,12 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
1115 * system failed, LOCKDOWN_E_SSL_ERROR if the certificates could not be 1255 * system failed, LOCKDOWN_E_SSL_ERROR if the certificates could not be
1116 * generated 1256 * generated
1117 */ 1257 */
1118lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * odevice_cert, 1258lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * odevice_cert,
1119 key_data_t * ohost_cert, key_data_t * oroot_cert) 1259 key_data_t * ohost_cert, key_data_t * oroot_cert)
1120{ 1260{
1121 if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert) 1261 if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert)
1122 return LOCKDOWN_E_INVALID_ARG; 1262 return LOCKDOWN_E_INVALID_ARG;
1263
1123 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 1264 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1124 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR; 1265 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
1125 1266
@@ -1148,7 +1289,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * od
1148 host_privkey.data = NULL; 1289 host_privkey.data = NULL;
1149 host_privkey.size = 0; 1290 host_privkey.size = 0;
1150 1291
1151 uret = userpref_get_keys_and_certs(&root_privkey, &root_cert, &host_privkey, &host_cert); 1292 uret = userpref_device_record_get_keys_and_certs(udid, &root_privkey, &root_cert, &host_privkey, &host_cert);
1152 if (USERPREF_E_SUCCESS == uret) { 1293 if (USERPREF_E_SUCCESS == uret) {
1153 /* generate device certificate */ 1294 /* generate device certificate */
1154 ASN1_INTEGER* sn = ASN1_INTEGER_new(); 1295 ASN1_INTEGER* sn = ASN1_INTEGER_new();
@@ -1209,7 +1350,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * od
1209 key_data_t pem_root_cert = { NULL, 0 }; 1350 key_data_t pem_root_cert = { NULL, 0 };
1210 key_data_t pem_host_cert = { NULL, 0 }; 1351 key_data_t pem_host_cert = { NULL, 0 };
1211 1352
1212 uret = userpref_get_certs_as_pem(&pem_root_cert, &pem_host_cert); 1353 uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert);
1213 if (USERPREF_E_SUCCESS == uret) { 1354 if (USERPREF_E_SUCCESS == uret) {
1214 /* copy buffer for output */ 1355 /* copy buffer for output */
1215 membp = BIO_new(BIO_s_mem()); 1356 membp = BIO_new(BIO_s_mem());
@@ -1395,6 +1536,10 @@ lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * od
1395 1536
1396 gnutls_free(der_pub_key.data); 1537 gnutls_free(der_pub_key.data);
1397#endif 1538#endif
1539 /* save device cert in config */
1540 if (odevice_cert->size) {
1541 userpref_device_record_set_value(udid, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data((char*)odevice_cert->data, (uint64_t)odevice_cert->size));
1542 }
1398 1543
1399 return ret; 1544 return ret;
1400} 1545}
@@ -1429,9 +1574,24 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char
1429 /* setup request plist */ 1574 /* setup request plist */
1430 dict = plist_new_dict(); 1575 dict = plist_new_dict();
1431 plist_dict_add_label(dict, client->label); 1576 plist_dict_add_label(dict, client->label);
1432 plist_dict_insert_item(dict,"HostID", plist_new_string(host_id));
1433 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); 1577 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
1434 1578
1579 /* add host id */
1580 if (host_id) {
1581 plist_dict_insert_item(dict, "HostID", plist_new_string(host_id));
1582 }
1583
1584 /* add system buid */
1585 char *system_buid = NULL;
1586 userpref_get_system_buid(&system_buid);
1587 if (system_buid) {
1588 plist_dict_insert_item(dict, "SystemBUID", plist_new_string(system_buid));
1589 if (system_buid) {
1590 free(system_buid);
1591 system_buid = NULL;
1592 }
1593 }
1594
1435 ret = lockdownd_send(client, dict); 1595 ret = lockdownd_send(client, dict);
1436 plist_free(dict); 1596 plist_free(dict);
1437 dict = NULL; 1597 dict = NULL;
@@ -1471,6 +1631,7 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char
1471 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { 1631 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
1472 plist_get_string_val(session_node, &client->session_id); 1632 plist_get_string_val(session_node, &client->session_id);
1473 } 1633 }
1634
1474 if (client->session_id) { 1635 if (client->session_id) {
1475 debug_info("SessionID: %s", client->session_id); 1636 debug_info("SessionID: %s", client->session_id);
1476 if (session_id != NULL) 1637 if (session_id != NULL)
@@ -1478,7 +1639,9 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char
1478 } else { 1639 } else {
1479 debug_info("Failed to get SessionID!"); 1640 debug_info("Failed to get SessionID!");
1480 } 1641 }
1642
1481 debug_info("Enable SSL Session: %s", (use_ssl?"true":"false")); 1643 debug_info("Enable SSL Session: %s", (use_ssl?"true":"false"));
1644
1482 if (use_ssl) { 1645 if (use_ssl) {
1483 ret = property_list_service_enable_ssl(client->parent); 1646 ret = property_list_service_enable_ssl(client->parent);
1484 if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) { 1647 if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) {
@@ -1523,7 +1686,7 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1523 } 1686 }
1524 1687
1525 char *host_id = NULL; 1688 char *host_id = NULL;
1526 userpref_get_host_id(&host_id); 1689 userpref_device_record_get_host_id(client->udid, &host_id);
1527 if (!host_id) 1690 if (!host_id)
1528 return LOCKDOWN_E_INVALID_CONF; 1691 return LOCKDOWN_E_INVALID_CONF;
1529 if (!client->session_id) 1692 if (!client->session_id)
diff --git a/src/lockdown.h b/src/lockdown.h
index 30ebc15..9c2be44 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -27,6 +27,8 @@
27#include "libimobiledevice/lockdown.h" 27#include "libimobiledevice/lockdown.h"
28#include "property_list_service.h" 28#include "property_list_service.h"
29 29
30#define LOCKDOWN_PROTOCOL_VERSION "2"
31
30struct lockdownd_client_private { 32struct lockdownd_client_private {
31 property_list_service_client_t parent; 33 property_list_service_client_t parent;
32 int ssl_enabled; 34 int ssl_enabled;
@@ -36,6 +38,6 @@ struct lockdownd_client_private {
36}; 38};
37 39
38lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key); 40lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key);
39lockdownd_error_t lockdownd_gen_pair_cert(key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert); 41lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert);
40 42
41#endif 43#endif