/** * 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; }
wi_status wi_parse_plist(wi_t self, const char *from_buf, size_t length, plist_t *to_rpc_dict, bool *to_is_partial) { wi_private_t my = self->private_state; *to_is_partial = false; *to_rpc_dict = NULL; if (my->is_sim) { plist_from_bin(from_buf, length, to_rpc_dict); } else { plist_t wi_dict = NULL; plist_from_bin(from_buf, length, &wi_dict); if (!wi_dict) { return WI_ERROR; } plist_t wi_rpc = plist_dict_get_item(wi_dict, "WIRFinalMessageKey"); if (!wi_rpc) { wi_rpc = plist_dict_get_item(wi_dict, "WIRPartialMessageKey"); if (!wi_rpc) { return WI_ERROR; } *to_is_partial = true; } uint64_t rpc_len = 0; char *rpc_bin = NULL; plist_get_data_val(wi_rpc, &rpc_bin, &rpc_len); plist_free(wi_dict); // also frees wi_rpc if (!rpc_bin) { return WI_ERROR; } // assert rpc_len < MAX_RPC_LEN? size_t p_length = my->partial->tail - my->partial->head; if (*to_is_partial || p_length) { if (cb_ensure_capacity(my->partial, rpc_len)) { return self->on_error(self, "Out of memory"); } memcpy(my->partial->tail, rpc_bin, rpc_len); my->partial->tail += rpc_len; p_length += rpc_len; free(rpc_bin); if (*to_is_partial) { return WI_SUCCESS; } } if (p_length) { plist_from_bin(my->partial->head, (uint32_t)p_length, to_rpc_dict); cb_clear(my->partial); } else { plist_from_bin(rpc_bin, (uint32_t)rpc_len, to_rpc_dict); free(rpc_bin); } } return (*to_rpc_dict ? WI_SUCCESS : WI_ERROR); }
int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob) { uint32_t i = 0; uint32_t tss_size = 0; uint64_t blob_size = 0; char* entry_key = NULL; char* blob_data = NULL; char* entry_path = NULL; plist_t tss_entry = NULL; plist_t blob_node = NULL; plist_t path_node = NULL; plist_dict_iter iter = NULL; *blob = NULL; plist_dict_new_iter(tss, &iter); tss_size = plist_dict_get_size(tss); for (i = 0; i < tss_size; i++) { plist_dict_next_item(tss, iter, &entry_key, &tss_entry); if (entry_key == NULL) break; if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { continue; } path_node = plist_dict_get_item(tss_entry, "Path"); if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { error("ERROR: Unable to find TSS path node in entry %s\n", entry_key); free(iter); return -1; } plist_get_string_val(path_node, &entry_path); if (strcmp(path, entry_path) == 0) { blob_node = plist_dict_get_item(tss_entry, "Blob"); if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key); free(iter); return -1; } plist_get_data_val(blob_node, &blob_data, &blob_size); break; } free(entry_key); } free(iter); if (blob_data == NULL || blob_size <= 0) { return -1; } *blob = (unsigned char*)blob_data; return 0; }
/** * 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; }
int normal_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) { idevice_t device = NULL; plist_t nonce_node = NULL; lockdownd_client_t lockdown = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; device_error = idevice_new(&device, client->udid); if (device_error != IDEVICE_E_SUCCESS) { return -1; } lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); if (lockdown_error != LOCKDOWN_E_SUCCESS) { error("ERROR: Unable to connect to lockdownd\n"); idevice_free(device); return -1; } lockdown_error = lockdownd_get_value(lockdown, NULL, "ApNonce", &nonce_node); if (lockdown_error != LOCKDOWN_E_SUCCESS) { error("ERROR: Unable to get ApNonce from lockdownd\n"); lockdownd_client_free(lockdown); idevice_free(device); return -1; } if (!nonce_node || plist_get_node_type(nonce_node) != PLIST_DATA) { error("ERROR: Unable to get nonce\n"); lockdownd_client_free(lockdown); idevice_free(device); return -1; } uint64_t n_size = 0; plist_get_data_val(nonce_node, (char**)nonce, &n_size); *nonce_size = (int)n_size; plist_free(nonce_node); lockdownd_client_free(lockdown); idevice_free(device); lockdown = NULL; device = NULL; return 0; }
int tss_get_ticket(plist_t tss, unsigned char** ticket, uint32_t* tlen) { plist_t entry_node = plist_dict_get_item(tss, "APTicket"); if (!entry_node || plist_get_node_type(entry_node) != PLIST_DATA) { error("ERROR: Unable to find APTicket entry in TSS response\n"); return -1; } char *data = NULL; uint64_t len = 0; plist_get_data_val(entry_node, &data, &len); if (data) { *tlen = (uint32_t)len; *ticket = data; return 0; } else { error("ERROR: Unable to get APTicket data from TSS response\n"); return -1; } }
/** * Retrieves the public key of the device from lockdownd. * * @param client An initialized lockdownd client. * @param public_key Holds the public key of the device. The caller is * responsible for freeing the memory. * * @return LOCKDOWN_E_SUCCESS on success */ static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_client_t client, key_data_t *public_key) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; char *value_value = NULL; uint64_t size = 0; ret = lockdownd_get_value(client, NULL, "DevicePublicKey", &value); if (ret != LOCKDOWN_E_SUCCESS) { return ret; } plist_get_data_val(value, &value_value, &size); public_key->data = (unsigned char*)value_value; public_key->size = size; plist_free(value); value = NULL; return ret; }
static int tss_response_get_data_by_key(plist_t response, const char* name, unsigned char** buffer, unsigned int* length) { plist_t node = plist_dict_get_item(response, name); if (!node || plist_get_node_type(node) != PLIST_DATA) { debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, name); return -1; } char *data = NULL; uint64_t len = 0; plist_get_data_val(node, &data, &len); if (data) { *length = (unsigned int)len; *buffer = (unsigned char*)data; return 0; } else { error("ERROR: Unable to get %s data from TSS response\n", name); return -1; } }
int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) { uint64_t blob_size = 0; char* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; *blob = NULL; tss_entry = plist_dict_get_item(response, entry); if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry); return -1; } blob_node = plist_dict_get_item(tss_entry, "Blob"); if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { error("ERROR: Unable to find blob in %s entry\n", entry); return -1; } plist_get_data_val(blob_node, &blob_data, &blob_size); *blob = (unsigned char*)blob_data; return 0; }
int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob) { uint64_t blob_size = 0; char* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; *blob = NULL; tss_entry = plist_dict_get_item(tss, entry); if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { error("ERROR: Unable to find %s entry in TSS response\n", entry); return -1; } blob_node = plist_dict_get_item(tss_entry, "Blob"); if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { error("ERROR: Unable to find blob in %s entry\n", entry); return -1; } plist_get_data_val(blob_node, &blob_data, &blob_size); *blob = blob_data; return 0; }
webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms) { webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR; plist_t message = NULL; plist_t key = NULL; int is_final_message = 1; char* buffer = NULL; uint64_t length = 0; char* packet = NULL; char* newpacket = NULL; uint64_t packet_length = 0; debug_info("Receiving webinspector message..."); do { /* receive message */ res = webinspector_error(property_list_service_receive_plist_with_timeout(client->parent, &message, timeout_ms)); if (res != WEBINSPECTOR_E_SUCCESS || !message) { debug_info("Could not receive message, error %d", res); plist_free(message); return WEBINSPECTOR_E_MUX_ERROR; } /* get message key */ key = plist_dict_get_item(message, "WIRFinalMessageKey"); if (!key) { key = plist_dict_get_item(message, "WIRPartialMessageKey"); if (!key) { debug_info("ERROR: Unable to read message key."); plist_free(message); return WEBINSPECTOR_E_PLIST_ERROR; } is_final_message = 0; } else { is_final_message = 1; } /* read partial data */ plist_get_data_val(key, &buffer, &length); if (!buffer || length == 0 || length > 0xFFFFFFFF) { debug_info("ERROR: Unable to get the inner plist binary data."); free(packet); free(buffer); return WEBINSPECTOR_E_PLIST_ERROR; } /* (re)allocate packet data */ if (!packet) { packet = (char*)malloc(length * sizeof(char)); } else { newpacket = (char*)realloc(packet, (packet_length + length) * sizeof(char)); packet = newpacket; } /* copy partial data into final packet data */ memcpy(packet + packet_length, buffer, length); /* cleanup buffer */ free(buffer); buffer = NULL; if (message) { plist_free(message); message = NULL; } /* adjust packet length */ packet_length += length; length = 0; } while(!is_final_message); /* read final message */ if (packet_length) { plist_from_bin(packet, (uint32_t)packet_length, plist); if (!*plist) { debug_info("Error restoring the final plist."); free(packet); return WEBINSPECTOR_E_PLIST_ERROR; } debug_plist(*plist); } if (packet) { free(packet); } return res; }
int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name) { plist_t node = NULL; plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); return -1; } /* add tags indicating we want to get the Savage,Ticket */ plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1)); /* add Savage,UID */ node = plist_dict_get_item(parameters, "Savage,UID"); if (!node) { error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,UID", plist_copy(node)); node = NULL; /* add SEP */ node = plist_access_path(manifest_node, 2, "SEP", "Digest"); if (!node) { error("ERROR: Unable to get SEP digest from manifest\n"); return -1; } plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Digest", plist_copy(node)); plist_dict_set_item(request, "SEP", dict); /* add Savage,PatchEpoch */ node = plist_dict_get_item(parameters, "Savage,PatchEpoch"); if (!node) { error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,PatchEpoch", plist_copy(node)); node = NULL; /* add Savage,ChipID */ node = plist_dict_get_item(parameters, "Savage,ChipID"); if (!node) { error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,ChipID", plist_copy(node)); node = NULL; /* add Savage,AllowOfflineBoot */ node = plist_dict_get_item(parameters, "Savage,AllowOfflineBoot"); if (!node) { error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,AllowOfflineBoot", plist_copy(node)); node = NULL; /* add Savage,ReadFWKey */ node = plist_dict_get_item(parameters, "Savage,ReadFWKey"); if (!node) { error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,ReadFWKey", plist_copy(node)); node = NULL; /* add Savage,ProductionMode */ node = plist_dict_get_item(parameters, "Savage,ProductionMode"); if (!node) { error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,ProductionMode", plist_copy(node)); const char *comp_name = NULL; uint8_t isprod = 0; plist_get_bool_val(node, &isprod); node = NULL; /* get the right component name */ comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; node = plist_dict_get_item(parameters, "Savage,Revision"); if (node && (plist_get_node_type(node) == PLIST_DATA)) { unsigned char *savage_rev = NULL; uint64_t savage_rev_len = 0; plist_get_data_val(node, (char**)&savage_rev, &savage_rev_len); if (savage_rev_len > 0) { if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; } else if ((savage_rev[0] & 0xF0) == 0xA0) { comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch"; } } free(savage_rev); } /* add Savage,B?-*-Patch */ node = plist_dict_get_item(manifest_node, comp_name); if (!node) { error("ERROR: Unable to get %s entry from manifest\n", comp_name); return -1; } dict = plist_copy(node); plist_dict_remove_item(dict, "Info"); plist_dict_set_item(request, comp_name, dict); if (component_name) { *component_name = strdup(comp_name); } /* add Savage,Nonce */ node = plist_dict_get_item(parameters, "Savage,Nonce"); if (!node) { error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,Nonce", plist_copy(node)); node = NULL; /* add Savage,ReadECKey */ node = plist_dict_get_item(parameters, "Savage,ReadECKey"); if (!node) { error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); return -1; } plist_dict_set_item(request, "Savage,ReadECKey", plist_copy(node)); node = NULL; /* apply overrides */ if (overrides) { plist_dict_merge(&request, overrides); } return 0; }
static int client_command(struct mux_client *client, struct usbmuxd_header *hdr) { int res; usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag); if(client->state != CLIENT_COMMAND) { usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state", client->fd); if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; client_close(client); return -1; } if((hdr->version != 0) && (hdr->version != 1)) { usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version); send_result(client, hdr->tag, RESULT_BADVERSION); return 0; } struct usbmuxd_connect_request *ch; char *payload; uint32_t payload_size; switch(hdr->message) { case MESSAGE_PLIST: client->proto_version = 1; payload = (char*)(hdr) + sizeof(struct usbmuxd_header); payload_size = hdr->length - sizeof(struct usbmuxd_header); plist_t dict = NULL; plist_from_xml(payload, payload_size, &dict); if (!dict) { usbmuxd_log(LL_ERROR, "Could not parse plist from payload!"); return -1; } else { char *message = NULL; plist_t node = plist_dict_get_item(dict, "MessageType"); plist_get_string_val(node, &message); if (!message) { usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!"); plist_free(dict); return -1; } if (!strcmp(message, "Listen")) { free(message); plist_free(dict); if (send_result(client, hdr->tag, 0) < 0) return -1; usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd); return start_listen(client); } else if (!strcmp(message, "Connect")) { uint64_t val; uint16_t portnum = 0; uint32_t device_id = 0; free(message); // get device id node = plist_dict_get_item(dict, "DeviceID"); if (!node) { usbmuxd_log(LL_ERROR, "Received connect request without device_id!"); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADDEV) < 0) return -1; return 0; } val = 0; plist_get_uint_val(node, &val); device_id = (uint32_t)val; // get port number node = plist_dict_get_item(dict, "PortNumber"); if (!node) { usbmuxd_log(LL_ERROR, "Received connect request without port number!"); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } val = 0; plist_get_uint_val(node, &val); portnum = (uint16_t)val; plist_free(dict); usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum)); res = device_start_connect(device_id, ntohs(portnum), client); if(res < 0) { if (send_result(client, hdr->tag, -res) < 0) return -1; } else { client->connect_tag = hdr->tag; client->connect_device = device_id; client->state = CLIENT_CONNECTING1; } return 0; } else if (!strcmp(message, "ListDevices")) { free(message); plist_free(dict); if (send_device_list(client, hdr->tag) < 0) return -1; return 0; } else if (!strcmp(message, "ReadBUID")) { free(message); plist_free(dict); if (send_system_buid(client, hdr->tag) < 0) return -1; return 0; } else if (!strcmp(message, "ReadPairRecord")) { free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); plist_free(dict); res = send_pair_record(client, hdr->tag, record_id); if (record_id) free(record_id); if (res < 0) return -1; return 0; } else if (!strcmp(message, "SavePairRecord")) { uint32_t rval = RESULT_OK; free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); char* record_data = NULL; uint64_t record_size = 0; plist_t rdata = plist_dict_get_item(dict, "PairRecordData"); if (rdata && plist_get_node_type(rdata) == PLIST_DATA) { plist_get_data_val(rdata, &record_data, &record_size); } plist_free(dict); if (record_id && record_data) { res = config_set_device_record(record_id, record_data, record_size); if (res < 0) { rval = -res; } free(record_id); } else { rval = EINVAL; } if (send_result(client, hdr->tag, rval) < 0) return -1; return 0; } else if (!strcmp(message, "DeletePairRecord")) { uint32_t rval = RESULT_OK; free(message); char* record_id = plist_dict_get_string_val(dict, "PairRecordID"); plist_free(dict); if (record_id) { res = config_remove_device_record(record_id); if (res < 0) { rval = -res; } free(record_id); } else { rval = EINVAL; } if (send_result(client, hdr->tag, rval) < 0) return -1; return 0; } else { usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message); free(message); plist_free(dict); if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } } // should not be reached?! return -1; case MESSAGE_LISTEN: if(send_result(client, hdr->tag, 0) < 0) return -1; usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd); return start_listen(client); case MESSAGE_CONNECT: ch = (void*)hdr; usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, ch->device_id, ntohs(ch->port)); res = device_start_connect(ch->device_id, ntohs(ch->port), client); if(res < 0) { if(send_result(client, hdr->tag, -res) < 0) return -1; } else { client->connect_tag = hdr->tag; client->connect_device = ch->device_id; client->state = CLIENT_CONNECTING1; } return 0; default: usbmuxd_log(LL_ERROR, "Client %d invalid command %d", client->fd, hdr->message); if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0) return -1; return 0; } return -1; }
plist_t tss_create_request(plist_t build_identity, uint64_t ecid, unsigned char* nonce, int nonce_size) { uint64_t unique_build_size = 0; char* unique_build_data = NULL; plist_t unique_build_node = plist_dict_get_item(build_identity, "UniqueBuildID"); if (!unique_build_node || plist_get_node_type(unique_build_node) != PLIST_DATA) { error("ERROR: Unable to find UniqueBuildID node\n"); return NULL; } plist_get_data_val(unique_build_node, &unique_build_data, &unique_build_size); int chip_id = 0; char* chip_id_string = NULL; plist_t chip_id_node = plist_dict_get_item(build_identity, "ApChipID"); if (!chip_id_node || plist_get_node_type(chip_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApChipID node\n"); return NULL; } plist_get_string_val(chip_id_node, &chip_id_string); sscanf(chip_id_string, "%x", &chip_id); int board_id = 0; char* board_id_string = NULL; plist_t board_id_node = plist_dict_get_item(build_identity, "ApBoardID"); if (!board_id_node || plist_get_node_type(board_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApBoardID node\n"); return NULL; } plist_get_string_val(board_id_node, &board_id_string); sscanf(board_id_string, "%x", &board_id); int security_domain = 0; char* security_domain_string = NULL; plist_t security_domain_node = plist_dict_get_item(build_identity, "ApSecurityDomain"); if (!security_domain_node || plist_get_node_type(security_domain_node) != PLIST_STRING) { error("ERROR: Unable to find ApSecurityDomain node\n"); return NULL; } plist_get_string_val(security_domain_node, &security_domain_string); sscanf(security_domain_string, "%x", &security_domain); char ecid_string[ECID_STRSIZE]; memset(ecid_string, '\0', ECID_STRSIZE); if (ecid == 0) { error("ERROR: Unable to get ECID\n"); return NULL; } snprintf(ecid_string, ECID_STRSIZE, FMT_qu, (long long unsigned int)ecid); // Add build information to TSS request plist_t tss_request = plist_new_dict(); plist_dict_insert_item(tss_request, "@APTicket", plist_new_bool(1)); plist_dict_insert_item(tss_request, "@BBTicket", plist_new_bool(1)); plist_dict_insert_item(tss_request, "@HostIpAddress", plist_new_string("192.168.0.1")); plist_dict_insert_item(tss_request, "@HostPlatformInfo", plist_new_string("mac")); plist_dict_insert_item(tss_request, "@Locality", plist_new_string("en_US")); char* guid = generate_guid(); if (guid) { plist_dict_insert_item(tss_request, "@UUID", plist_new_string(guid)); free(guid); } plist_dict_insert_item(tss_request, "@VersionInfo", plist_new_string("libauthinstall-107.3")); plist_dict_insert_item(tss_request, "ApBoardID", plist_new_uint(board_id)); plist_dict_insert_item(tss_request, "ApChipID", plist_new_uint(chip_id)); plist_dict_insert_item(tss_request, "ApECID", plist_new_string(ecid_string)); if (nonce && (nonce_size > 0)) { plist_dict_insert_item(tss_request, "ApNonce", plist_new_data(nonce, nonce_size)); } plist_dict_insert_item(tss_request, "ApProductionMode", plist_new_bool(1)); plist_dict_insert_item(tss_request, "ApSecurityDomain", plist_new_uint(security_domain)); plist_dict_insert_item(tss_request, "UniqueBuildID", plist_new_data(unique_build_data, unique_build_size)); free(unique_build_data); // Add all firmware files to TSS request plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: Unable to find restore manifest\n"); plist_free(tss_request); return NULL; } char* key = NULL; plist_t manifest_entry = NULL; plist_dict_iter iter = NULL; plist_dict_new_iter(manifest_node, &iter); while (1) { plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); if (key == NULL) break; if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { error("ERROR: Unable to fetch BuildManifest entry\n"); free(tss_request); return NULL; } if (strcmp(key, "BasebandFirmware") == 0) { free(key); continue; } plist_t tss_entry = plist_copy(manifest_entry); plist_dict_insert_item(tss_request, key, tss_entry); free(key); } if (idevicerestore_debug) { debug_plist(tss_request); } return tss_request; }
static void plist_node_to_string(plist_t node) { char *s = NULL; char *data = NULL; double d; uint8_t b; uint64_t u = 0; GTimeVal tv = { 0, 0 }; plist_type t; if (!node) return; t = plist_get_node_type(node); switch (t) { case PLIST_BOOLEAN: plist_get_bool_val(node, &b); printf("%s\n", (b ? "true" : "false")); break; case PLIST_UINT: plist_get_uint_val(node, &u); printf("%llu\n", (long long)u); break; case PLIST_REAL: plist_get_real_val(node, &d); printf("%f\n", d); break; case PLIST_STRING: plist_get_string_val(node, &s); printf("%s\n", s); free(s); break; case PLIST_KEY: plist_get_key_val(node, &s); printf("%s: ", s); free(s); break; case PLIST_DATA: plist_get_data_val(node, &data, &u); s = g_base64_encode((guchar *)data, u); free(data); printf("%s\n", s); g_free(s); break; case PLIST_DATE: plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec); s = g_time_val_to_iso8601(&tv); printf("%s\n", s); free(s); break; case PLIST_ARRAY: printf("\n"); indent_level++; plist_array_to_string(node); indent_level--; break; case PLIST_DICT: printf("\n"); indent_level++; plist_dict_to_string(node); indent_level--; break; default: break; } }
int main(int argc, char *argv[]) { lockdownd_client_t client = NULL; lockdownd_service_descriptor_t service = NULL; idevice_t device = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; int i; int op = -1; const char* udid = NULL; const char* param = NULL; /* parse cmdline args */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { idevice_set_debug_level(1); continue; } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); return 0; } udid = argv[i]; continue; } else if (!strcmp(argv[i], "install")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_INSTALL; continue; } else if (!strcmp(argv[i], "list")) { op = OP_LIST; } else if (!strcmp(argv[i], "copy")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_COPY; continue; } else if (!strcmp(argv[i], "remove")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_REMOVE; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); return 0; } else { print_usage(argc, argv); return 0; } } if ((op == -1) || (op >= NUM_OPS)) { print_usage(argc, argv); return 0; } ret = idevice_new(&device, udid); if (ret != IDEVICE_E_SUCCESS) { if (udid) { printf("No device found with udid %s, is it plugged in?\n", udid); } else { printf("No device found, is it plugged in?\n"); } return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "ideviceprovision")) { idevice_free(device); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &service)) { fprintf(stderr, "Could not start service \"com.apple.misagent\"\n"); lockdownd_client_free(client); idevice_free(device); return -1; } lockdownd_client_free(client); client = NULL; misagent_client_t mis = NULL; if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) { fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n"); if (service) lockdownd_service_descriptor_free(service); lockdownd_client_free(client); idevice_free(device); return -1; } if (service) lockdownd_service_descriptor_free(service); switch (op) { case OP_INSTALL: { FILE* f = fopen(param, "rb"); if (!f) { fprintf(stderr, "Could not open file '%s'\n", param); break; } fseek(f, 0, SEEK_END); long int size = ftell(f); fseek(f, 0, SEEK_SET); if (size >= 0x1000000) { fprintf(stderr, "The file '%s' is too large for processing.\n", param); fclose(f); break; } char* buf = (char *)malloc(size); if (!buf) { fprintf(stderr, "Could not allocate memory...\n"); fclose(f); break; } long int cur = 0; while (cur < size) { ssize_t r = fread(buf+cur, 1, 512, f); if (r <= 0) { break; } cur += r; } fclose(f); if (cur != size) { free(buf); fprintf(stderr, "Could not read in file '%s' (size %ld read %ld)\n", param, size, cur); break; } uint64_t psize = size; plist_t pdata = plist_new_data(buf, psize); if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) { printf("Profile '%s' installed successfully.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not install profile '%s', status code: 0x%x\n", param, sc); } free(buf); } break; case OP_LIST: case OP_COPY: { plist_t profiles = NULL; if (misagent_copy(mis, &profiles) == MISAGENT_E_SUCCESS) { uint32_t num_profiles = plist_array_get_size(profiles); printf("Device has %d provisioning %s installed:\n", num_profiles, (num_profiles == 1) ? "profile" : "profiles"); uint32_t j; for (j = 0; j < num_profiles; j++) { char* p_name = NULL; char* p_uuid = NULL; plist_t profile = plist_array_get_item(profiles, j); plist_t pl = profile_get_embedded_plist(profile); if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_t node; node = plist_dict_get_item(pl, "Name"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_name); } node = plist_dict_get_item(pl, "UUID"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_uuid); } } printf("%s - %s\n", (p_uuid) ? p_uuid : "(unknown id)", (p_name) ? p_name : "(no name)"); if (op == OP_COPY) { char pfname[512]; if (p_uuid) { sprintf(pfname, "%s/%s.mobileprovision", param, p_uuid); } else { sprintf(pfname, "%s/profile%d.mobileprovision", param, j); } FILE* f = fopen(pfname, "wb"); if (f) { char* dt = NULL; uint64_t ds = 0; plist_get_data_val(profile, &dt, &ds); fwrite(dt, 1, (size_t) ds, f); fclose(f); printf(" => %s\n", pfname); } else { fprintf(stderr, "Could not open '%s' for writing\n", pfname); } } if (p_uuid) { free(p_uuid); } if (p_name) { free(p_name); } } } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not get installed profiles from device, status code: 0x%x\n", sc); } } break; case OP_REMOVE: if (misagent_remove(mis, param) == MISAGENT_E_SUCCESS) { printf("Profile '%s' removed.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not remove profile '%s', status code 0x%x\n", param, sc); } break; default: break; } misagent_client_free(mis); idevice_free(device); return 0; }
static plist_t profile_get_embedded_plist(plist_t profile) { if (plist_get_node_type(profile) != PLIST_DATA) { fprintf(stderr, "%s: unexpected plist node type for profile (PLIST_DATA expected)\n", __FUNCTION__); return NULL; } char* bbuf = NULL; uint64_t blen = 0; plist_get_data_val(profile, &bbuf, &blen); if (!bbuf) { fprintf(stderr, "%s: could not get data value from plist node\n", __FUNCTION__); return NULL; } unsigned char* pp = (unsigned char*)bbuf; if (*pp != ASN1_SEQUENCE) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (0)\n", __FUNCTION__); return NULL; } uint16_t slen = asn1_item_get_size(pp); if (slen+4 != (uint16_t)blen) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (1)\n", __FUNCTION__); return NULL; } asn1_next_item(&pp); if (*pp != ASN1_OBJECT_IDENTIFIER) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (2)\n", __FUNCTION__); return NULL; } asn1_skip_item(&pp); if (*pp != ASN1_CONTAINER) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (3)\n", __FUNCTION__); return NULL; } asn1_next_item(&pp); if (*pp != ASN1_SEQUENCE) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (4)\n", __FUNCTION__); return NULL; } asn1_next_item(&pp); int k = 0; // go to the 3rd element (skip 2) while (k < 2) { asn1_skip_item(&pp); k++; } if (*pp != ASN1_SEQUENCE) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (5)\n", __FUNCTION__); return NULL; } asn1_next_item(&pp); if (*pp != ASN1_OBJECT_IDENTIFIER) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (6)\n", __FUNCTION__); return NULL; } asn1_skip_item(&pp); if (*pp != ASN1_CONTAINER) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (7)\n", __FUNCTION__); return NULL; } asn1_next_item(&pp); if (*pp != ASN1_OCTET_STRING) { free(bbuf); fprintf(stderr, "%s: unexpected profile data (8)\n", __FUNCTION__); return NULL; } slen = asn1_item_get_size(pp); asn1_next_item(&pp); plist_t pl = NULL; plist_from_xml((char*)pp, slen, &pl); free(bbuf); return pl; }
int main(int argc, char *argv[]) { lockdownd_client_t client = NULL; lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; lockdownd_service_descriptor_t service = NULL; idevice_t device = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; int i; int op = -1; int output_xml = 0; const char* udid = NULL; const char* param = NULL; /* parse cmdline args */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { idevice_set_debug_level(1); continue; } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); return 0; } udid = argv[i]; continue; } else if (!strcmp(argv[i], "install")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_INSTALL; continue; } else if (!strcmp(argv[i], "list")) { op = OP_LIST; } else if (!strcmp(argv[i], "copy")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_COPY; continue; } else if (!strcmp(argv[i], "remove")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_REMOVE; continue; } else if (!strcmp(argv[i], "dump")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_DUMP; continue; } else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) { output_xml = 1; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); return 0; } else { print_usage(argc, argv); return 0; } } if ((op == -1) || (op >= NUM_OPS)) { print_usage(argc, argv); return 0; } if (op == OP_DUMP) { int res = 0; unsigned char* profile_data = NULL; unsigned int profile_size = 0; if (profile_read_from_file(param, &profile_data, &profile_size) != 0) { return -1; } plist_t pdata = plist_new_data((char*)profile_data, profile_size); plist_t pl = profile_get_embedded_plist(pdata); plist_free(pdata); free(profile_data); if (pl) { if (output_xml) { char* xml = NULL; uint32_t xlen = 0; plist_to_xml(pl, &xml, &xlen); if (xml) { printf("%s\n", xml); free(xml); } } else { if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_print_to_stream(pl, stdout); } else { fprintf(stderr, "ERROR: unexpected node type in profile plist (not PLIST_DICT)\n"); res = -1; } } } else { fprintf(stderr, "ERROR: could not extract embedded plist from profile!\n"); } plist_free(pl); return res; } ret = idevice_new(&device, udid); if (ret != IDEVICE_E_SUCCESS) { if (udid) { printf("No device found with udid %s, is it plugged in?\n", udid); } else { printf("No device found, is it plugged in?\n"); } return -1; } if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "ideviceprovision"))) { fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ldret); idevice_free(device); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &service)) { fprintf(stderr, "Could not start service \"com.apple.misagent\"\n"); lockdownd_client_free(client); idevice_free(device); return -1; } lockdownd_client_free(client); client = NULL; misagent_client_t mis = NULL; if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) { fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n"); if (service) lockdownd_service_descriptor_free(service); lockdownd_client_free(client); idevice_free(device); return -1; } if (service) lockdownd_service_descriptor_free(service); switch (op) { case OP_INSTALL: { unsigned char* profile_data = NULL; unsigned int profile_size = 0; if (profile_read_from_file(param, &profile_data, &profile_size) != 0) { break; } uint64_t psize = profile_size; plist_t pdata = plist_new_data((const char*)profile_data, psize); free(profile_data); if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) { printf("Profile '%s' installed successfully.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not install profile '%s', status code: 0x%x\n", param, sc); } } break; case OP_LIST: case OP_COPY: { plist_t profiles = NULL; if (misagent_copy(mis, &profiles) == MISAGENT_E_SUCCESS) { uint32_t num_profiles = plist_array_get_size(profiles); printf("Device has %d provisioning %s installed:\n", num_profiles, (num_profiles == 1) ? "profile" : "profiles"); uint32_t j; for (j = 0; j < num_profiles; j++) { char* p_name = NULL; char* p_uuid = NULL; plist_t profile = plist_array_get_item(profiles, j); plist_t pl = profile_get_embedded_plist(profile); if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_t node; node = plist_dict_get_item(pl, "Name"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_name); } node = plist_dict_get_item(pl, "UUID"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_uuid); } } printf("%s - %s\n", (p_uuid) ? p_uuid : "(unknown id)", (p_name) ? p_name : "(no name)"); if (op == OP_COPY) { char pfname[512]; if (p_uuid) { sprintf(pfname, "%s/%s.mobileprovision", param, p_uuid); } else { sprintf(pfname, "%s/profile%d.mobileprovision", param, j); } FILE* f = fopen(pfname, "wb"); if (f) { char* dt = NULL; uint64_t ds = 0; plist_get_data_val(profile, &dt, &ds); fwrite(dt, 1, ds, f); fclose(f); printf(" => %s\n", pfname); } else { fprintf(stderr, "Could not open '%s' for writing\n", pfname); } } if (p_uuid) { free(p_uuid); } if (p_name) { free(p_name); } } } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not get installed profiles from device, status code: 0x%x\n", sc); } } break; case OP_REMOVE: if (misagent_remove(mis, param) == MISAGENT_E_SUCCESS) { printf("Profile '%s' removed.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not remove profile '%s', status code 0x%x\n", param, sc); } break; default: break; } misagent_client_free(mis); idevice_free(device); return 0; }
static void plist_node_to_string(plist_t node) { char *s = NULL; char *data = NULL; double d; uint8_t b; uint64_t u = 0; struct timeval tv = { 0, 0 }; plist_type t; if (!node) return; t = plist_get_node_type(node); switch (t) { case PLIST_BOOLEAN: plist_get_bool_val(node, &b); printf("%s\n", (b ? "true" : "false")); break; case PLIST_UINT: plist_get_uint_val(node, &u); printf("%llu\n", (long long)u); break; case PLIST_REAL: plist_get_real_val(node, &d); printf("%f\n", d); break; case PLIST_STRING: plist_get_string_val(node, &s); printf("%s\n", s); free(s); break; case PLIST_KEY: plist_get_key_val(node, &s); printf("%s: ", s); free(s); break; case PLIST_DATA: plist_get_data_val(node, &data, &u); uint64_t i; for (i = 0; i < u; i++) { printf("%02x", (unsigned char)data[i]); } free(data); printf("\n"); break; case PLIST_DATE: plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec); { time_t ti = (time_t)tv.tv_sec; struct tm *btime = localtime(&ti); if (btime) { s = (char*)malloc(24); memset(s, 0, 24); if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) { free (s); s = NULL; } } } if (s) { puts(s); free(s); } puts("\n"); break; case PLIST_ARRAY: printf("\n"); indent_level++; plist_array_to_string(node); indent_level--; break; case PLIST_DICT: printf("\n"); indent_level++; plist_dict_to_string(node); indent_level--; break; default: break; } }