summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libiphone/lockdown.h13
-rw-r--r--src/lockdown.c434
-rw-r--r--src/lockdown.h6
3 files changed, 227 insertions, 226 deletions
diff --git a/include/libiphone/lockdown.h b/include/libiphone/lockdown.h
index e134f5f..f4b3f6a 100644
--- a/include/libiphone/lockdown.h
+++ b/include/libiphone/lockdown.h
@@ -47,6 +47,7 @@ extern "C" {
47#define LOCKDOWN_E_ACTIVATION_FAILED -13 47#define LOCKDOWN_E_ACTIVATION_FAILED -13
48#define LOCKDOWN_E_PASSWORD_PROTECTED -14 48#define LOCKDOWN_E_PASSWORD_PROTECTED -14
49#define LOCKDOWN_E_NO_RUNNING_SESSION -15 49#define LOCKDOWN_E_NO_RUNNING_SESSION -15
50#define LOCKDOWN_E_INVALID_HOST_ID -16
50 51
51#define LOCKDOWN_E_UNKNOWN_ERROR -256 52#define LOCKDOWN_E_UNKNOWN_ERROR -256
52 53
@@ -59,13 +60,14 @@ typedef struct lockdownd_client_int *lockdownd_client_t;
59lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label); 60lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label);
60lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label); 61lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label);
61lockdownd_error_t lockdownd_client_free(lockdownd_client_t client); 62lockdownd_error_t lockdownd_client_free(lockdownd_client_t client);
62void lockdownd_client_set_label(lockdownd_client_t client, const char *label); 63
63lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type); 64lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type);
64lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value); 65lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value);
65lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value); 66lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *domain, const char *key, plist_t value);
66lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key); 67lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *domain, const char *key);
67lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port); 68lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port);
68lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client); 69lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled);
70lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id);
69lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist); 71lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist);
70lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist); 72lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist);
71lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id); 73lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id);
@@ -73,11 +75,14 @@ lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_
73lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, char *host_id); 75lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, char *host_id);
74lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record); 76lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record);
75lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client); 77lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client);
76lockdownd_error_t lockdownd_get_device_uuid(lockdownd_client_t control, char **uuid);
77lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name);
78lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client); 78lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client);
79lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client); 79lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client);
80 80
81/* Helper */
82void lockdownd_client_set_label(lockdownd_client_t client, const char *label);
83lockdownd_error_t lockdownd_get_device_uuid(lockdownd_client_t control, char **uuid);
84lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **device_name);
85
81#ifdef __cplusplus 86#ifdef __cplusplus
82} 87}
83#endif 88#endif
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 */
134lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) 134static 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 */
153static 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 */
204static 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 */
188static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) 264static 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 */
304lockdownd_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 */
1113lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *host_id) 1249lockdownd_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 */
1263ssize_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 */
1283ssize_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
diff --git a/src/lockdown.h b/src/lockdown.h
index d7a18b5..9da3872 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -42,10 +42,4 @@ lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, gnu
42lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert, 42lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * device_cert,
43 gnutls_datum_t * host_cert, gnutls_datum_t * root_cert); 43 gnutls_datum_t * host_cert, gnutls_datum_t * root_cert);
44 44
45/* SSL functions */
46lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *host_id);
47ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length);
48ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length);
49
50
51#endif 45#endif