summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2010-01-12 17:17:48 +0100
committerGravatar Martin Szulecki2010-01-12 17:17:48 +0100
commit219a8db037ec1cc163d2ad4902e6e4578040a2de (patch)
tree2084e1b9bd0b3666042ce0a1cf2c68f6d8650ee5 /src
parente7884c40d73e25ee6e6addb3f9d9efc0ffbe068e (diff)
downloadlibimobiledevice-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')
-rw-r--r--src/lockdown.c434
-rw-r--r--src/lockdown.h6
2 files changed, 218 insertions, 222 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 */
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