From 15b9f3451e20ccb4f9c6cdadc0dd75bc72246360 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 29 Nov 2009 16:04:18 +0100 Subject: Evaluate EnableSessionSSL key on session startup This is required if the device does not send the EnableSessionSSL:true key-value pair in the answer to the StartSession request. [#92 state:resolved] Signed-off-by: Matt Colyer --- src/lockdown.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index d147f75..b182706 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -971,7 +971,8 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu return ret; } -/** Starts SSL communication with lockdownd after the iPhone has been paired. +/** Starts communication with lockdownd after the iPhone has been paired, + * and if the device requires it, switches to SSL mode. * * @param client The lockdownd client * @param HostID The HostID used with this phone @@ -1038,9 +1039,24 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c } ret = LOCKDOWN_E_SSL_ERROR; + + int session_ok = 0; + uint8_t UseSSL = 0; + if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) { + plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); + if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { + plist_get_bool_val(enable_ssl, &UseSSL); + } + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); + session_ok = 1; + } + if (session_ok && !UseSSL) { + client->in_SSL = 0; + ret = LOCKDOWN_E_SUCCESS; + } else if (session_ok) { // Set up GnuTLS... - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: started the session OK, now trying GnuTLS\n", __func__); + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); errno = 0; gnutls_global_init(); //gnutls_anon_allocate_client_credentials(&anoncred); -- cgit v1.1-32-gdbae From 213025d04ae8788be393b63e245f2805386f7f8a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 18:07:56 +0100 Subject: fix signature of lockdownd_stop_session This removes the session_id parameter from lockdownd_stop_session because the session_id is stored in the lockdownd_client_int structure anyway. --- src/lockdown.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index b182706..afca410 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -115,7 +115,7 @@ static int lockdown_check_result(plist_t dict, const char *query_match) * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) +lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -124,7 +124,7 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char * plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); - plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id)); + plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); @@ -170,7 +170,7 @@ static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client) if (client->in_SSL) { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__); - ret = lockdownd_stop_session(client, client->session_id); + ret = lockdownd_stop_session(client); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__); gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR); } -- cgit v1.1-32-gdbae From ea45a41a7987ab1d05e2160ce831d2fcff695077 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 18:13:21 +0100 Subject: better handling of session_id This will change session_id out of the lockdownd_client_int struct to a pointer instead of using a buffer of fixed size. The session_id is allocated anyway by libplist when reading it from the plist received from the device, so why don't just use it? [#94 state:resolved] Signed-off-by: Matt Colyer --- src/lockdown.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index afca410..6bf4c84 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -120,13 +120,18 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) if (!client) return LOCKDOWN_E_INVALID_ARG; + if (!client->session_id) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); + return LOCKDOWN_E_INVALID_ARG; + } + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); ret = lockdownd_send(client, dict); @@ -148,6 +153,9 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) plist_free(dict); dict = NULL; + free(client->session_id); + client->session_id = NULL; + return ret; } @@ -209,6 +217,10 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) } } + if (client->session_id) { + free(client->session_id); + } + free(client); return ret; } @@ -642,6 +654,7 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ client_loc->ssl_session = NULL; client_loc->ssl_certificate = NULL; client_loc->in_SSL = 0; + client_loc->session_id = NULL; if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); @@ -985,7 +998,10 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c uint32_t return_me = 0; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; - client->session_id[0] = '\0'; + if (client->session_id) { + free(client->session_id); + client->session_id = NULL; + } /* Setup DevicePublicKey request plist */ dict = plist_new_dict(); @@ -1100,27 +1116,16 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c ret = LOCKDOWN_E_SUCCESS; } } - /* store session id */ + /* store session id, we need it for StopSession */ plist_t session_node = plist_dict_get_item(dict, "SessionID"); - if (session_node) { - - plist_type session_node_type = plist_get_node_type(session_node); - - if (session_node_type == PLIST_STRING) { - - char *session_id = NULL; - plist_get_string_val(session_node, &session_id); - - if (session_node_type == PLIST_STRING && session_id) { - /* we need to store the session ID for StopSession */ - strcpy(client->session_id, session_id); - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); - } - if (session_id) - free(session_id); - } - } else + if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { + plist_get_string_val(session_node, &client->session_id); + } + if (client->session_id) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id); + } else { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__); + } plist_free(dict); dict = NULL; -- cgit v1.1-32-gdbae From 62c23c1ccafedab1bf8bed2fb0e511462b8ab4cc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 16:37:47 +0100 Subject: fix lockdownd_pair returning success on error This fixes a bug where lockdown_check_result() might return -1 and lockdownd_pair() still returns success. Thanks to dborca for spotting this. --- src/lockdown.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index 6bf4c84..02b0024 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -755,8 +755,8 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho if (ret != LOCKDOWN_E_SUCCESS) return ret; - if (lockdown_check_result(dict, "Pair") == RESULT_SUCCESS) { - ret = LOCKDOWN_E_SUCCESS; + if (lockdown_check_result(dict, "Pair") != RESULT_SUCCESS) { + ret = LOCKDOWN_E_PAIRING_FAILED; } plist_free(dict); dict = NULL; @@ -767,7 +767,6 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho userpref_set_device_public_key(uuid, public_key); } else { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair failure\n", __func__); - ret = LOCKDOWN_E_PAIRING_FAILED; } free(public_key.data); return ret; -- cgit v1.1-32-gdbae From b9ecd70c30ac1fd7024cadfcda9c7be1d1f7f44f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 18:58:55 +0100 Subject: cache device uuid in client struct When accessing/storing key info with userprefs, a device uuid is required that makes it possible to distinguish between different devices. On execution of lockdownd_client_new, the uuid is queried via lockdown and now stored in the client struct for later reuse. This patch also removes the uuid parameter from lockdownd_pair(). --- src/lockdown.c | 51 +++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index 02b0024..b6289ed 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -220,6 +220,9 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) if (client->session_id) { free(client->session_id); } + if (client->uuid) { + free(client->uuid); + } free(client); return ret; @@ -655,31 +658,26 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ client_loc->ssl_certificate = NULL; client_loc->in_SSL = 0; client_loc->session_id = NULL; + client_loc->uuid = NULL; if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); ret = LOCKDOWN_E_NOT_ENOUGH_DATA; } - char *uuid = NULL; - ret = iphone_device_get_uuid(device, &uuid); + ret = iphone_device_get_uuid(device, &client_loc->uuid); if (LOCKDOWN_E_SUCCESS != ret) { log_debug_msg("%s: failed to get device uuid.\n", __func__); } - log_debug_msg("%s: device uuid: %s\n", __func__, uuid); + log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); userpref_get_host_id(&host_id); if (LOCKDOWN_E_SUCCESS == ret && !host_id) { ret = LOCKDOWN_E_INVALID_CONF; } - if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(uuid)) - ret = lockdownd_pair(client_loc, uuid, host_id); - - if (uuid) { - free(uuid); - uuid = NULL; - } + if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) + ret = lockdownd_pair(client_loc, host_id); if (LOCKDOWN_E_SUCCESS == ret) { ret = lockdownd_start_ssl_session(client_loc, host_id); @@ -703,9 +701,14 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ /** Generates the appropriate keys and pairs the device. It's part of the * lockdownd handshake. * + * @param client The lockdown client to pair with. + * @param host_id The HostID to use for pairing. If NULL is passed, then + * the HostID of the current machine is used. A new HostID will be + * generated automatically when pairing is done for the first time. + * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *host_id) +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = NULL; @@ -764,7 +767,7 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *uuid, char *ho /* store public key in config if pairing succeeded */ if (ret == LOCKDOWN_E_SUCCESS) { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair success\n", __func__); - userpref_set_device_public_key(uuid, public_key); + userpref_set_device_public_key(client->uuid, public_key); } else { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair failure\n", __func__); } @@ -1027,26 +1030,22 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c if (!strcmp(error, "InvalidHostID")) { /* hostid is unknown. Pair and try again */ - char *uuid = NULL; char *host_id = NULL; userpref_get_host_id(&host_id); - if (LOCKDOWN_E_SUCCESS == lockdownd_get_device_uuid(client, &uuid) ) { - if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, uuid, host_id) ) { - /* start session again */ - plist_free(dict); - dict = plist_new_dict(); - plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); - plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); + if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) { + /* start session again */ + plist_free(dict); + dict = plist_new_dict(); + plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); + plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); - ret = lockdownd_send(client, dict); - plist_free(dict); - dict = NULL; + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; - ret = lockdownd_recv(client, &dict); - } + ret = lockdownd_recv(client, &dict); } - free(uuid); free(host_id); } free(error); -- cgit v1.1-32-gdbae From 6ae6880ce5cf00977dfdb204855a7308d7bf42c9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 19:16:48 +0100 Subject: Allow passing NULL as HostID to lockdownd_pair() When NULL is given as HostID, lockdownd_pair() will use the HostID available from userprefs. --- src/lockdown.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index b6289ed..d717c01 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -719,6 +719,8 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) gnutls_datum_t root_cert = { NULL, 0 }; gnutls_datum_t public_key = { NULL, 0 }; + char *host_id_loc = host_id; + ret = lockdownd_get_device_public_key(client, &public_key); if (ret != LOCKDOWN_E_SUCCESS) { log_debug_msg("%s: device refused to send public key.\n", __func__); @@ -732,6 +734,10 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) return ret; } + if (!host_id) { + userpref_get_host_id(&host_id_loc); + } + /* Setup Pair request plist */ dict = plist_new_dict(); dict_record = plist_new_dict(); @@ -739,7 +745,7 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); - plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id)); + plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc)); plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); plist_dict_insert_item(dict, "Request", plist_new_string("Pair")); @@ -749,6 +755,10 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) plist_free(dict); dict = NULL; + if (!host_id) { + free(host_id_loc); + } + if (ret != LOCKDOWN_E_SUCCESS) return ret; -- cgit v1.1-32-gdbae From 318cc4f7b336109819c7b4c6a1a9f2e8d37d9bed Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 7 Dec 2009 19:27:54 +0100 Subject: New function lockdownd_validate_pair() This function allows the current host (or the host specified by the given HostID to become the trusted host of the device. [#89 state:resolved] Signed-off-by: Matt Colyer --- src/lockdown.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'src/lockdown.c') diff --git a/src/lockdown.c b/src/lockdown.c index d717c01..fb5f8f5 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -698,17 +698,17 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ return ret; } -/** Generates the appropriate keys and pairs the device. It's part of the - * lockdownd handshake. +/** Function used internally by lockdownd_pair() and lockdownd_validate_pair() * * @param client The lockdown client to pair with. * @param host_id The HostID to use for pairing. If NULL is passed, then * the HostID of the current machine is used. A new HostID will be * generated automatically when pairing is done for the first time. + * @param verb This is either "Pair" or "ValidatePair". * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) +static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = NULL; @@ -748,7 +748,7 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc)); plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); - plist_dict_insert_item(dict, "Request", plist_new_string("Pair")); + plist_dict_insert_item(dict, "Request", plist_new_string(verb)); /* send to iPhone */ ret = lockdownd_send(client, dict); @@ -768,7 +768,7 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) if (ret != LOCKDOWN_E_SUCCESS) return ret; - if (lockdown_check_result(dict, "Pair") != RESULT_SUCCESS) { + if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { ret = LOCKDOWN_E_PAIRING_FAILED; } plist_free(dict); @@ -776,15 +776,48 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) /* store public key in config if pairing succeeded */ if (ret == LOCKDOWN_E_SUCCESS) { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair success\n", __func__); + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); userpref_set_device_public_key(client->uuid, public_key); } else { - log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pair failure\n", __func__); + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); } free(public_key.data); return ret; } +/** + * Pairs the device with the given HostID. + * It's part of the lockdownd handshake. + * + * @param client The lockdown client to pair with. + * @param host_id The HostID to use for pairing. If NULL is passed, then + * the HostID of the current machine is used. A new HostID will be + * generated automatically when pairing is done for the first time. + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) +{ + return lockdownd_do_pair(client, host_id, "Pair"); +} + +/** + * Pairs the device with the given HostID. The difference to lockdownd_pair() + * is that the specified host will become trusted host of the device. + * It's part of the lockdownd handshake. + * + * @param client The lockdown client to pair with. + * @param host_id The HostID to use for pairing. If NULL is passed, then + * the HostID of the current machine is used. A new HostID will be + * generated automatically when pairing is done for the first time. + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) +{ + return lockdownd_do_pair(client, host_id, "ValidatePair"); +} + /** * Tells the device to immediately enter recovery mode. * -- cgit v1.1-32-gdbae