/** * Mounts an image on the device. * * @param client The connected mobile_image_mounter client. * @param image_path The absolute path of the image to mount. The image must * be present before calling this function. * @param image_signature Pointer to a buffer holding the images' signature * @param signature_length Length of the signature image_signature points to * @param image_type Type of image to mount * @param result Pointer to a plist that will receive the result of the * operation. * * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the * operation has failed. Check the resulting plist for further information. * Note that there is no unmounting function. The mount persists until the * device is rebooted. * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if on ore more parameters are * invalid, or another error code otherwise. */ mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *image_signature, uint16_t signature_length, const char *image_type, plist_t *result) { if (!client || !image_path || !image_signature || (signature_length == 0) || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; } mobile_image_mounter_lock(client); plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Command", plist_new_string("MountImage")); plist_dict_set_item(dict, "ImagePath", plist_new_string(image_path)); plist_dict_set_item(dict, "ImageSignature", plist_new_data(image_signature, signature_length)); plist_dict_set_item(dict, "ImageType", plist_new_string(image_type)); mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error sending XML plist to device!", __func__); goto leave_unlock; } res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, result)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error receiving response from device!", __func__); } leave_unlock: mobile_image_mounter_unlock(client); return res; }
/** * Sets the icon state of the connected device. * * @param client The connected sbservices client to use. * @param newstate A plist containing the new iconstate. * * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or newstate is NULL, or an SBSERVICES_E_* error code otherwise. */ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) { if (!client || !client->parent || !newstate) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("setIconState")); plist_dict_insert_item(dict, "iconState", plist_copy(newstate)); sbs_lock(client); res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); } /* NO RESPONSE */ if (dict) { plist_free(dict); } sbs_unlock(client); return res; }
/** * Get the home screen wallpaper as PNG data. * * @param client The connected sbservices client to use. * @param pngdata Pointer that will point to a newly allocated buffer * containing the PNG data upon successful return. It is up to the caller * to free the memory. * @param pngsize Pointer to a uint64_t that will be set to the size of the * buffer pngdata points to upon successful return. * * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or pngdata are invalid, or an SBSERVICES_E_* error * code otherwise. */ sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !pngdata) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("getHomeScreenWallpaperPNGData")); sbs_lock(client); res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); goto leave_unlock; } plist_free(dict); dict = NULL; res = sbservices_error(property_list_service_receive_plist(client->parent, &dict)); if (res == SBSERVICES_E_SUCCESS) { plist_t node = plist_dict_get_item(dict, "pngData"); if (node) { plist_get_data_val(node, pngdata, pngsize); } } leave_unlock: if (dict) { plist_free(dict); } sbs_unlock(client); return res; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(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_set_item(dict,"Request", plist_new_string("EnterRecovery")); debug_info("telling device to enter recovery mode"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(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_set_item(dict,"Request", plist_new_string("Goodbye")); debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return LOCKDOWN_E_PLIST_ERROR; } if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
/** * Sends a backup message plist. * * @param client The connected MobileBackup client to use. * @param message The message to send. This will be inserted into the request * plist as value for BackupMessageTypeKey. If this parameter is NULL, * the plist passed in the options parameter will be sent directly. * @param options Additional options as PLIST_DICT to add to the request. * The BackupMessageTypeKey with the value passed in the message parameter * will be inserted into this plist before sending it. This parameter * can be NULL if message is not NULL. */ static mobilebackup_error_t mobilebackup_send_message(mobilebackup_client_t client, const char *message, plist_t options) { if (!client || !client->parent || (!message && !options)) return MOBILEBACKUP_E_INVALID_ARG; if (options && (plist_get_node_type(options) != PLIST_DICT)) { return MOBILEBACKUP_E_INVALID_ARG; } mobilebackup_error_t err; if (message) { plist_t dict = NULL; if (options) { dict = plist_copy(options); } else { dict = plist_new_dict(); } plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string(message)); /* send it as DLMessageProcessMessage */ err = mobilebackup_error(device_link_service_send_process_message(client->parent, dict)); plist_free(dict); } else { err = mobilebackup_error(device_link_service_send_process_message(client->parent, options)); } if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send message '%s' (%d)!", message, err); } return err; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!client->session_id) return LOCKDOWN_E_NO_RUNNING_SESSION; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("Deactivate")); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
plist_t tss_request_new(plist_t overrides) { plist_t request = plist_new_dict(); plist_dict_set_item(request, "@Locality", plist_new_string("en_US")); plist_dict_set_item(request, "@HostPlatformInfo", #ifdef WIN32 plist_new_string("windows") #else plist_new_string("mac") #endif ); plist_dict_set_item(request, "@VersionInfo", plist_new_string(TSS_CLIENT_VERSION_STRING)); char* guid = generate_guid(); if (guid) { plist_dict_set_item(request, "@UUID", plist_new_string(guid)); free(guid); } /* apply overrides */ if (overrides) { plist_dict_merge(&request, overrides); } return request; }
static int send_device_list(struct mux_client *client, uint32_t tag) { int res = -1; plist_t dict = plist_new_dict(); plist_t devices = plist_new_array(); struct device_info *devs = NULL; struct device_info *dev; int i; int count = device_get_list(0, &devs); dev = devs; for (i = 0; devs && i < count; i++) { plist_t device = create_device_attached_plist(dev++); if (device) { plist_array_append_item(devices, device); } } if (devs) free(devs); plist_dict_set_item(dict, "DeviceList", devices); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; }
/** * Uninstall an application from the device. * * @param client The connected installation proxy client * @param appid ApplicationIdentifier of the app to uninstall * @param client_options The client options to use, as PLIST_DICT, or NULL. * Currently there are no known client options, so pass NULL here. * @param status_cb Callback function for progress and status information. If * NULL is passed, this function will run synchronously. * @param user_data Callback data passed to status_cb. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occured. * * @note If a callback function is given (async mode), this function returns * INSTPROXY_E_SUCCESS immediately if the status updater thread has been * created successfully; any error occuring during the operation has to be * handled inside the specified callback function. */ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { if (!client || !client->parent || !appid) { return INSTPROXY_E_INVALID_ARG; } if (client->status_updater) { return INSTPROXY_E_OP_IN_PROGRESS; } instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid)); plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); instproxy_lock(client); res = instproxy_send_command(client, "Uninstall", client_options, appid, NULL); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { debug_info("could not send plist, error %d", res); return res; } return instproxy_create_status_updater(client, status_cb, "Uninstall", user_data); }
dl_status dl_start(dl_t self) { // Assume usbmuxd supports proto_version 1. If not then we'd need to // send a binary listen request, check for failure, then retry this: plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "ClientVersionString", plist_new_string( "device_listener")); plist_dict_insert_item(dict, "MessageType", plist_new_string("Listen")); plist_dict_insert_item(dict, "ProgName", plist_new_string("libusbmuxd")); char *xml = NULL; uint32_t xml_length = 0; plist_to_xml(dict, &xml, &xml_length); plist_free(dict); size_t length = 16 + xml_length; char *packet = (char *)calloc(length, sizeof(char)); if (!packet) { return DL_ERROR; } char *tail = packet; tail = dl_sprintf_uint32(tail, length); tail = dl_sprintf_uint32(tail, 1); // version: 1 tail = dl_sprintf_uint32(tail, TYPE_PLIST); // type: plist tail = dl_sprintf_uint32(tail, 1); // tag: 1 tail = stpncpy(tail, xml, xml_length); free(xml); dl_status ret = self->send_packet(self, packet, length); free(packet); return ret; }
/** * Hangs up the connection to the mobile_image_mounter service. * This functions has to be called before freeing up a mobile_image_mounter * instance. If not, errors appear in the device's syslog. * * @param client The client to hang up * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is invalid, * or another error code otherwise. */ mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) { if (!client) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; } mobile_image_mounter_lock(client); plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Command", plist_new_string("Hangup")); mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error sending XML plist to device!", __func__); goto leave_unlock; } dict = NULL; res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &dict)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error receiving response from device!", __func__); } if (dict) { debug_plist(dict); plist_free(dict); } leave_unlock: mobile_image_mounter_unlock(client); return res; }
LIBIMOBILEDEVICE_API mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) { if (!client || !client->parent || !request || !target_identifier) return MOBILEBACKUP2_E_INVALID_ARG; plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "TargetIdentifier", plist_new_string(target_identifier)); if (source_identifier) { plist_dict_set_item(dict, "SourceIdentifier", plist_new_string(source_identifier)); } if (options) { plist_dict_set_item(dict, "Options", plist_copy(options)); } if (!strcmp(request, "Unback") && options) { plist_t node = plist_dict_get_item(options, "Password"); if (node) { plist_dict_set_item(dict, "Password", plist_copy(node)); } } if (!strcmp(request, "EnableCloudBackup") && options) { plist_t node = plist_dict_get_item(options, "CloudBackupState"); if (node) { plist_dict_set_item(dict, "CloudBackupState", plist_copy(node)); } } mobilebackup2_error_t err = mobilebackup2_send_message(client, request, dict); plist_free(dict); return err; }
/** * Request a backup from the connected device. * * @param client The connected MobileBackup client to use. * @param backup_manifest The backup manifest, a plist_t of type PLIST_DICT * containing the backup state of the last backup. For a first-time backup * set this parameter to NULL. * @param base_path The base path on the device to use for the backup * operation, usually "/". * @param proto_version A string denoting the version of the backup protocol * to use. Latest known version is "1.6" * * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if * one of the parameters is invalid, MOBILEBACKUP_E_PLIST_ERROR if * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR * if a communication error occurs, MOBILEBACKUP_E_REPLY_NOT_OK */ mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) { if (!client || !client->parent || !base_path || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; if (backup_manifest && (plist_get_node_type(backup_manifest) != PLIST_DICT)) return MOBILEBACKUP_E_PLIST_ERROR; mobilebackup_error_t err; /* construct request plist */ plist_t dict = plist_new_dict(); if (backup_manifest) plist_dict_insert_item(dict, "BackupManifestKey", plist_copy(backup_manifest)); plist_dict_insert_item(dict, "BackupComputerBasePathKey", plist_new_string(base_path)); plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); plist_dict_insert_item(dict, "BackupProtocolVersion", plist_new_string(proto_version)); /* send request */ err = mobilebackup_send_message(client, NULL, dict); plist_free(dict); dict = NULL; if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send backup request message (%d)!", err); goto leave; } /* now receive and hopefully get a BackupMessageBackupReplyOK */ err = mobilebackup_receive_message(client, "BackupMessageBackupReplyOK", &dict); if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not receive BackupReplyOK message (%d)!", err); goto leave; } plist_t node = plist_dict_get_item(dict, "BackupProtocolVersion"); if (node) { char *str = NULL; plist_get_string_val(node, &str); if (str) { if (strcmp(str, proto_version) != 0) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); } } if (err != MOBILEBACKUP_E_SUCCESS) goto leave; /* BackupMessageBackupReplyOK received, send it back */ err = mobilebackup_send_message(client, NULL, dict); if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send BackupReplyOK ACK (%d)", err); } leave: if (dict) plist_free(dict); return err; }
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; int i = 0; plist_t lookup_result = NULL; plist_t command = NULL; plist_t appid_array = NULL; plist_t node = NULL; if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; command = plist_new_dict(); plist_dict_set_item(command, "Command", plist_new_string("Lookup")); if (client_options) { node = plist_copy(client_options); } else if (appids) { node = plist_new_dict(); } /* add bundle identifiers to client options */ if (appids) { appid_array = plist_new_array(); while (appids[i]) { plist_array_append_item(appid_array, plist_new_string(appids[i])); i++; } plist_dict_set_item(node, "BundleIDs", appid_array); } if (node) { plist_dict_set_item(command, "ClientOptions", node); } res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_SYNC, instproxy_copy_lookup_result_cb, (void*)&lookup_result); if (res == INSTPROXY_E_SUCCESS) { *result = lookup_result; } else { plist_free(lookup_result); } plist_free(command); return res; }
LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("QueryType")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; ret = RESTORE_E_UNKNOWN_ERROR; plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && (plist_get_node_type(type_node) == PLIST_STRING)) { char* typestr = NULL; /* save our device information info */ client->info = dict; plist_get_string_val(type_node, &typestr); debug_info("success with type %s", typestr); /* return the type if requested */ if (type) { *type = typestr; } else { free(typestr); } /* fetch the restore protocol version */ if (version) { plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion"); if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { plist_get_uint_val(version_node, version); debug_info("restored protocol version %llu", *version); } else { return RESTORE_E_UNKNOWN_ERROR; } } ret = RESTORE_E_SUCCESS; } else { debug_info("hmm. QueryType response does not contain a type?!"); debug_plist(dict); plist_free(dict); } return ret; }
/** * Performs the mobilebackup2 protocol version exchange. * * @param client The MobileBackup client to use. * @param local_versions An array of supported versions to send to the remote. * @param count The number of items in local_versions. * @param remote_version Holds the protocol version of the remote on success. * * @return MOBILEBACKUP2_E_SUCCESS on success, or a MOBILEBACKUP2_E_* error * code otherwise. */ mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) { int i; if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; plist_t dict = plist_new_dict(); plist_t array = plist_new_array(); for (i = 0; i < count; i++) { plist_array_append_item(array, plist_new_real(local_versions[i])); } plist_dict_insert_item(dict, "SupportedProtocolVersions", array); mobilebackup2_error_t err = mobilebackup2_send_message(client, "Hello", dict); plist_free(dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; dict = NULL; err = internal_mobilebackup2_receive_message(client, "Response", &dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; /* check if we received an error */ plist_t node = plist_dict_get_item(dict, "ErrorCode"); if (!node || (plist_get_node_type(node) != PLIST_UINT)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } uint64_t val = 0; plist_get_uint_val(node, &val); if (val != 0) { if (val == 1) { err = MOBILEBACKUP2_E_NO_COMMON_VERSION; } else { err = MOBILEBACKUP2_E_REPLY_NOT_OK; } goto leave; } /* retrieve the protocol version of the device */ node = plist_dict_get_item(dict, "ProtocolVersion"); if (!node || (plist_get_node_type(node) != PLIST_REAL)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } *remote_version = 0.0; plist_get_real_val(node, remote_version); leave: if (dict) plist_free(dict); return err; }
webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; uint32_t offset = 0; int is_final_message = 0; char *packet = NULL; uint32_t packet_length = 0; debug_info("Sending webinspector message..."); debug_plist(plist); /* convert plist to packet */ plist_to_bin(plist, &packet, &packet_length); if (!packet || packet_length == 0) { debug_info("Error converting plist to binary."); return res; } do { /* determine if we need to send partial messages */ if (packet_length < WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE) { is_final_message = 1; } else { /* send partial packet */ is_final_message = 0; } plist_t outplist = plist_new_dict(); if (!is_final_message) { /* split packet into partial chunks */ plist_dict_set_item(outplist, "WIRPartialMessageKey", plist_new_data(packet + offset, WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE)); offset += WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE; packet_length -= WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE; } else { /* send final chunk */ plist_dict_set_item(outplist, "WIRFinalMessageKey", plist_new_data(packet + offset, packet_length)); offset += packet_length; packet_length -= packet_length; } res = webinspector_error(property_list_service_send_binary_plist(client->parent, outplist)); plist_free(outplist); outplist = NULL; if (res != WEBINSPECTOR_E_SUCCESS) { debug_info("Sending plist failed with error %d", res); return res; } } while(packet_length > 0); free(packet); packet = NULL; return res; }
/** * Query the type of the service daemon. Depending on whether the device is * queried in normal mode or restore mode, different types will be returned. * * @param client The restored client * @param type The type returned by the service daemon. Pass NULL to ignore. * @param version The restore protocol version. Pass NULL to ignore. * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL */ restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_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")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; ret = RESTORE_E_UNKNOWN_ERROR; if (restored_check_result(dict) == RESULT_SUCCESS) { /* save our device information info */ client->info = dict; /* return the type if requested */ if (type) { plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && PLIST_STRING == plist_get_node_type(type_node)) { plist_get_string_val(type_node, type); debug_info("success with type %s", *type); ret = RESTORE_E_SUCCESS; } else { return RESTORE_E_UNKNOWN_ERROR; } } /* fetch the restore protocol version */ if (version) { plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion"); if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { plist_get_uint_val(version_node, version); debug_info("restored protocol version %llu", *version); ret = RESTORE_E_SUCCESS; } else { return RESTORE_E_UNKNOWN_ERROR; } } ret = RESTORE_E_SUCCESS; } return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) { if (!client) return LOCKDOWN_E_INVALID_ARG; plist_t dict = NULL; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; /* setup request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); if (domain) { plist_dict_set_item(dict,"Domain", plist_new_string(domain)); } if (key) { plist_dict_set_item(dict,"Key", plist_new_string(key)); } plist_dict_set_item(dict,"Request", plist_new_string("GetValue")); /* send to device */ ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; if (ret != LOCKDOWN_E_SUCCESS) return ret; /* Now get device's answer */ ret = lockdownd_receive(client, &dict); if (ret != LOCKDOWN_E_SUCCESS) return ret; if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } else { ret = LOCKDOWN_E_UNKNOWN_ERROR; } if (ret != LOCKDOWN_E_SUCCESS) { plist_free(dict); return ret; } plist_t value_node = plist_dict_get_item(dict, "Value"); if (value_node) { debug_info("has a value"); *value = plist_copy(value_node); } plist_free(dict); return ret; }
/** * 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; }
/** * Get a screen shot from the connected device. * * @param client The connection screenshotr service client. * @param imgdata Pointer that will point to a newly allocated buffer * containing TIFF image data upon successful return. It is up to the * caller to free the memory. * @param imgsize Pointer to a uint64_t that will be set to the size of the * buffer imgdata points to upon successful return. * * @return SCREENSHOTR_E_SUCCESS on success, SCREENSHOTR_E_INVALID_ARG if * one or more parameters are invalid, or another error code if an * error occured. */ screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) { if (!client || !client->parent || !imgdata) return SCREENSHOTR_E_INVALID_ARG; screenshotr_error_t res = SCREENSHOTR_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("ScreenShotRequest")); res = screenshotr_error(device_link_service_send_process_message(client->parent, dict)); plist_free(dict); if (res != SCREENSHOTR_E_SUCCESS) { debug_info("could not send plist, error %d", res); return res; } dict = NULL; res = screenshotr_error(device_link_service_receive_process_message(client->parent, &dict)); if (res != SCREENSHOTR_E_SUCCESS) { debug_info("could not get screenshot data, error %d", res); goto leave; } if (!dict) { debug_info("did not receive screenshot data!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } plist_t node = plist_dict_get_item(dict, "MessageType"); char *strval = NULL; plist_get_string_val(node, &strval); if (!strval || strcmp(strval, "ScreenShotReply")) { debug_info("invalid screenshot data received!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } node = plist_dict_get_item(dict, "ScreenShotData"); if (!node || plist_get_node_type(node) != PLIST_DATA) { debug_info("no PNG data received!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } plist_get_data_val(node, imgdata, imgsize); res = SCREENSHOTR_E_SUCCESS; leave: if (dict) plist_free(dict); return res; }
LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client) { plist_t dict; property_list_service_client_t parent; if (!client) return NP_E_INVALID_ARG; dict = plist_new_dict(); plist_dict_set_item(dict,"Command", plist_new_string("Shutdown")); property_list_service_send_xml_plist(client->parent, dict); plist_free(dict); parent = client->parent; /* notifies the client->notifier thread that it should terminate */ client->parent = NULL; if (client->notifier) { debug_info("joining np callback"); thread_join(client->notifier); thread_free(client->notifier); client->notifier = (thread_t)NULL; } else { dict = NULL; property_list_service_receive_plist(parent, &dict); if (dict) { #ifndef STRIP_DEBUG_CODE char *cmd_value = NULL; plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { plist_get_string_val(cmd_value_node, &cmd_value); } if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { // this is the expected answer } else { debug_info("Did not get ProxyDeath but:"); debug_plist(dict); } if (cmd_value) { free(cmd_value); } #endif plist_free(dict); } } property_list_service_client_free(parent); mutex_destroy(&client->mutex); free(client); return NP_E_SUCCESS; }
/** * Request that a backup should be restored to the connected device. * * @param client The connected MobileBackup client to use. * @param backup_manifest The backup manifest, a plist_t of type PLIST_DICT * containing the backup state to be restored. * @param flags Flags to send with the request. Currently this is a combination * of the following mobilebackup_flags_t: * MB_RESTORE_NOTIFY_SPRINGBOARD - let SpringBoard show a 'Restore' screen * MB_RESTORE_PRESERVE_SETTINGS - do not overwrite any settings * MB_RESTORE_PRESERVE_CAMERA_ROLL - preserve the photos of the camera roll * @param proto_version A string denoting the version of the backup protocol * to use. Latest known version is "1.6". Ideally this value should be * extracted from the given manifest plist. * * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if * one of the parameters is invalid, MOBILEBACKUP_E_PLIST_ERROR if * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR * if a communication error occurs, or MOBILEBACKUP_E_REPLY_NOT_OK * if the device did not accept the request. */ mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) { if (!client || !client->parent || !backup_manifest || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; if (backup_manifest && (plist_get_node_type(backup_manifest) != PLIST_DICT)) return MOBILEBACKUP_E_PLIST_ERROR; mobilebackup_error_t err; /* construct request plist */ plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "BackupManifestKey", plist_copy(backup_manifest)); plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("kBackupMessageRestoreRequest")); plist_dict_insert_item(dict, "BackupProtocolVersion", plist_new_string(proto_version)); /* add flags */ plist_dict_insert_item(dict, "BackupNotifySpringBoard", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_NOTIFY_SPRINGBOARD))); plist_dict_insert_item(dict, "BackupPreserveSettings", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_SETTINGS))); plist_dict_insert_item(dict, "BackupPreserveCameraRoll", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_CAMERA_ROLL))); /* send request */ err = mobilebackup_send_message(client, NULL, dict); plist_free(dict); dict = NULL; if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send restore request message (%d)!", err); goto leave; } /* now receive and hopefully get a BackupMessageRestoreReplyOK */ err = mobilebackup_receive_message(client, "BackupMessageRestoreReplyOK", &dict); if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not receive RestoreReplyOK message (%d)!", err); goto leave; } plist_t node = plist_dict_get_item(dict, "BackupProtocolVersion"); if (node) { char *str = NULL; plist_get_string_val(node, &str); if (str) { if (strcmp(str, proto_version) != 0) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); } } leave: if (dict) plist_free(dict); return err; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!session_id) { debug_info("no session_id given, cannot stop session"); 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_set_item(dict,"Request", plist_new_string("StopSession")); plist_dict_set_item(dict,"SessionID", plist_new_string(session_id)); debug_info("stopping session %s", session_id); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; if (client->session_id) { free(client->session_id); client->session_id = NULL; } if (client->ssl_enabled) { property_list_service_disable_ssl(client->parent); client->ssl_enabled = 0; } return ret; }
static int send_system_buid(struct mux_client *client, uint32_t tag) { int res = -1; char* buid = NULL; config_get_system_buid(&buid); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "BUID", plist_new_string(buid)); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!client->session_id) return LOCKDOWN_E_NO_RUNNING_SESSION; 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_set_item(dict,"Request", plist_new_string("Activate")); plist_dict_set_item(dict,"ActivationRecord", plist_copy(activation_record)); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_ACTIVATION_FAILED; if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } else { plist_t error_node = plist_dict_get_item(dict, "Error"); if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { char *error = NULL; plist_get_string_val(error_node, &error); if (!strcmp(error, "InvalidActivationRecord")) { ret = LOCKDOWN_E_INVALID_ACTIVATION_RECORD; } free(error); } } plist_free(dict); dict = NULL; 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; }
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t command = plist_new_dict(); plist_dict_set_item(command, "Command", plist_new_string("LookupArchives")); if (client_options) plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_SYNC, instproxy_copy_lookup_result_cb, (void*)result); plist_free(command); return res; }
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t command = plist_new_dict(); plist_dict_set_item(command, "Command", plist_new_string("RemoveArchive")); if (client_options) plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); plist_dict_set_item(command, "ApplicationIdentifier", plist_new_string(appid)); res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_ASYNC, status_cb, user_data); plist_free(command); return res; }