summaryrefslogtreecommitdiffstats
path: root/src/lockdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lockdown.c')
-rw-r--r--src/lockdown.c191
1 files changed, 179 insertions, 12 deletions
diff --git a/src/lockdown.c b/src/lockdown.c
index 2532999..24dd4a1 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -108,6 +108,21 @@ static int lockdown_check_result(plist_t dict, const char *query_match)
}
/**
+ * Adds a label key with the passed value to a plist dict node.
+ *
+ * @param plist The plist to add the key to
+ * @param label The value for the label key
+ *
+ */
+static void plist_dict_add_label(plist_t plist, const char *label)
+{
+ if (plist && label) {
+ if (plist_get_node_type(plist) == PLIST_DICT)
+ plist_dict_insert_item(plist, "Label", plist_new_string(label));
+ }
+}
+
+/**
* Closes the lockdownd communication session, by sending
* the StopSession Request to the device.
*
@@ -128,6 +143,7 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client)
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"Request", plist_new_string("StopSession"));
plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id));
@@ -223,11 +239,27 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
if (client->uuid) {
free(client->uuid);
}
+ if (client->label) {
+ free(client->label);
+ }
free(client);
return ret;
}
+/**
+ * Sets the label to send for requests to lockdownd.
+ *
+ * @param client The lockdown client
+ * @param label The label to set or NULL to disable
+ *
+ */
+void lockdownd_client_set_label(lockdownd_client_t client, const char *label)
+{
+ if (client)
+ client->label = strdup(label);
+}
+
/** Polls the iPhone for lockdownd data.
*
* @param control The lockdownd client
@@ -306,6 +338,7 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"Request", plist_new_string("QueryType"));
log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__);
@@ -349,6 +382,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
/* setup request plist */
dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
if (domain) {
plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
}
@@ -410,6 +444,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom
/* setup request plist */
dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
if (domain) {
plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
}
@@ -467,6 +502,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *
/* setup request plist */
dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
if (domain) {
plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
}
@@ -576,10 +612,11 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de
*
* @param phone The iPhone to create a lockdownd client for
* @param client The pointer to the location of the new lockdownd_client
+ * @param label The label to use for communication. Usually the program name
*
* @return an error code (LOCKDOWN_E_SUCCESS on success)
*/
-lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client)
+lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label)
{
if (!client)
return LOCKDOWN_E_INVALID_ARG;
@@ -599,6 +636,7 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_
client_loc->in_SSL = 0;
client_loc->session_id = NULL;
client_loc->uuid = NULL;
+ client_loc->label = strdup(label);
if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) {
log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__);
@@ -681,6 +719,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
/* Setup Pair request plist */
dict = plist_new_dict();
dict_record = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"PairRecord", dict_record);
plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
@@ -711,16 +750,36 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) {
ret = LOCKDOWN_E_PAIRING_FAILED;
}
- plist_free(dict);
- dict = NULL;
- /* store public key in config if pairing succeeded */
+ /* if pairing succeeded */
if (ret == LOCKDOWN_E_SUCCESS) {
log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb);
- userpref_set_device_public_key(client->uuid, public_key);
+ if (!strcmp("Unpair", verb)) {
+ /* remove public key from config */
+ userpref_remove_device_public_key(client->uuid);
+ } else {
+ /* store public key in config */
+ userpref_set_device_public_key(client->uuid, public_key);
+ }
} else {
log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb);
+ plist_t error_node = NULL;
+ /* verify error condition */
+ error_node = plist_dict_get_item(dict, "Error");
+ if (error_node) {
+ char *value = NULL;
+ plist_get_string_val(error_node, &value);
+ /* the first pairing fails if the device is password protected */
+ if (value && !strcmp(value, "PasswordProtected")) {
+ ret = LOCKDOWN_E_PASSWORD_PROTECTED;
+ free(value);
+ }
+ plist_free(error_node);
+ error_node = NULL;
+ }
}
+ plist_free(dict);
+ dict = NULL;
free(public_key.data);
return ret;
}
@@ -758,6 +817,21 @@ lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_
return lockdownd_do_pair(client, host_id, "ValidatePair");
}
+/**
+ * Unpairs the device with the given HostID and removes the pairing records
+ * from the device and host.
+ *
+ * @param client The lockdown client to pair with.
+ * @param host_id The HostID to use for unpairing. If NULL is passed, then
+ * the HostID of the current machine is used.
+ *
+ * @return an error code (LOCKDOWN_E_SUCCESS on success)
+ */
+lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, char *host_id)
+{
+ return lockdownd_do_pair(client, host_id, "Unpair");
+}
+
/**
* Tells the device to immediately enter recovery mode.
*
@@ -773,6 +847,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery"));
log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__);
@@ -808,6 +883,7 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));
log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__);
@@ -977,7 +1053,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
*
* @return an error code (LOCKDOWN_E_SUCCESS on success)
*/
-lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID)
+lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *host_id)
{
plist_t dict = NULL;
uint32_t return_me = 0;
@@ -990,7 +1066,8 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c
/* Setup DevicePublicKey request plist */
dict = plist_new_dict();
- plist_dict_insert_item(dict,"HostID", plist_new_string(HostID));
+ plist_dict_add_label(dict, client->label);
+ plist_dict_insert_item(dict,"HostID", plist_new_string(host_id));
plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
ret = lockdownd_send(client, dict);
@@ -1013,14 +1090,15 @@ 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 *host_id = NULL;
- userpref_get_host_id(&host_id);
+ char *host_id_new = NULL;
+ userpref_get_host_id(&host_id_new);
- if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) {
+ if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id_new) ) {
/* start session again */
plist_free(dict);
dict = plist_new_dict();
- plist_dict_insert_item(dict,"HostID", plist_new_string(HostID));
+ plist_dict_add_label(dict, client->label);
+ plist_dict_insert_item(dict,"HostID", plist_new_string(host_id_new));
plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
ret = lockdownd_send(client, dict);
@@ -1029,7 +1107,7 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c
ret = lockdownd_recv(client, &dict);
}
- free(host_id);
+ free(host_id_new);
}
free(error);
}
@@ -1217,6 +1295,7 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
host_id = NULL;
dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
plist_dict_insert_item(dict,"Request", plist_new_string("StartService"));
plist_dict_insert_item(dict,"Service", plist_new_string(service));
@@ -1260,3 +1339,91 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
return ret;
}
+/**
+ * Activates the device. Only works within an open session.
+ * The ActivationRecord plist dictionary must be obtained using the
+ * activation protocol requesting from Apple's https webservice.
+ *
+ * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation
+ *
+ * @param control The lockdown client
+ * @param activation_record The activation record plist dictionary
+ *
+ * @return an error code (LOCKDOWN_E_SUCCESS on success)
+ */
+lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)
+{
+ if (!client)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ if (!activation_record)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
+
+ plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
+ plist_dict_insert_item(dict,"Request", plist_new_string("Activate"));
+ plist_dict_insert_item(dict,"ActivationRecord", activation_record);
+
+ ret = lockdownd_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+
+ ret = lockdownd_recv(client, &dict);
+ if (!dict) {
+ log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__);
+ return LOCKDOWN_E_PLIST_ERROR;
+ }
+
+ ret = LOCKDOWN_E_ACTIVATION_FAILED;
+ if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) {
+ log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__);
+ ret = LOCKDOWN_E_SUCCESS;
+ }
+ plist_free(dict);
+ dict = NULL;
+
+ return ret;
+}
+
+/**
+ * Deactivates the device, returning it to the locked
+ * “Activate with iTunes” screen.
+ *
+ * @param control The lockdown client
+ *
+ * @return an error code (LOCKDOWN_E_SUCCESS on success)
+ */
+lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client)
+{
+ if (!client)
+ return LOCKDOWN_E_INVALID_ARG;
+
+ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
+
+ plist_t dict = plist_new_dict();
+ plist_dict_add_label(dict, client->label);
+ plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate"));
+
+ ret = lockdownd_send(client, dict);
+ plist_free(dict);
+ dict = NULL;
+
+ ret = lockdownd_recv(client, &dict);
+ if (!dict) {
+ log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__);
+ return LOCKDOWN_E_PLIST_ERROR;
+ }
+
+ ret = LOCKDOWN_E_UNKNOWN_ERROR;
+ if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) {
+ log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__);
+ ret = LOCKDOWN_E_SUCCESS;
+ }
+ plist_free(dict);
+ dict = NULL;
+
+ return ret;
+}
+