/** * Generates a pair record plist with required certificates for a specific * device. If a pairing exists, it is loaded from the computer instead of being * generated. * * @param pair_record_plist Holds the pair record. * * @return LOCKDOWN_E_SUCCESS on success */ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; key_data_t public_key = { NULL, 0 }; char* host_id = NULL; char* system_buid = NULL; /* retrieve device public key */ ret = lockdownd_get_device_public_key_as_key_data(client, &public_key); if (ret != LOCKDOWN_E_SUCCESS) { debug_info("device refused to send public key."); goto leave; } debug_info("device public key follows:\n%.*s", public_key.size, public_key.data); *pair_record = plist_new_dict(); /* generate keys and certificates into pair record */ userpref_error_t uret = USERPREF_E_SUCCESS; uret = pair_record_generate_keys_and_certs(*pair_record, public_key); switch(uret) { case USERPREF_E_INVALID_ARG: ret = LOCKDOWN_E_INVALID_ARG; break; case USERPREF_E_INVALID_CONF: ret = LOCKDOWN_E_INVALID_CONF; break; case USERPREF_E_SSL_ERROR: ret = LOCKDOWN_E_SSL_ERROR; default: break; } /* set SystemBUID */ userpref_read_system_buid(&system_buid); if (system_buid) { plist_dict_set_item(*pair_record, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); } /* set HostID */ host_id = generate_uuid(); pair_record_set_host_id(*pair_record, host_id); leave: if (host_id) free(host_id); if (system_buid) free(system_buid); if (public_key.data) free(public_key.data); return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label) { if (!client) return LOCKDOWN_E_INVALID_ARG; static struct lockdownd_service_descriptor service = { .port = 0xf27e, .ssl_enabled = 0 }; property_list_service_client_t plistclient = NULL; if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("could not connect to lockdownd (device %s)", device->udid); return LOCKDOWN_E_MUX_ERROR; } lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_private)); client_loc->parent = plistclient; client_loc->ssl_enabled = 0; client_loc->session_id = NULL; if (idevice_get_udid(device, &client_loc->udid) != IDEVICE_E_SUCCESS) { debug_info("failed to get device udid."); } debug_info("device udid: %s", client_loc->udid); client_loc->label = label ? strdup(label) : NULL; *client = client_loc; return LOCKDOWN_E_SUCCESS; } LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label) { if (!client) return LOCKDOWN_E_INVALID_ARG; lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; lockdownd_client_t client_loc = NULL; char *host_id = NULL; char *type = NULL; ret = lockdownd_client_new(device, &client_loc, label); if (LOCKDOWN_E_SUCCESS != ret) { debug_info("failed to create lockdownd client."); return ret; } /* perform handshake */ if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) { debug_info("QueryType failed in the lockdownd client."); ret = LOCKDOWN_E_NOT_ENOUGH_DATA; } else { if (strcmp("com.apple.mobile.lockdown", type)) { debug_info("Warning QueryType request returned \"%s\".", type); } } if (type) free(type); plist_t pair_record = NULL; userpref_read_pair_record(client_loc->udid, &pair_record); if (pair_record) { pair_record_get_host_id(pair_record, &host_id); } if (LOCKDOWN_E_SUCCESS == ret && !host_id) { ret = LOCKDOWN_E_INVALID_CONF; } if (LOCKDOWN_E_SUCCESS == ret && !pair_record) { /* attempt pairing */ ret = lockdownd_pair(client_loc, NULL); } plist_free(pair_record); pair_record = NULL; /* in any case, we need to validate pairing to receive trusted host status */ ret = lockdownd_validate_pair(client_loc, NULL); /* if not paired yet, let's do it now */ if (LOCKDOWN_E_INVALID_HOST_ID == ret) { ret = lockdownd_pair(client_loc, NULL); if (LOCKDOWN_E_SUCCESS == ret) { ret = lockdownd_validate_pair(client_loc, NULL); } else if (LOCKDOWN_E_PAIRING_DIALOG_PENDING == ret) { debug_info("Device shows the pairing dialog."); } } if (LOCKDOWN_E_SUCCESS == ret) { if (!host_id) { userpref_read_pair_record(client_loc->udid, &pair_record); if (pair_record) { pair_record_get_host_id(pair_record, &host_id); plist_free(pair_record); } } ret = lockdownd_start_session(client_loc, host_id, NULL, NULL); if (LOCKDOWN_E_SUCCESS != ret) { debug_info("Session opening failed."); } if (host_id) { free(host_id); host_id = NULL; } } if (LOCKDOWN_E_SUCCESS == ret) { *client = client_loc; } else { lockdownd_client_free(client_loc); } return ret; } /** * Returns a new plist from the supplied lockdownd pair record. The caller is * responsible for freeing the plist. * * @param pair_record The pair record to create a plist from. * * @return A pair record plist from the device, NULL if pair_record is not set */ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record) { if (!pair_record) return NULL; /* setup request plist */ plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate))); plist_dict_set_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate))); plist_dict_set_item(dict, "HostID", plist_new_string(pair_record->host_id)); plist_dict_set_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate))); plist_dict_set_item(dict, "SystemBUID", plist_new_string(pair_record->system_buid)); return dict; } /** * Generates a pair record plist with required certificates for a specific * device. If a pairing exists, it is loaded from the computer instead of being * generated. * * @param pair_record_plist Holds the pair record. * * @return LOCKDOWN_E_SUCCESS on success */ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; key_data_t public_key = { NULL, 0 }; char* host_id = NULL; char* system_buid = NULL; /* retrieve device public key */ ret = lockdownd_get_device_public_key_as_key_data(client, &public_key); if (ret != LOCKDOWN_E_SUCCESS) { debug_info("device refused to send public key."); goto leave; } debug_info("device public key follows:\n%.*s", public_key.size, public_key.data); *pair_record = plist_new_dict(); /* generate keys and certificates into pair record */ userpref_error_t uret = USERPREF_E_SUCCESS; uret = pair_record_generate_keys_and_certs(*pair_record, public_key); switch(uret) { case USERPREF_E_INVALID_ARG: ret = LOCKDOWN_E_INVALID_ARG; break; case USERPREF_E_INVALID_CONF: ret = LOCKDOWN_E_INVALID_CONF; break; case USERPREF_E_SSL_ERROR: ret = LOCKDOWN_E_SSL_ERROR; default: break; } /* set SystemBUID */ userpref_read_system_buid(&system_buid); if (system_buid) { plist_dict_set_item(*pair_record, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); } /* set HostID */ host_id = generate_uuid(); pair_record_set_host_id(*pair_record, host_id); leave: if (host_id) free(host_id); if (system_buid) free(system_buid); if (public_key.data) free(public_key.data); return ret; }