diff options
Diffstat (limited to 'src/lockdown.c')
| -rw-r--r-- | src/lockdown.c | 164 |
1 files changed, 105 insertions, 59 deletions
diff --git a/src/lockdown.c b/src/lockdown.c index b182706..fb5f8f5 100644 --- a/src/lockdown.c +++ b/src/lockdown.c | |||
| @@ -115,18 +115,23 @@ static int lockdown_check_result(plist_t dict, const char *query_match) | |||
| 115 | * | 115 | * |
| 116 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | 116 | * @return an error code (LOCKDOWN_E_SUCCESS on success) |
| 117 | */ | 117 | */ |
| 118 | lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) | 118 | lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) |
| 119 | { | 119 | { |
| 120 | if (!client) | 120 | if (!client) |
| 121 | return LOCKDOWN_E_INVALID_ARG; | 121 | return LOCKDOWN_E_INVALID_ARG; |
| 122 | 122 | ||
| 123 | if (!client->session_id) { | ||
| 124 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); | ||
| 125 | return LOCKDOWN_E_INVALID_ARG; | ||
| 126 | } | ||
| 127 | |||
| 123 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 128 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; |
| 124 | 129 | ||
| 125 | plist_t dict = plist_new_dict(); | 130 | plist_t dict = plist_new_dict(); |
| 126 | plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); | 131 | plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); |
| 127 | plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id)); | 132 | plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); |
| 128 | 133 | ||
| 129 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); | 134 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); |
| 130 | 135 | ||
| 131 | ret = lockdownd_send(client, dict); | 136 | ret = lockdownd_send(client, dict); |
| 132 | 137 | ||
| @@ -148,6 +153,9 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char * | |||
| 148 | plist_free(dict); | 153 | plist_free(dict); |
| 149 | dict = NULL; | 154 | dict = NULL; |
| 150 | 155 | ||
| 156 | free(client->session_id); | ||
| 157 | client->session_id = NULL; | ||
| 158 | |||
| 151 | return ret; | 159 | return ret; |
| 152 | } | 160 | } |
| 153 | 161 | ||
| @@ -170,7 +178,7 @@ static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) | |||
| 170 | 178 | ||
| 171 | if (client->in_SSL) { | 179 | if (client->in_SSL) { |
| 172 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); | 180 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); |
| 173 | ret = lockdownd_stop_session(client, client->session_id); | 181 | ret = lockdownd_stop_session(client); |
| 174 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); | 182 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); |
| 175 | gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); | 183 | gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); |
| 176 | } | 184 | } |
| @@ -209,6 +217,13 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) | |||
| 209 | } | 217 | } |
| 210 | } | 218 | } |
| 211 | 219 | ||
| 220 | if (client->session_id) { | ||
| 221 | free(client->session_id); | ||
| 222 | } | ||
| 223 | if (client->uuid) { | ||
| 224 | free(client->uuid); | ||
| 225 | } | ||
| 226 | |||
| 212 | free(client); | 227 | free(client); |
| 213 | return ret; | 228 | return ret; |
| 214 | } | 229 | } |
| @@ -642,31 +657,27 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ | |||
| 642 | client_loc->ssl_session = NULL; | 657 | client_loc->ssl_session = NULL; |
| 643 | client_loc->ssl_certificate = NULL; | 658 | client_loc->ssl_certificate = NULL; |
| 644 | client_loc->in_SSL = 0; | 659 | client_loc->in_SSL = 0; |
| 660 | client_loc->session_id = NULL; | ||
| 661 | client_loc->uuid = NULL; | ||
| 645 | 662 | ||
| 646 | if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { | 663 | if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { |
| 647 | log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); | 664 | log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); |
| 648 | ret = LOCKDOWN_E_NOT_ENOUGH_DATA; | 665 | ret = LOCKDOWN_E_NOT_ENOUGH_DATA; |
| 649 | } | 666 | } |
| 650 | 667 | ||
| 651 | char *uuid = NULL; | 668 | ret = iphone_device_get_uuid(device, &client_loc->uuid); |
| 652 | ret = iphone_device_get_uuid(device, &uuid); | ||
| 653 | if (LOCKDOWN_E_SUCCESS != ret) { | 669 | if (LOCKDOWN_E_SUCCESS != ret) { |
| 654 | log_debug_msg("%s: failed to get device uuid.\n", __func__); | 670 | log_debug_msg("%s: failed to get device uuid.\n", __func__); |
| 655 | } | 671 | } |
| 656 | log_debug_msg("%s: device uuid: %s\n", __func__, uuid); | 672 | log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); |
| 657 | 673 | ||
| 658 | userpref_get_host_id(&host_id); | 674 | userpref_get_host_id(&host_id); |
| 659 | if (LOCKDOWN_E_SUCCESS == ret && !host_id) { | 675 | if (LOCKDOWN_E_SUCCESS == ret && !host_id) { |
| 660 | ret = LOCKDOWN_E_INVALID_CONF; | 676 | ret = LOCKDOWN_E_INVALID_CONF; |
| 661 | } | 677 | } |
| 662 | 678 | ||
| 663 | if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(uuid)) | 679 | if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) |
| 664 | ret = lockdownd_pair(client_loc, uuid, host_id); | 680 | ret = lockdownd_pair(client_loc, host_id); |
| 665 | |||
| 666 | if (uuid) { | ||
| 667 | free(uuid); | ||
| 668 | uuid = NULL; | ||
| 669 | } | ||
| 670 | 681 | ||
| 671 | if (LOCKDOWN_E_SUCCESS == ret) { | 682 | if (LOCKDOWN_E_SUCCESS == ret) { |
| 672 | ret = lockdownd_start_ssl_session(client_loc, host_id); | 683 | ret = lockdownd_start_ssl_session(client_loc, host_id); |
| @@ -687,12 +698,17 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ | |||
| 687 | return ret; | 698 | return ret; |
| 688 | } | 699 | } |
| 689 | 700 | ||
| 690 | /** Generates the appropriate keys and pairs the device. It's part of the | 701 | /** Function used internally by lockdownd_pair() and lockdownd_validate_pair() |
| 691 | * lockdownd handshake. | 702 | * |
| 703 | * @param client The lockdown client to pair with. | ||
| 704 | * @param host_id The HostID to use for pairing. If NULL is passed, then | ||
| 705 | * the HostID of the current machine is used. A new HostID will be | ||
| 706 | * generated automatically when pairing is done for the first time. | ||
| 707 | * @param verb This is either "Pair" or "ValidatePair". | ||
| 692 | * | 708 | * |
| 693 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | 709 | * @return an error code (LOCKDOWN_E_SUCCESS on success) |
| 694 | */ | 710 | */ |
| 695 | lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *host_id) | 711 | static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) |
| 696 | { | 712 | { |
| 697 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 713 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; |
| 698 | plist_t dict = NULL; | 714 | plist_t dict = NULL; |
| @@ -703,6 +719,8 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho | |||
| 703 | gnutls_datum_t root_cert = { NULL, 0 }; | 719 | gnutls_datum_t root_cert = { NULL, 0 }; |
| 704 | gnutls_datum_t public_key = { NULL, 0 }; | 720 | gnutls_datum_t public_key = { NULL, 0 }; |
| 705 | 721 | ||
| 722 | char *host_id_loc = host_id; | ||
| 723 | |||
| 706 | ret = lockdownd_get_device_public_key(client, &public_key); | 724 | ret = lockdownd_get_device_public_key(client, &public_key); |
| 707 | if (ret != LOCKDOWN_E_SUCCESS) { | 725 | if (ret != LOCKDOWN_E_SUCCESS) { |
| 708 | log_debug_msg("%s: device refused to send public key.\n", __func__); | 726 | log_debug_msg("%s: device refused to send public key.\n", __func__); |
| @@ -716,6 +734,10 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho | |||
| 716 | return ret; | 734 | return ret; |
| 717 | } | 735 | } |
| 718 | 736 | ||
| 737 | if (!host_id) { | ||
| 738 | userpref_get_host_id(&host_id_loc); | ||
| 739 | } | ||
| 740 | |||
| 719 | /* Setup Pair request plist */ | 741 | /* Setup Pair request plist */ |
| 720 | dict = plist_new_dict(); | 742 | dict = plist_new_dict(); |
| 721 | dict_record = plist_new_dict(); | 743 | dict_record = plist_new_dict(); |
| @@ -723,16 +745,20 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho | |||
| 723 | 745 | ||
| 724 | plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); | 746 | plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); |
| 725 | plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); | 747 | plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); |
| 726 | plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id)); | 748 | plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc)); |
| 727 | plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); | 749 | plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); |
| 728 | 750 | ||
| 729 | plist_dict_insert_item(dict, "Request", plist_new_string("Pair")); | 751 | plist_dict_insert_item(dict, "Request", plist_new_string(verb)); |
| 730 | 752 | ||
| 731 | /* send to iPhone */ | 753 | /* send to iPhone */ |
| 732 | ret = lockdownd_send(client, dict); | 754 | ret = lockdownd_send(client, dict); |
| 733 | plist_free(dict); | 755 | plist_free(dict); |
| 734 | dict = NULL; | 756 | dict = NULL; |
| 735 | 757 | ||
| 758 | if (!host_id) { | ||
| 759 | free(host_id_loc); | ||
| 760 | } | ||
| 761 | |||
| 736 | if (ret != LOCKDOWN_E_SUCCESS) | 762 | if (ret != LOCKDOWN_E_SUCCESS) |
| 737 | return ret; | 763 | return ret; |
| 738 | 764 | ||
| @@ -742,24 +768,56 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho | |||
| 742 | if (ret != LOCKDOWN_E_SUCCESS) | 768 | if (ret != LOCKDOWN_E_SUCCESS) |
| 743 | return ret; | 769 | return ret; |
| 744 | 770 | ||
| 745 | if (lockdown_check_result(dict, "Pair") == RESULT_SUCCESS) { | 771 | if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { |
| 746 | ret = LOCKDOWN_E_SUCCESS; | 772 | ret = LOCKDOWN_E_PAIRING_FAILED; |
| 747 | } | 773 | } |
| 748 | plist_free(dict); | 774 | plist_free(dict); |
| 749 | dict = NULL; | 775 | dict = NULL; |
| 750 | 776 | ||
| 751 | /* store public key in config if pairing succeeded */ | 777 | /* store public key in config if pairing succeeded */ |
| 752 | if (ret == LOCKDOWN_E_SUCCESS) { | 778 | if (ret == LOCKDOWN_E_SUCCESS) { |
| 753 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair success\n", __func__); | 779 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); |
| 754 | userpref_set_device_public_key(uuid, public_key); | 780 | userpref_set_device_public_key(client->uuid, public_key); |
| 755 | } else { | 781 | } else { |
| 756 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair failure\n", __func__); | 782 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); |
| 757 | ret = LOCKDOWN_E_PAIRING_FAILED; | ||
| 758 | } | 783 | } |
| 759 | free(public_key.data); | 784 | free(public_key.data); |
| 760 | return ret; | 785 | return ret; |
| 761 | } | 786 | } |
| 762 | 787 | ||
| 788 | /** | ||
| 789 | * Pairs the device with the given HostID. | ||
| 790 | * It's part of the lockdownd handshake. | ||
| 791 | * | ||
| 792 | * @param client The lockdown client to pair with. | ||
| 793 | * @param host_id The HostID to use for pairing. If NULL is passed, then | ||
| 794 | * the HostID of the current machine is used. A new HostID will be | ||
| 795 | * generated automatically when pairing is done for the first time. | ||
| 796 | * | ||
| 797 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | ||
| 798 | */ | ||
| 799 | lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) | ||
| 800 | { | ||
| 801 | return lockdownd_do_pair(client, host_id, "Pair"); | ||
| 802 | } | ||
| 803 | |||
| 804 | /** | ||
| 805 | * Pairs the device with the given HostID. The difference to lockdownd_pair() | ||
| 806 | * is that the specified host will become trusted host of the device. | ||
| 807 | * It's part of the lockdownd handshake. | ||
| 808 | * | ||
| 809 | * @param client The lockdown client to pair with. | ||
| 810 | * @param host_id The HostID to use for pairing. If NULL is passed, then | ||
| 811 | * the HostID of the current machine is used. A new HostID will be | ||
| 812 | * generated automatically when pairing is done for the first time. | ||
| 813 | * | ||
| 814 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | ||
| 815 | */ | ||
| 816 | lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) | ||
| 817 | { | ||
| 818 | return lockdownd_do_pair(client, host_id, "ValidatePair"); | ||
| 819 | } | ||
| 820 | |||
| 763 | /** | 821 | /** |
| 764 | * Tells the device to immediately enter recovery mode. | 822 | * Tells the device to immediately enter recovery mode. |
| 765 | * | 823 | * |
| @@ -985,7 +1043,10 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c | |||
| 985 | uint32_t return_me = 0; | 1043 | uint32_t return_me = 0; |
| 986 | 1044 | ||
| 987 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 1045 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; |
| 988 | client->session_id[0] = '\0'; | 1046 | if (client->session_id) { |
| 1047 | free(client->session_id); | ||
| 1048 | client->session_id = NULL; | ||
| 1049 | } | ||
| 989 | 1050 | ||
| 990 | /* Setup DevicePublicKey request plist */ | 1051 | /* Setup DevicePublicKey request plist */ |
| 991 | dict = plist_new_dict(); | 1052 | dict = plist_new_dict(); |
| @@ -1012,26 +1073,22 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c | |||
| 1012 | 1073 | ||
| 1013 | if (!strcmp(error, "InvalidHostID")) { | 1074 | if (!strcmp(error, "InvalidHostID")) { |
| 1014 | /* hostid is unknown. Pair and try again */ | 1075 | /* hostid is unknown. Pair and try again */ |
| 1015 | char *uuid = NULL; | ||
| 1016 | char *host_id = NULL; | 1076 | char *host_id = NULL; |
| 1017 | userpref_get_host_id(&host_id); | 1077 | userpref_get_host_id(&host_id); |
| 1018 | 1078 | ||
| 1019 | if (LOCKDOWN_E_SUCCESS == lockdownd_get_device_uuid(client, &uuid) ) { | 1079 | if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) { |
| 1020 | if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, uuid, host_id) ) { | 1080 | /* start session again */ |
| 1021 | /* start session again */ | 1081 | plist_free(dict); |
| 1022 | plist_free(dict); | 1082 | dict = plist_new_dict(); |
| 1023 | dict = plist_new_dict(); | 1083 | plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); |
| 1024 | plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); | 1084 | plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); |
| 1025 | plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); | ||
| 1026 | 1085 | ||
| 1027 | ret = lockdownd_send(client, dict); | 1086 | ret = lockdownd_send(client, dict); |
| 1028 | plist_free(dict); | 1087 | plist_free(dict); |
| 1029 | dict = NULL; | 1088 | dict = NULL; |
| 1030 | 1089 | ||
| 1031 | ret = lockdownd_recv(client, &dict); | 1090 | ret = lockdownd_recv(client, &dict); |
| 1032 | } | ||
| 1033 | } | 1091 | } |
| 1034 | free(uuid); | ||
| 1035 | free(host_id); | 1092 | free(host_id); |
| 1036 | } | 1093 | } |
| 1037 | free(error); | 1094 | free(error); |
| @@ -1100,27 +1157,16 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c | |||
| 1100 | ret = LOCKDOWN_E_SUCCESS; | 1157 | ret = LOCKDOWN_E_SUCCESS; |
| 1101 | } | 1158 | } |
| 1102 | } | 1159 | } |
| 1103 | /* store session id */ | 1160 | /* store session id, we need it for StopSession */ |
| 1104 | plist_t session_node = plist_dict_get_item(dict, "SessionID"); | 1161 | plist_t session_node = plist_dict_get_item(dict, "SessionID"); |
| 1105 | if (session_node) { | 1162 | if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { |
| 1106 | 1163 | plist_get_string_val(session_node, &client->session_id); | |
| 1107 | plist_type session_node_type = plist_get_node_type(session_node); | 1164 | } |
| 1108 | 1165 | if (client->session_id) { | |
| 1109 | if (session_node_type == PLIST_STRING) { | 1166 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); |
| 1110 | 1167 | } else { | |
| 1111 | char *session_id = NULL; | ||
| 1112 | plist_get_string_val(session_node, &session_id); | ||
| 1113 | |||
| 1114 | if (session_node_type == PLIST_STRING && session_id) { | ||
| 1115 | /* we need to store the session ID for StopSession */ | ||
| 1116 | strcpy(client->session_id, session_id); | ||
| 1117 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); | ||
| 1118 | } | ||
| 1119 | if (session_id) | ||
| 1120 | free(session_id); | ||
| 1121 | } | ||
| 1122 | } else | ||
| 1123 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); | 1168 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); |
| 1169 | } | ||
| 1124 | plist_free(dict); | 1170 | plist_free(dict); |
| 1125 | dict = NULL; | 1171 | dict = NULL; |
| 1126 | 1172 | ||
