summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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