diff options
| author | 2010-01-12 17:17:48 +0100 | |
|---|---|---|
| committer | 2010-01-12 17:17:48 +0100 | |
| commit | 219a8db037ec1cc163d2ad4902e6e4578040a2de (patch) | |
| tree | 2084e1b9bd0b3666042ce0a1cf2c68f6d8650ee5 /src/lockdown.c | |
| parent | e7884c40d73e25ee6e6addb3f9d9efc0ffbe068e (diff) | |
| download | libimobiledevice-219a8db037ec1cc163d2ad4902e6e4578040a2de.tar.gz libimobiledevice-219a8db037ec1cc163d2ad4902e6e4578040a2de.tar.bz2 | |
Refactor lockdown session handling and expose it in public API
This splits out SSL code and allows implementations to manually handle
session start and stop if needed. Also brings the API closer to the
lockdown request protocol.
Diffstat (limited to 'src/lockdown.c')
| -rw-r--r-- | src/lockdown.c | 434 |
1 files changed, 218 insertions, 216 deletions
diff --git a/src/lockdown.c b/src/lockdown.c index 11b4fe6..f78fbb4 100644 --- a/src/lockdown.c +++ b/src/lockdown.c | |||
| @@ -123,69 +123,145 @@ static void plist_dict_add_label(plist_t plist, const char *label) | |||
| 123 | } | 123 | } |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | /** | 126 | /** gnutls callback for writing data to the device. |
| 127 | * Closes the lockdownd communication session, by sending | ||
| 128 | * the StopSession Request to the device. | ||
| 129 | * | 127 | * |
| 130 | * @param control The lockdown client | 128 | * @param transport It's really the lockdownd client, but the method signature has to match |
| 129 | * @param buffer The data to send | ||
| 130 | * @param length The length of data to send in bytes | ||
| 131 | * | 131 | * |
| 132 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | 132 | * @return The number of bytes sent |
| 133 | */ | 133 | */ |
| 134 | lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) | 134 | static ssize_t lockdownd_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length) |
| 135 | { | 135 | { |
| 136 | if (!client) | 136 | uint32_t bytes = 0; |
| 137 | return LOCKDOWN_E_INVALID_ARG; | 137 | lockdownd_client_t client; |
| 138 | client = (lockdownd_client_t) transport; | ||
| 139 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length); | ||
| 140 | iphone_device_send(property_list_service_get_connection(client->parent), buffer, length, &bytes); | ||
| 141 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes); | ||
| 142 | return bytes; | ||
| 143 | } | ||
| 138 | 144 | ||
| 139 | if (!client->session_id) { | 145 | /** gnutls callback for reading data from the device. |
| 140 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); | 146 | * |
| 141 | return LOCKDOWN_E_INVALID_ARG; | 147 | * @param transport It's really the lockdownd client, but the method signature has to match |
| 142 | } | 148 | * @param buffer The buffer to store data in |
| 149 | * @param length The length of data to read in bytes | ||
| 150 | * | ||
| 151 | * @return The number of bytes read | ||
| 152 | */ | ||
| 153 | static ssize_t lockdownd_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length) | ||
| 154 | { | ||
| 155 | int bytes = 0, pos_start_fill = 0; | ||
| 156 | size_t tbytes = 0; | ||
| 157 | int this_len = length; | ||
| 158 | iphone_error_t res; | ||
| 159 | lockdownd_client_t client; | ||
| 160 | client = (lockdownd_client_t) transport; | ||
| 161 | char *recv_buffer; | ||
| 143 | 162 | ||
| 144 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 163 | log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length); |
| 145 | 164 | ||
| 146 | plist_t dict = plist_new_dict(); | 165 | recv_buffer = (char *) malloc(sizeof(char) * this_len); |
| 147 | plist_dict_add_label(dict, client->label); | ||
| 148 | plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); | ||
| 149 | plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); | ||
| 150 | 166 | ||
| 151 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); | 167 | /* repeat until we have the full data or an error occurs */ |
| 168 | do { | ||
| 169 | if ((res = iphone_device_recv(property_list_service_get_connection(client->parent), recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { | ||
| 170 | log_debug_msg("%s: ERROR: iphone_device_recv returned %d\n", __func__, res); | ||
| 171 | return res; | ||
| 172 | } | ||
| 173 | log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes); | ||
| 152 | 174 | ||
| 153 | ret = lockdownd_send(client, dict); | 175 | // increase read count |
| 176 | tbytes += bytes; | ||
| 154 | 177 | ||
| 155 | plist_free(dict); | 178 | // fill the buffer with what we got right now |
| 156 | dict = NULL; | 179 | memcpy(buffer + pos_start_fill, recv_buffer, bytes); |
| 180 | pos_start_fill += bytes; | ||
| 157 | 181 | ||
| 158 | ret = lockdownd_recv(client, &dict); | 182 | if (tbytes >= length) { |
| 183 | break; | ||
| 184 | } | ||
| 159 | 185 | ||
| 160 | if (!dict) { | 186 | this_len = length - tbytes; |
| 161 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); | 187 | log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len); |
| 162 | return LOCKDOWN_E_PLIST_ERROR; | 188 | } while (tbytes < length); |
| 189 | |||
| 190 | if (recv_buffer) { | ||
| 191 | free(recv_buffer); | ||
| 163 | } | 192 | } |
| 164 | 193 | ||
| 165 | ret = LOCKDOWN_E_UNKNOWN_ERROR; | 194 | return tbytes; |
| 166 | if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { | 195 | } |
| 167 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); | 196 | |
| 197 | /** Starts communication with lockdownd after the iPhone has been paired, | ||
| 198 | * and if the device requires it, switches to SSL mode. | ||
| 199 | * | ||
| 200 | * @param client The lockdownd client | ||
| 201 | * | ||
| 202 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | ||
| 203 | */ | ||
| 204 | static lockdownd_error_t lockdownd_ssl_start_session(lockdownd_client_t client) | ||
| 205 | { | ||
| 206 | lockdownd_error_t ret = LOCKDOWN_E_SSL_ERROR; | ||
| 207 | uint32_t return_me = 0; | ||
| 208 | |||
| 209 | // Set up GnuTLS... | ||
| 210 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: enabling SSL mode\n", __func__); | ||
| 211 | errno = 0; | ||
| 212 | gnutls_global_init(); | ||
| 213 | gnutls_certificate_allocate_credentials(&client->ssl_certificate); | ||
| 214 | gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); | ||
| 215 | gnutls_init(&client->ssl_session, GNUTLS_CLIENT); | ||
| 216 | { | ||
| 217 | int protocol_priority[16] = { GNUTLS_SSL3, 0 }; | ||
| 218 | int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; | ||
| 219 | int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; | ||
| 220 | int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; | ||
| 221 | int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; | ||
| 222 | |||
| 223 | gnutls_cipher_set_priority(client->ssl_session, cipher_priority); | ||
| 224 | gnutls_compression_set_priority(client->ssl_session, comp_priority); | ||
| 225 | gnutls_kx_set_priority(client->ssl_session, kx_priority); | ||
| 226 | gnutls_protocol_set_priority(client->ssl_session, protocol_priority); | ||
| 227 | gnutls_mac_set_priority(client->ssl_session, mac_priority); | ||
| 228 | } | ||
| 229 | gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate); // this part is killing me. | ||
| 230 | |||
| 231 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); | ||
| 232 | gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); | ||
| 233 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__); | ||
| 234 | gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_ssl_write); | ||
| 235 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__); | ||
| 236 | gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_ssl_read); | ||
| 237 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__); | ||
| 238 | if (errno) | ||
| 239 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno)); | ||
| 240 | return_me = gnutls_handshake(client->ssl_session); | ||
| 241 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__); | ||
| 242 | |||
| 243 | if (return_me != GNUTLS_E_SUCCESS) { | ||
| 244 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__); | ||
| 245 | gnutls_perror(return_me); | ||
| 246 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno)); | ||
| 247 | } else { | ||
| 248 | client->ssl_enabled = 1; | ||
| 168 | ret = LOCKDOWN_E_SUCCESS; | 249 | ret = LOCKDOWN_E_SUCCESS; |
| 250 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SSL mode enabled\n", __func__); | ||
| 169 | } | 251 | } |
| 170 | plist_free(dict); | ||
| 171 | dict = NULL; | ||
| 172 | |||
| 173 | free(client->session_id); | ||
| 174 | client->session_id = NULL; | ||
| 175 | 252 | ||
| 176 | return ret; | 253 | return ret; |
| 177 | } | 254 | } |
| 178 | 255 | ||
| 179 | /** | 256 | /** |
| 180 | * Shuts down the SSL session by first calling iphone_lckd_stop_session | 257 | * Shuts down the SSL session by performing a close notify, which is done |
| 181 | * to cleanly close the lockdownd communication session, and then | 258 | * by "gnutls_bye". |
| 182 | * performing a close notify, which is done by "gnutls_bye". | ||
| 183 | * | 259 | * |
| 184 | * @param client The lockdown client | 260 | * @param client The lockdown client |
| 185 | * | 261 | * |
| 186 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | 262 | * @return an error code (LOCKDOWN_E_SUCCESS on success) |
| 187 | */ | 263 | */ |
| 188 | static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) | 264 | static lockdownd_error_t lockdownd_ssl_stop_session(lockdownd_client_t client) |
| 189 | { | 265 | { |
| 190 | if (!client) { | 266 | if (!client) { |
| 191 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__); | 267 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__); |
| @@ -194,19 +270,79 @@ static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) | |||
| 194 | lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; | 270 | lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; |
| 195 | 271 | ||
| 196 | if (client->ssl_enabled) { | 272 | if (client->ssl_enabled) { |
| 197 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); | ||
| 198 | ret = lockdownd_stop_session(client); | ||
| 199 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); | 273 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); |
| 200 | gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); | 274 | gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); |
| 201 | } | 275 | } |
| 202 | if (client->ssl_session) { | 276 | if (client->ssl_session) { |
| 203 | gnutls_deinit(client->ssl_session); | 277 | gnutls_deinit(client->ssl_session); |
| 204 | } | 278 | } |
| 205 | if (client->ssl_certificate) { | 279 | if (client->ssl_certificate) { |
| 206 | gnutls_certificate_free_credentials(client->ssl_certificate); | 280 | gnutls_certificate_free_credentials(client->ssl_certificate); |
| 207 | } | 281 | } |
| 208 | client->ssl_enabled = 0; | 282 | client->ssl_enabled = 0; |
| 209 | 283 | ||
| 284 | if (client->session_id) | ||
| 285 | free(client->session_id); | ||
| 286 | client->session_id = NULL; | ||
| 287 | |||
| 288 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SSL mode disabled\n", __func__); | ||
| 289 | |||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Closes the lockdownd communication session, by sending the StopSession | ||
| 295 | * Request to the device. | ||
| 296 | * | ||
| 297 | * @see lockdownd_start_session | ||
| 298 | * | ||
| 299 | * @param control The lockdown client | ||
| 300 | * @param session_id The id of a running session | ||
| 301 | * | ||
| 302 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | ||
| 303 | */ | ||
| 304 | lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) | ||
| 305 | { | ||
| 306 | if (!client) | ||
| 307 | return LOCKDOWN_E_INVALID_ARG; | ||
| 308 | |||
| 309 | if (!session_id) { | ||
| 310 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); | ||
| 311 | return LOCKDOWN_E_INVALID_ARG; | ||
| 312 | } | ||
| 313 | |||
| 314 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | ||
| 315 | |||
| 316 | plist_t dict = plist_new_dict(); | ||
| 317 | plist_dict_add_label(dict, client->label); | ||
| 318 | plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); | ||
| 319 | plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id)); | ||
| 320 | |||
| 321 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, session_id); | ||
| 322 | |||
| 323 | ret = lockdownd_send(client, dict); | ||
| 324 | |||
| 325 | plist_free(dict); | ||
| 326 | dict = NULL; | ||
| 327 | |||
| 328 | ret = lockdownd_recv(client, &dict); | ||
| 329 | |||
| 330 | if (!dict) { | ||
| 331 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); | ||
| 332 | return LOCKDOWN_E_PLIST_ERROR; | ||
| 333 | } | ||
| 334 | |||
| 335 | ret = LOCKDOWN_E_UNKNOWN_ERROR; | ||
| 336 | if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { | ||
| 337 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); | ||
| 338 | ret = LOCKDOWN_E_SUCCESS; | ||
| 339 | } | ||
| 340 | plist_free(dict); | ||
| 341 | dict = NULL; | ||
| 342 | |||
| 343 | /* stop ssl session */ | ||
| 344 | lockdownd_ssl_stop_session(client); | ||
| 345 | |||
| 210 | return ret; | 346 | return ret; |
| 211 | } | 347 | } |
| 212 | 348 | ||
| @@ -222,7 +358,8 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) | |||
| 222 | return LOCKDOWN_E_INVALID_ARG; | 358 | return LOCKDOWN_E_INVALID_ARG; |
| 223 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 359 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; |
| 224 | 360 | ||
| 225 | lockdownd_stop_ssl_session(client); | 361 | if (client->session_id) |
| 362 | lockdownd_stop_session(client, client->session_id); | ||
| 226 | 363 | ||
| 227 | if (client->parent) { | 364 | if (client->parent) { |
| 228 | lockdownd_goodbye(client); | 365 | lockdownd_goodbye(client); |
| @@ -232,9 +369,6 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) | |||
| 232 | } | 369 | } |
| 233 | } | 370 | } |
| 234 | 371 | ||
| 235 | if (client->session_id) { | ||
| 236 | free(client->session_id); | ||
| 237 | } | ||
| 238 | if (client->uuid) { | 372 | if (client->uuid) { |
| 239 | free(client->uuid); | 373 | free(client->uuid); |
| 240 | } | 374 | } |
| @@ -712,7 +846,7 @@ lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lo | |||
| 712 | ret = lockdownd_validate_pair(client_loc, host_id); | 846 | ret = lockdownd_validate_pair(client_loc, host_id); |
| 713 | 847 | ||
| 714 | if (LOCKDOWN_E_SUCCESS == ret) { | 848 | if (LOCKDOWN_E_SUCCESS == ret) { |
| 715 | ret = lockdownd_start_ssl_session(client_loc, host_id); | 849 | ret = lockdownd_start_session(client_loc, host_id, NULL, NULL); |
| 716 | if (LOCKDOWN_E_SUCCESS != ret) { | 850 | if (LOCKDOWN_E_SUCCESS != ret) { |
| 717 | ret = LOCKDOWN_E_SSL_ERROR; | 851 | ret = LOCKDOWN_E_SSL_ERROR; |
| 718 | log_debug_msg("%s: SSL Session opening failed.\n", __func__); | 852 | log_debug_msg("%s: SSL Session opening failed.\n", __func__); |
| @@ -1012,7 +1146,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu | |||
| 1012 | asn1_delete_structure(&pkcs1); | 1146 | asn1_delete_structure(&pkcs1); |
| 1013 | } | 1147 | } |
| 1014 | 1148 | ||
| 1015 | /* now generate certifcates */ | 1149 | /* now generate certificates */ |
| 1016 | if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { | 1150 | if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { |
| 1017 | 1151 | ||
| 1018 | gnutls_global_init(); | 1152 | gnutls_global_init(); |
| @@ -1106,22 +1240,26 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu | |||
| 1106 | * and if the device requires it, switches to SSL mode. | 1240 | * and if the device requires it, switches to SSL mode. |
| 1107 | * | 1241 | * |
| 1108 | * @param client The lockdownd client | 1242 | * @param client The lockdownd client |
| 1109 | * @param HostID The HostID used with this phone | 1243 | * @param host_id The HostID of the computer |
| 1244 | * @param session_id The session_id of the created session | ||
| 1245 | * @param ssl_enabled Whether SSL communication is used in the session | ||
| 1110 | * | 1246 | * |
| 1111 | * @return an error code (LOCKDOWN_E_SUCCESS on success) | 1247 | * @return an error code (LOCKDOWN_E_SUCCESS on success) |
| 1112 | */ | 1248 | */ |
| 1113 | lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *host_id) | 1249 | lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) |
| 1114 | { | 1250 | { |
| 1251 | lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; | ||
| 1115 | plist_t dict = NULL; | 1252 | plist_t dict = NULL; |
| 1116 | uint32_t return_me = 0; | ||
| 1117 | 1253 | ||
| 1118 | lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; | 1254 | if (!client || !host_id) |
| 1255 | ret = LOCKDOWN_E_INVALID_ARG; | ||
| 1256 | |||
| 1257 | /* if we have a running session, stop current one first */ | ||
| 1119 | if (client->session_id) { | 1258 | if (client->session_id) { |
| 1120 | free(client->session_id); | 1259 | lockdownd_stop_session(client, client->session_id); |
| 1121 | client->session_id = NULL; | ||
| 1122 | } | 1260 | } |
| 1123 | 1261 | ||
| 1124 | /* Setup DevicePublicKey request plist */ | 1262 | /* setup request plist */ |
| 1125 | dict = plist_new_dict(); | 1263 | dict = plist_new_dict(); |
| 1126 | plist_dict_add_label(dict, client->label); | 1264 | plist_dict_add_label(dict, client->label); |
| 1127 | plist_dict_insert_item(dict,"HostID", plist_new_string(host_id)); | 1265 | plist_dict_insert_item(dict,"HostID", plist_new_string(host_id)); |
| @@ -1144,184 +1282,48 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c | |||
| 1144 | if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { | 1282 | if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { |
| 1145 | char *error = NULL; | 1283 | char *error = NULL; |
| 1146 | plist_get_string_val(error_node, &error); | 1284 | plist_get_string_val(error_node, &error); |
| 1147 | |||
| 1148 | if (!strcmp(error, "InvalidHostID")) { | 1285 | if (!strcmp(error, "InvalidHostID")) { |
| 1149 | /* hostid is unknown. Pair and try again */ | 1286 | ret = LOCKDOWN_E_INVALID_HOST_ID; |
| 1150 | char *host_id_new = NULL; | ||
| 1151 | userpref_get_host_id(&host_id_new); | ||
| 1152 | |||
| 1153 | if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id_new) ) { | ||
| 1154 | /* start session again */ | ||
| 1155 | plist_free(dict); | ||
| 1156 | dict = plist_new_dict(); | ||
| 1157 | plist_dict_add_label(dict, client->label); | ||
| 1158 | plist_dict_insert_item(dict,"HostID", plist_new_string(host_id_new)); | ||
| 1159 | plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); | ||
| 1160 | |||
| 1161 | ret = lockdownd_send(client, dict); | ||
| 1162 | plist_free(dict); | ||
| 1163 | dict = NULL; | ||
| 1164 | |||
| 1165 | ret = lockdownd_recv(client, &dict); | ||
| 1166 | } | ||
| 1167 | free(host_id_new); | ||
| 1168 | } | 1287 | } |
| 1169 | free(error); | 1288 | free(error); |
| 1170 | } | 1289 | } |
| 1171 | } | 1290 | } else { |
| 1172 | 1291 | uint8_t use_ssl = 0; | |
| 1173 | ret = LOCKDOWN_E_SSL_ERROR; | ||
| 1174 | |||
| 1175 | int session_ok = 0; | ||
| 1176 | uint8_t UseSSL = 0; | ||
| 1177 | 1292 | ||
| 1178 | if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) { | ||
| 1179 | plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); | 1293 | plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); |
| 1180 | if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { | 1294 | if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { |
| 1181 | plist_get_bool_val(enable_ssl, &UseSSL); | 1295 | plist_get_bool_val(enable_ssl, &use_ssl); |
| 1182 | } | 1296 | } |
| 1183 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); | 1297 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); |
| 1184 | session_ok = 1; | 1298 | |
| 1185 | } | 1299 | if (ssl_enabled != NULL) |
| 1186 | if (session_ok && !UseSSL) { | 1300 | *ssl_enabled = use_ssl; |
| 1187 | client->ssl_enabled = 0; | 1301 | |
| 1188 | ret = LOCKDOWN_E_SUCCESS; | 1302 | /* store session id, we need it for StopSession */ |
| 1189 | } else if (session_ok) { | 1303 | plist_t session_node = plist_dict_get_item(dict, "SessionID"); |
| 1190 | // Set up GnuTLS... | 1304 | if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { |
| 1191 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); | 1305 | plist_get_string_val(session_node, &client->session_id); |
| 1192 | errno = 0; | ||
| 1193 | gnutls_global_init(); | ||
| 1194 | //gnutls_anon_allocate_client_credentials(&anoncred); | ||
| 1195 | gnutls_certificate_allocate_credentials(&client->ssl_certificate); | ||
| 1196 | gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM); | ||
| 1197 | gnutls_init(&client->ssl_session, GNUTLS_CLIENT); | ||
| 1198 | { | ||
| 1199 | int protocol_priority[16] = { GNUTLS_SSL3, 0 }; | ||
| 1200 | int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; | ||
| 1201 | int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; | ||
| 1202 | int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; | ||
| 1203 | int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; | ||
| 1204 | |||
| 1205 | gnutls_cipher_set_priority(client->ssl_session, cipher_priority); | ||
| 1206 | gnutls_compression_set_priority(client->ssl_session, comp_priority); | ||
| 1207 | gnutls_kx_set_priority(client->ssl_session, kx_priority); | ||
| 1208 | gnutls_protocol_set_priority(client->ssl_session, protocol_priority); | ||
| 1209 | gnutls_mac_set_priority(client->ssl_session, mac_priority); | ||
| 1210 | } | 1306 | } |
| 1211 | gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate); // this part is killing me. | 1307 | if (client->session_id) { |
| 1212 | 1308 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); | |
| 1213 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); | 1309 | if (session_id != NULL) |
| 1214 | gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); | 1310 | *session_id = strdup(client->session_id); |
| 1215 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__); | ||
| 1216 | gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_secuwrite); | ||
| 1217 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__); | ||
| 1218 | gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_securead); | ||
| 1219 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__); | ||
| 1220 | if (errno) | ||
| 1221 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno)); | ||
| 1222 | return_me = gnutls_handshake(client->ssl_session); | ||
| 1223 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__); | ||
| 1224 | |||
| 1225 | if (return_me != GNUTLS_E_SUCCESS) { | ||
| 1226 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__); | ||
| 1227 | gnutls_perror(return_me); | ||
| 1228 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno)); | ||
| 1229 | return LOCKDOWN_E_SSL_ERROR; | ||
| 1230 | } else { | 1311 | } else { |
| 1231 | client->ssl_enabled = 1; | 1312 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); |
| 1313 | } | ||
| 1314 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Enable SSL Session: %s\n", __func__, (use_ssl?"true":"false")); | ||
| 1315 | if (use_ssl) { | ||
| 1316 | ret = lockdownd_ssl_start_session(client); | ||
| 1317 | } else { | ||
| 1318 | client->ssl_enabled = 0; | ||
| 1232 | ret = LOCKDOWN_E_SUCCESS; | 1319 | ret = LOCKDOWN_E_SUCCESS; |
| 1233 | } | 1320 | } |
| 1234 | } | 1321 | } |
| 1235 | /* store session id, we need it for StopSession */ | 1322 | |
| 1236 | plist_t session_node = plist_dict_get_item(dict, "SessionID"); | ||
| 1237 | if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { | ||
| 1238 | plist_get_string_val(session_node, &client->session_id); | ||
| 1239 | } | ||
| 1240 | if (client->session_id) { | ||
| 1241 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); | ||
| 1242 | } else { | ||
| 1243 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); | ||
| 1244 | } | ||
| 1245 | plist_free(dict); | 1323 | plist_free(dict); |
| 1246 | dict = NULL; | 1324 | dict = NULL; |
| 1247 | 1325 | ||
| 1248 | if (ret == LOCKDOWN_E_SUCCESS) | 1326 | return ret; |
| 1249 | return ret; | ||
| 1250 | |||
| 1251 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Apparently failed negotiating with lockdownd.\n", __func__); | ||
| 1252 | return LOCKDOWN_E_SSL_ERROR; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /** gnutls callback for writing data to the iPhone. | ||
| 1256 | * | ||
| 1257 | * @param transport It's really the lockdownd client, but the method signature has to match | ||
| 1258 | * @param buffer The data to send | ||
| 1259 | * @param length The length of data to send in bytes | ||
| 1260 | * | ||
| 1261 | * @return The number of bytes sent | ||
| 1262 | */ | ||
| 1263 | ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) | ||
| 1264 | { | ||
| 1265 | uint32_t bytes = 0; | ||
| 1266 | lockdownd_client_t client; | ||
| 1267 | client = (lockdownd_client_t) transport; | ||
| 1268 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); | ||
| 1269 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length); | ||
| 1270 | iphone_device_send(property_list_service_get_connection(client->parent), buffer, length, &bytes); | ||
| 1271 | log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes); | ||
| 1272 | return bytes; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | /** gnutls callback for reading data from the iPhone | ||
| 1276 | * | ||
| 1277 | * @param transport It's really the lockdownd client, but the method signature has to match | ||
| 1278 | * @param buffer The buffer to store data in | ||
| 1279 | * @param length The length of data to read in bytes | ||
| 1280 | * | ||
| 1281 | * @return The number of bytes read | ||
| 1282 | */ | ||
| 1283 | ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) | ||
| 1284 | { | ||
| 1285 | int bytes = 0, pos_start_fill = 0; | ||
| 1286 | size_t tbytes = 0; | ||
| 1287 | int this_len = length; | ||
| 1288 | iphone_error_t res; | ||
| 1289 | lockdownd_client_t client; | ||
| 1290 | client = (lockdownd_client_t) transport; | ||
| 1291 | char *recv_buffer; | ||
| 1292 | |||
| 1293 | log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length); | ||
| 1294 | |||
| 1295 | recv_buffer = (char *) malloc(sizeof(char) * this_len); | ||
| 1296 | |||
| 1297 | // repeat until we have the full data or an error occurs. | ||
| 1298 | do { | ||
| 1299 | if ((res = iphone_device_recv(property_list_service_get_connection(client->parent), recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) { | ||
| 1300 | log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res); | ||
| 1301 | return res; | ||
| 1302 | } | ||
| 1303 | log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes); | ||
| 1304 | |||
| 1305 | // increase read count | ||
| 1306 | tbytes += bytes; | ||
| 1307 | |||
| 1308 | // fill the buffer with what we got right now | ||
| 1309 | memcpy(buffer + pos_start_fill, recv_buffer, bytes); | ||
| 1310 | pos_start_fill += bytes; | ||
| 1311 | |||
| 1312 | if (tbytes >= length) { | ||
| 1313 | break; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | this_len = length - tbytes; | ||
| 1317 | log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len); | ||
| 1318 | } while (tbytes < length); | ||
| 1319 | |||
| 1320 | if (recv_buffer) { | ||
| 1321 | free(recv_buffer); | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | return tbytes; | ||
| 1325 | } | 1327 | } |
| 1326 | 1328 | ||
| 1327 | /** Command to start the desired service | 1329 | /** Command to start the desired service |
