static void plist_copy_node(node_t *node, void *parent_node_ptr) { plist_type node_type = PLIST_NONE; plist_t newnode = NULL; plist_data_t data = plist_get_data(node); plist_data_t newdata = plist_new_plist_data(); assert(data); // plist should always have data memcpy(newdata, data, sizeof(struct plist_data_s)); node_type = plist_get_node_type(node); if (node_type == PLIST_DATA || node_type == PLIST_STRING || node_type == PLIST_KEY) { switch (node_type) { case PLIST_DATA: newdata->buff = (uint8_t *) malloc(data->length); memcpy(newdata->buff, data->buff, data->length); break; case PLIST_KEY: case PLIST_STRING: newdata->strval = strdup((char *) data->strval); break; default: break; } } newnode = plist_new_node(newdata); if (*(plist_t*)parent_node_ptr) { node_attach(*(plist_t*)parent_node_ptr, newnode); } else { *(plist_t*)parent_node_ptr = newnode; } node_iterator_t *ni = node_iterator_create(node->children); node_t *ch; while ((ch = node_iterator_next(ni))) { plist_copy_node(ch, &newnode); } node_iterator_destroy(ni); }
Node* Node::FromPlist(plist_t node, Node* parent) { Node* ret = NULL; if (node) { plist_type type = plist_get_node_type(node); switch (type) { case PLIST_DICT: ret = new Dictionary(node, parent); break; case PLIST_ARRAY: ret = new Array(node, parent); break; case PLIST_BOOLEAN: ret = new Boolean(node, parent); break; case PLIST_UINT: ret = new Integer(node, parent); break; case PLIST_REAL: ret = new Real(node, parent); break; case PLIST_STRING: ret = new String(node, parent); break; case PLIST_KEY: ret = new Key(node, parent); break; case PLIST_UID: ret = new Uid(node, parent); break; case PLIST_DATE: ret = new Date(node, parent); break; case PLIST_DATA: ret = new Data(node, parent); break; default: plist_free(node); break; } } return ret; }
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; } }
PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item) { if (node && PLIST_DICT == plist_get_node_type(node)) { node_t* old_item = plist_dict_get_item(node, key); if (old_item) { int idx = plist_free_node(old_item); if (idx < 0) { node_attach(node, item); } else { node_insert(node, idx, item); } } else { node_attach(node, plist_new_key(key)); node_attach(node, item); } } return; }
int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { char* type = NULL; plist_t node = NULL; // checks and see what kind of data restored is requests and pass // the request to its own handler node = plist_dict_get_item(message, "DataType"); if (node && PLIST_STRING == plist_get_node_type(node)) { plist_get_string_val(node, &type); // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { restore_send_filesystem(device, filesystem); } else if (!strcmp(type, "KernelCache")) { int kernelcache_size = 0; char* kernelcache_data = NULL; char* kernelcache_path = NULL; if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { error("ERROR: Unable to find kernelcache path\n"); return -1; } if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { error("ERROR: Unable to get kernelcache file\n"); return -1; } restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); free(kernelcache_data); } else if (!strcmp(type, "NORData")) { restore_send_nor(restore, ipsw, tss); } else { // Unknown DataType!! debug("Unknown data request received\n"); } } return 0; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) { 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("QueryType")); debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (LOCKDOWN_E_SUCCESS != ret) return ret; ret = LOCKDOWN_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; plist_get_string_val(type_node, &typestr); debug_info("success with type %s", typestr); /* return the type if requested */ if (type != NULL) { *type = typestr; } else { free(typestr); } ret = LOCKDOWN_E_SUCCESS; } else { debug_info("hmm. QueryType response does not contain a type?!"); debug_plist(dict); } plist_free(dict); dict = NULL; return ret; }
/** * Sends a DLMessageProcessMessage plist. * * @param client The device link service client to use. * @param message PLIST_DICT to send. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid or * message is not a PLIST_DICT, or DEVICE_LINK_SERVICE_E_MUX_ERROR if * the DLMessageProcessMessage plist could not be sent. */ device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message) { if (!client || !client->parent || !message) return DEVICE_LINK_SERVICE_E_INVALID_ARG; if (plist_get_node_type(message) != PLIST_DICT) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); plist_array_append_item(array, plist_copy(message)); device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { err = DEVICE_LINK_SERVICE_E_MUX_ERROR; } plist_free(array); return err; }
int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { idevice_t device = NULL; plist_t unique_chip_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->uuid); if (device_error != IDEVICE_E_SUCCESS) { return -1; } lockdown_error = lockdownd_client_new_with_handshake(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, "UniqueChipID", &unique_chip_node); if (lockdown_error != LOCKDOWN_E_SUCCESS) { error("ERROR: Unable to get UniqueChipID from lockdownd\n"); lockdownd_client_free(lockdown); idevice_free(device); return -1; } if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { error("ERROR: Unable to get ECID\n"); lockdownd_client_free(lockdown); idevice_free(device); return -1; } plist_get_uint_val(unique_chip_node, ecid); plist_free(unique_chip_node); lockdownd_client_free(lockdown); idevice_free(device); lockdown = NULL; device = NULL; return 0; }
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; } }
static mobileactivation_error_t mobileactivation_check_result(plist_t dict, const char *command) { mobileactivation_error_t ret = MOBILEACTIVATION_E_UNKNOWN_ERROR; if (!dict || plist_get_node_type(dict) != PLIST_DICT) { return MOBILEACTIVATION_E_PLIST_ERROR; } plist_t err_node = plist_dict_get_item(dict, "Error"); if (!err_node) { return MOBILEACTIVATION_E_SUCCESS; } else { char *errmsg = NULL; plist_get_string_val(err_node, &errmsg); debug_info("ERROR: %s: %s", command, errmsg); ret = MOBILEACTIVATION_E_REQUEST_FAILED; free(errmsg); } return ret; }
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) { if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"MobileGestaltKeys", plist_copy(keys)); plist_dict_insert_item(dict,"Request", plist_new_string("MobileGestalt")); ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; ret = diagnostics_relay_receive(client, &dict); if (!dict) { return DIAGNOSTICS_RELAY_E_PLIST_ERROR; } int check = diagnostics_relay_check_result(dict); if (check == RESULT_SUCCESS) { ret = DIAGNOSTICS_RELAY_E_SUCCESS; } else if (check == RESULT_UNKNOWN_REQUEST) { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST; } else { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; } if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { plist_free(dict); return ret; } plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); if (value_node) { *result = plist_copy(value_node); } plist_free(dict); return ret; }
static int get_dictval_date_from_key(plist_t dict, const char *key, uint32_t *val) { plist_t node; int32_t secs; int32_t dummy; node = plist_dict_get_item(dict, key); if (!node) return -1; if (plist_get_node_type(node) != PLIST_DATE) return -1; plist_get_date_val(node, &secs, &dummy); *val = (uint32_t) secs; return 0; }
/** * Send a command with specified options to the device. * Only used internally. * * @param client The connected installation_proxy client. * @param command The command to execute. Required. * @param client_options The client options to use, as PLIST_DICT, or NULL. * @param appid The ApplicationIdentifier to add or NULL if not required. * @param package_path The installation package path or NULL if not required. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occured. */ static instproxy_error_t instproxy_send_command(instproxy_client_t client, const char *command, plist_t client_options, const char *appid, const char *package_path) { if (!client || !command || (client_options && (plist_get_node_type(client_options) != PLIST_DICT))) return INSTPROXY_E_INVALID_ARG; plist_t dict = plist_new_dict(); if (appid) { plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid)); } if (client_options && (plist_dict_get_size(client_options) > 0)) { plist_dict_insert_item(dict, "ClientOptions", plist_copy(client_options)); } plist_dict_insert_item(dict, "Command", plist_new_string(command)); if (package_path) { plist_dict_insert_item(dict, "PackagePath", plist_new_string(package_path)); } instproxy_error_t err = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); return err; }
static int get_dictval_bool_from_key(plist_t dict, const char *key, uint8_t *val) { plist_t node; node = plist_dict_get_item(dict, key); /* Not present means false */ if (!node) { *val = 0; return 0; } if (plist_get_node_type(node) != PLIST_BOOLEAN) return -1; plist_get_bool_val(node, val); return 0; }
static int get_dictval_date_from_key(plist_t dict, const char *key, uint32_t *val) { plist_t node; int32_t secs; int32_t dummy; node = plist_dict_get_item(dict, key); if (!node) return -1; if (plist_get_node_type(node) != PLIST_DATE) return -1; // secs will be number of seconds since 01/01/2001 plist_get_date_val(node, &secs, &dummy); // make it a Unix Timestamp by adding seconds from 1/1/1970 to 1/1/2001 *val = (uint32_t) (secs + 978307200); return 0; }
PLIST_API void plist_dict_merge(plist_t *target, plist_t source) { if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT)) return; char* key = NULL; plist_dict_iter it = NULL; plist_t subnode = NULL; plist_dict_new_iter(source, &it); if (!it) return; do { plist_dict_next_item(source, it, &key, &subnode); if (!key) break; plist_dict_set_item(*target, key, plist_copy(subnode)); free(key); key = NULL; } while (1); free(it); }
static void plist_dict_to_string(plist_t node) { plist_dict_iter it = NULL; char* key = NULL; plist_t subnode = NULL; plist_dict_new_iter(node, &it); plist_dict_next_item(node, it, &key, &subnode); while (subnode) { printf("%*s", indent_level, ""); printf("%s", key); if (plist_get_node_type(subnode) == PLIST_ARRAY) printf("[%d]: ", plist_array_get_size(subnode)); else printf(": "); free(key); key = NULL; plist_node_to_string(subnode); plist_dict_next_item(node, it, &key, &subnode); } free(it); }
plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v) { plist_t current = plist; plist_type type = PLIST_NONE; uint32_t i = 0; for (i = 0; i < length && current; i++) { type = plist_get_node_type(current); if (type == PLIST_ARRAY) { uint32_t n = va_arg(v, uint32_t); current = plist_array_get_item(current, n); } else if (type == PLIST_DICT) { const char* key = va_arg(v, const char*); current = plist_dict_get_item(current, key); } } return current; }
/** * Internal function used by lockdownd_do_start_service to create the * StartService request's plist. * * @param client The lockdownd client * @param identifier The identifier of the service to start * @param send_escrow_bag Should we send the device's escrow bag with the request * @param request The request's plist on success, NULL on failure * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_CONF on failure * to read the escrow bag from the device's record (when used). */ static lockdownd_error_t lockdownd_build_start_service_request(lockdownd_client_t client, const char *identifier, int send_escrow_bag, plist_t *request) { plist_t dict = plist_new_dict(); /* create the basic request params */ plist_dict_add_label(dict, client->label); plist_dict_set_item(dict, "Request", plist_new_string("StartService")); plist_dict_set_item(dict, "Service", plist_new_string(identifier)); /* if needed - get the escrow bag for the device and send it with the request */ if (send_escrow_bag) { /* get the pairing record */ plist_t pair_record = NULL; userpref_read_pair_record(client->udid, &pair_record); if (!pair_record) { debug_info("ERROR: failed to read pair record for device: %s", client->udid); plist_free(dict); return LOCKDOWN_E_INVALID_CONF; } /* try to read the escrow bag from the record */ plist_t escrow_bag = plist_dict_get_item(pair_record, USERPREF_ESCROW_BAG_KEY); if (!escrow_bag || (PLIST_DATA != plist_get_node_type(escrow_bag))) { debug_info("ERROR: Failed to retrieve the escrow bag from the device's record"); plist_free(dict); plist_free(pair_record); return LOCKDOWN_E_INVALID_CONF; } debug_info("Adding escrow bag to StartService for %s", identifier); plist_dict_set_item(dict, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag)); plist_free(pair_record); } *request = dict; return LOCKDOWN_E_SUCCESS; }
static int extract_raw_crash_report(const char* filename) { int res = 0; plist_t report = NULL; char* raw = NULL; char* raw_filename = strdup(filename); /* create filename with '.crash' extension */ char* p = strrchr(raw_filename, '.'); if ((p == NULL) || (strcmp(p, ".plist") != 0)) { free(raw_filename); return res; } strcpy(p, ".crash"); /* read plist crash report */ if (plist_read_from_filename(&report, filename)) { plist_t description_node = plist_dict_get_item(report, "description"); if (description_node && plist_get_node_type(description_node) == PLIST_STRING) { plist_get_string_val(description_node, &raw); if (raw != NULL) { /* write file */ buffer_write_to_filename(raw_filename, raw, strlen(raw)); free(raw); res = 1; } } } if (report) plist_free(report); if (raw_filename) free(raw_filename); return res; }
static void process_pl_items(plist_t items, int pl_id) { plist_t trk; uint64_t itml_id; uint32_t db_id; uint32_t alen; uint32_t i; int ret; alen = plist_array_get_size(items); for (i = 0; i < alen; i++) { trk = plist_array_get_item(items, i); if (plist_get_node_type(trk) != PLIST_DICT) continue; ret = get_dictval_int_from_key(trk, "Track ID", &itml_id); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "No Track ID found for playlist item %u\n", i); continue; } db_id = id_map_get(itml_id); if (!db_id) { DPRINTF(E_INFO, L_SCAN, "Track ID %" PRIu64 " dropped\n", itml_id); continue; } ret = db_pl_add_item_byid(pl_id, db_id); if (ret < 0) DPRINTF(E_WARN, L_SCAN, "Could not add ID %d to playlist\n", db_id); } }
LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list) { plist_t node = NULL; if (status && plist_get_node_type(status) == PLIST_DICT) { /* command specific logic: parse browsed list */ if (list != NULL) { node = plist_dict_get_item(status, "CurrentList"); if (node) { *current_amount = plist_array_get_size(node); *list = plist_copy(node); } } if (total != NULL) { node = plist_dict_get_item(status, "Total"); if (node) { plist_get_uint_val(node, total); } } if (current_amount != NULL) { node = plist_dict_get_item(status, "CurrentAmount"); if (node) { plist_get_uint_val(node, current_amount); } } if (current_index != NULL) { node = plist_dict_get_item(status, "CurrentIndex"); if (node) { plist_get_uint_val(node, current_index); } } } }
/** * Installs the given provisioning profile. Only works with valid profiles. * * @param client The connected misagent to use for installation * @param profile The valid provisioning profile to install. This has to be * passed as a PLIST_DATA, otherwise the function will fail. * * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when * client is invalid, or an MISAGENT_E_* error code otherwise. */ misagent_error_t misagent_install(misagent_client_t client, plist_t profile) { if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA)) return MISAGENT_E_INVALID_ARG; client->last_error = MISAGENT_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Install")); plist_dict_insert_item(dict, "Profile", plist_copy(profile)); plist_dict_insert_item(dict, "ProfileType", plist_new_string("Provisioning")); misagent_error_t res = misagent_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = NULL; if (res != MISAGENT_E_SUCCESS) { debug_info("could not send plist, error %d", res); return res; } res = misagent_error(property_list_service_receive_plist(client->parent, &dict)); if (res != MISAGENT_E_SUCCESS) { debug_info("could not receive response, error %d", res); return res; } if (!dict) { debug_info("could not get response plist"); return MISAGENT_E_UNKNOWN_ERROR; } res = misagent_check_result(dict, &client->last_error); plist_free(dict); return res; }
static void xml_to_node(xmlNodePtr xml_node, plist_t * plist_node) { xmlNodePtr node = NULL; plist_data_t data = NULL; plist_t subnode = NULL; //for string long len = 0; int type = 0; if (!xml_node) return; for (node = xml_node->children; node; node = node->next) { while (node && !xmlStrcmp(node->name, XPLIST_TEXT)) node = node->next; if (!node) break; if (!xmlStrcmp(node->name, BAD_CAST("comment"))) { continue; } data = plist_new_plist_data(); subnode = plist_new_node(data); if (*plist_node) node_attach(*plist_node, subnode); else *plist_node = subnode; if (!xmlStrcmp(node->name, XPLIST_TRUE)) { data->boolval = TRUE; data->type = PLIST_BOOLEAN; data->length = 1; continue; } if (!xmlStrcmp(node->name, XPLIST_FALSE)) { data->boolval = FALSE; data->type = PLIST_BOOLEAN; data->length = 1; continue; } if (!xmlStrcmp(node->name, XPLIST_INT)) { xmlChar *strval = xmlNodeGetContent(node); int is_negative = 0; char *str = (char*)strval; if ((str[0] == '-') || (str[0] == '+')) { if (str[0] == '-') { is_negative = 1; } str++; } char* endp = NULL; data->intval = strtoull((char*)str, &endp, 0); if ((endp != NULL) && (strlen(endp) > 0)) { fprintf(stderr, "%s: integer parse error: string contains invalid characters: '%s'\n", __func__, endp); } if (is_negative || (data->intval <= INT64_MAX)) { int64_t v = data->intval; if (is_negative) { v = -v; } data->intval = (uint64_t)v; data->length = 8; } else { data->length = 16; } data->type = PLIST_UINT; xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_REAL)) { xmlChar *strval = xmlNodeGetContent(node); data->realval = atof((char *) strval); data->type = PLIST_REAL; data->length = 8; xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_DATE)) { xmlChar *strval = xmlNodeGetContent(node); time_t timev = 0; if (strlen((const char*)strval) >= 11) { struct tm btime; struct tm* tm_utc; parse_date((const char*)strval, &btime); timev = mktime(&btime); tm_utc = gmtime(&timev); timev -= (mktime(tm_utc) - timev); } data->timeval.tv_sec = (long)(timev - MAC_EPOCH); data->timeval.tv_usec = 0; data->type = PLIST_DATE; data->length = sizeof(struct timeval); xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_STRING)) { xmlChar *strval = xmlNodeGetContent(node); len = strlen((char *) strval); type = xmlDetectCharEncoding(strval, len); if (XML_CHAR_ENCODING_UTF8 == type || XML_CHAR_ENCODING_ASCII == type || XML_CHAR_ENCODING_NONE == type) { data->strval = strdup((char *) strval); data->type = PLIST_STRING; data->length = strlen(data->strval); } xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_KEY)) { xmlChar *strval = xmlNodeGetContent(node); len = strlen((char *) strval); type = xmlDetectCharEncoding(strval, len); if (XML_CHAR_ENCODING_UTF8 == type || XML_CHAR_ENCODING_ASCII == type || XML_CHAR_ENCODING_NONE == type) { data->strval = strdup((char *) strval); data->type = PLIST_KEY; data->length = strlen(data->strval); } xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_DATA)) { xmlChar *strval = xmlNodeGetContent(node); size_t size = 0; unsigned char *dec = base64decode((char*)strval, &size); data->buff = (uint8_t *) malloc(size * sizeof(uint8_t)); memcpy(data->buff, dec, size * sizeof(uint8_t)); free(dec); data->length = size; data->type = PLIST_DATA; xmlFree(strval); continue; } if (!xmlStrcmp(node->name, XPLIST_ARRAY)) { data->type = PLIST_ARRAY; xml_to_node(node, &subnode); continue; } if (!xmlStrcmp(node->name, XPLIST_DICT)) { data->type = PLIST_DICT; xml_to_node(node, &subnode); if (plist_get_node_type(subnode) == PLIST_DICT) { if (plist_dict_get_size(subnode) == 1) { plist_t uid = plist_dict_get_item(subnode, "CF$UID"); if (uid) { uint64_t val = 0; plist_get_uint_val(uid, &val); plist_dict_remove_item(subnode, "CF$UID"); plist_data_t nodedata = plist_get_data((node_t*)subnode); free(nodedata->buff); nodedata->type = PLIST_UID; nodedata->length = sizeof(uint64_t); nodedata->intval = val; } } } continue; } } }
void plist_get_data_val(plist_t node, char **val, uint64_t * length) { plist_type type = plist_get_node_type(node); if (PLIST_DATA == type) plist_get_type_and_value(node, &type, (void *) val, length); }
static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t* device) { int num_devices = 0; char **devices = NULL; idevice_get_device_list(&devices, &num_devices); if (num_devices == 0) { return -1; } *device = NULL; idevice_t dev = NULL; idevice_error_t device_error; lockdownd_client_t lockdown = NULL; int j; for (j = 0; j < num_devices; j++) { if (lockdown != NULL) { lockdownd_client_free(lockdown); lockdown = NULL; } if (dev != NULL) { idevice_free(dev); dev = NULL; } device_error = idevice_new(&dev, devices[j]); if (device_error != IDEVICE_E_SUCCESS) { error("ERROR: %s: can't open device with UUID %s", __func__, devices[j]); continue; } if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) { error("ERROR: %s: can't connect to lockdownd on device with UUID %s", __func__, devices[j]); continue; } char* type = NULL; if (lockdownd_query_type(lockdown, &type) != LOCKDOWN_E_SUCCESS) { continue; } if (strcmp(type, "com.apple.mobile.lockdown") != 0) { free(type); continue; } free(type); if (client->ecid != 0) { plist_t node = NULL; if ((lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_UINT)){ if (node) { plist_free(node); } continue; } lockdownd_client_free(lockdown); lockdown = NULL; uint64_t this_ecid = 0; plist_get_uint_val(node, &this_ecid); plist_free(node); if (this_ecid != client->ecid) { continue; } } if (lockdown) { lockdownd_client_free(lockdown); lockdown = NULL; } client->uuid = strdup(devices[j]); *device = dev; break; } idevice_device_list_free(devices); 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; 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; } }
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; }
int main(int argc, char *argv[]) { lockdownd_client_t client = NULL; idevice_t phone = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; int i; int simple = 0; int format = FORMAT_KEY_VALUE; char uuid[41]; char *domain = NULL; char *key = NULL; char *xml_doc = NULL; uint32_t xml_length; plist_t node = NULL; plist_type node_type; uuid[0] = 0; /* 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], "--uuid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); return 0; } strcpy(uuid, argv[i]); continue; } else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--domain")) { i++; if (!argv[i] || (strlen(argv[i]) < 4)) { print_usage(argc, argv); return 0; } if (!is_domain_known(argv[i])) { fprintf(stderr, "WARNING: Sending query with unknown domain \"%s\".\n", argv[i]); } domain = strdup(argv[i]); continue; } else if (!strcmp(argv[i], "-k") || !strcmp(argv[i], "--key")) { i++; if (!argv[i] || (strlen(argv[i]) <= 1)) { print_usage(argc, argv); return 0; } key = strdup(argv[i]); continue; } else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) { format = FORMAT_XML; continue; } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--simple")) { simple = 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 (uuid[0] != 0) { ret = idevice_new(&phone, uuid); if (ret != IDEVICE_E_SUCCESS) { printf("No device found with uuid %s, is it plugged in?\n", uuid); return -1; } } else { ret = idevice_new(&phone, NULL); if (ret != IDEVICE_E_SUCCESS) { printf("No device found, is it plugged in?\n"); return -1; } } if (LOCKDOWN_E_SUCCESS != (simple ? lockdownd_client_new(phone, &client, "ideviceinfo"): lockdownd_client_new_with_handshake(phone, &client, "ideviceinfo"))) { idevice_free(phone); return -1; } /* run query and output information */ if(lockdownd_get_value(client, domain, key, &node) == LOCKDOWN_E_SUCCESS) { if (node) { switch (format) { case FORMAT_XML: plist_to_xml(node, &xml_doc, &xml_length); printf("%s", xml_doc); free(xml_doc); break; case FORMAT_KEY_VALUE: node_type = plist_get_node_type(node); if (node_type == PLIST_DICT) { plist_dict_to_string(node); } else if (node_type == PLIST_ARRAY) { plist_array_to_string(node); break; } default: if (key != NULL) plist_node_to_string(node); break; } plist_free(node); node = NULL; } } if (domain != NULL) free(domain); lockdownd_client_free(client); idevice_free(phone); return 0; }