int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) { unsigned int size = 0; unsigned char* data = NULL; *tss_enabled = 0; /* older devices don't require personalized firmwares and use a BuildManifesto.plist */ if (ipsw_file_exists(ipsw, "BuildManifesto.plist") == 0) { if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) { plist_from_xml((char*)data, size, buildmanifest); free(data); return 0; } } data = NULL; size = 0; /* whereas newer devices do not require personalized firmwares and use a BuildManifest.plist */ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) == 0) { *tss_enabled = 1; plist_from_xml((char*)data, size, buildmanifest); free(data); return 0; } return -1; }
int asr_receive(asr_client_t asr, plist_t* data) { uint32_t size = 0; char* buffer = NULL; plist_t request = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; *data = NULL; buffer = (char*) malloc(ASR_BUFFER_SIZE); if (buffer == NULL) { error("ERROR: Unable to allocate memory for ASR receive buffer\n"); return -1; } memset(buffer, '\0', ASR_BUFFER_SIZE); device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size); if (device_error != IDEVICE_E_SUCCESS) { error("ERROR: Unable to receive data from ASR\n"); free(buffer); return -1; } plist_from_xml(buffer, size, &request); *data = request; debug("Received %d bytes:\n", size); if (idevicerestore_debug) debug_plist(request); free(buffer); return 0; }
const CharVt& PlistEntry::GetBinPlist(CharVt&& xmlBuff) { GuardedPlist plist; plist_from_xml( xmlBuff.data(), xmlBuff.size(), plist.get_ptr() ); uint32_t cbBinXML = 0; char* pBinXML{}; plist_to_bin( plist, &pBinXML, &cbBinXML ); if ( cbBinXML > 0 ) { rawFileBuff_.assign( pBinXML, pBinXML + cbBinXML ); free( pBinXML ); } else { rawFileBuff_.clear(); } if ( rawFileBuff_.empty() ) { contentType_ = ContentType::corrupted; throw std::runtime_error( "error converting xml to bplist - bplist will be restored." ); } contentType_ = ContentType::raw; return rawFileBuff_; }
/** * Receives a plist using the given property list service client. * Internally used generic plist receive function. * * @param client The property list service client to use for receiving * @param plist pointer to a plist_t that will point to the received plist * upon successful return * @param timeout Maximum time in milliseconds to wait for data. * * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR * when an unspecified error occurs. */ static property_list_service_error_t internal_plist_receive_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) { property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; uint32_t pktlen = 0; uint32_t bytes = 0; if (!client || (client && !client->connection) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; } idevice_connection_receive_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); debug_info("initial read=%i", bytes); if (bytes < 4) { debug_info("initial read failed!"); return PROPERTY_LIST_SERVICE_E_MUX_ERROR; } else { pktlen = be32toh(pktlen); if (pktlen < (1 << 24)) { /* prevent huge buffers */ uint32_t curlen = 0; char *content = NULL; debug_info("%d bytes following", pktlen); content = (char*)malloc(pktlen); while (curlen < pktlen) { idevice_connection_receive(client->connection, content+curlen, pktlen-curlen, &bytes); if (bytes <= 0) { res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; break; } debug_info("received %d bytes", bytes); curlen += bytes; } if (!memcmp(content, "bplist00", 8)) { plist_from_bin(content, pktlen, plist); } else { /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */ for (bytes = 0; bytes < pktlen-1; bytes++) { if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) content[bytes] = 0x20; } plist_from_xml(content, pktlen, plist); } if (*plist) { debug_plist(*plist); res = PROPERTY_LIST_SERVICE_E_SUCCESS; } else { res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; } free(content); content = NULL; } else { res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; } } return res; }
int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) { unsigned int size = 0; unsigned char* data = NULL; if (ipsw_extract_to_memory(ipsw, "Restore.plist", &data, &size) == 0) { plist_from_xml((char*)data, size, restore_plist); free(data); return 0; } return -1; }
static int load_version_data(struct idevicerestore_client_t* client) { if (!client) { return -1; } struct stat fst; int cached = 0; if ((stat(VERSION_XML, &fst) < 0) || ((time(NULL)-86400) > fst.st_mtime)) { char tmpf[256]; tmpf[0] = '\0'; if (!tmpnam(tmpf) || (tmpf[0] == '\0')) { error("ERROR: Could not get temporary filename\n"); return -1; } if (download_to_file("http://ax.itunes.apple.com/check/version", tmpf) == 0) { __mkdir("cache", 0755); remove(VERSION_XML); if (rename(tmpf, VERSION_XML) < 0) { error("ERROR: Could not update '" VERSION_XML "'\n"); } else { info("NOTE: Updated version data.\n"); } } } else { cached = 1; } char *verbuf = NULL; size_t verlen = 0; read_file(VERSION_XML, (void**)&verbuf, &verlen); if (!verbuf) { error("ERROR: Could not load '" VERSION_XML "'.\n"); return -1; } client->version_data = NULL; plist_from_xml(verbuf, verlen, &client->version_data); if (!client->version_data) { error("ERROR: Cannot parse plist data from '" VERSION_XML "'.\n"); return -1; } if (cached) { info("NOTE: using cached version data\n"); } return 0; }
PLIST_API void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist) { if (length < 8) { *plist = NULL; return; } if (plist_is_binary(plist_data, length)) { plist_from_bin(plist_data, length, plist); } else { plist_from_xml(plist_data, length, plist); } }
int isManifestSignedForDevice(char *buildManifestPath, char **device, uint64_t ecid, int checkBaseband, char **version){ int isSigned = 0; #define reterror(a ...) {error(a); isSigned = -1; goto error;} plist_t manifest = NULL; plist_t ProductVersion = NULL; plist_t SupportedProductTypes = NULL; plist_t mDevice = NULL; info("[TSSC] opening %s\n",buildManifestPath); //filehandling FILE *fmanifest = fopen(buildManifestPath, "r"); if (!fmanifest) reterror("[TSSC] ERROR: file %s nof found!\n",buildManifestPath); fseek(fmanifest, 0, SEEK_END); long fsize = ftell(fmanifest); fseek(fmanifest, 0, SEEK_SET); char *bufManifest = (char*)malloc(fsize + 1); fread(bufManifest, fsize, 1, fmanifest); fclose(fmanifest); plist_from_xml(bufManifest, (unsigned)strlen(bufManifest), &manifest); if (version && !*version){ if (!manifest){ warning("[TSSC] WARNING: could not find ProductVersion in BuildManifest.plist, failing to properly display iOS version\n"); }else{ ProductVersion = plist_dict_get_item(manifest, "ProductVersion"); plist_get_string_val(ProductVersion, version); } } if (!*device) { if (manifest){ SupportedProductTypes = plist_dict_get_item(manifest, "SupportedProductTypes"); if (SupportedProductTypes) { mDevice = plist_array_get_item(SupportedProductTypes, 0); plist_get_string_val(mDevice, device); } } if (!*device) reterror("[TSSR] ERROR: device wasn't specified and could not be fetched from BuildManifest\n") else info("[TSSR] requesting ticket for %s\n",*device); } isSigned = isManifestBufSignedForDevice(bufManifest, *device, ecid, checkBaseband); error: if (manifest) plist_free(manifest); free(bufManifest); return isSigned; #undef reterror }
int fill_in_info() { plist_t *node=NULL; char* type=NULL; char* version=NULL; char* name=NULL; char* img=NULL; lockdownd_get_device_name(client, &name); lockdownd_get_value(client, NULL, "ProductType", &node); plist_get_string_val(node, &type); plist_free(node); node=NULL; lockdownd_get_value(client, NULL, "ProductVersion", &node); plist_get_string_val(node, &version); plist_free(node); node=NULL; plist_from_xml(img_plist, strlen(img_plist), &node); plist_t devNode=plist_dict_get_item(node, type); if (!devNode) { printf("ERROR: Unknown device!\n"); } plist_get_string_val(devNode, &img); plist_free(node); node=NULL; strcpy(data, ""); gtk_image_set_from_file(devImg, img); //gtk_label_set_use_underline(dName, TRUE); char devL[512]=""; snprintf(devL, 512, "<b>%s</b>", name); gtk_label_set_text(dName, name); gtk_label_set_markup(dName, devL); gtk_label_set_text(fV, version); return 0; }
int plist_read_from_filename(plist_t *plist, const char *filename) { char *buffer = NULL; uint64_t length; if (!filename) return 0; buffer_read_from_filename(filename, &buffer, &length); if (!buffer) { return 0; } if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) { plist_from_bin(buffer, length, plist); } else { plist_from_xml(buffer, length, plist); } free(buffer); return 1; }
int main(int argc, char **argv) { // map ctrl-c to quit_flag=1 signal(SIGINT, on_signal); signal(SIGTERM, on_signal); // parse args char *device_id = NULL; bool is_debug = false; int i = 0; for (i = 1; i < argc; i++) { if ((!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) && i + 1 < argc) { free(device_id); device_id = strdup(argv[++i]); } else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { is_debug = true; } else { bool is_help = (!strcmp(argv[i], "h") || !strcmp(argv[i], "--help")); char *name = strrchr(argv[0], '/'); printf("Usage: %s OPTIONS\n" "Minimal iOS webinspector client.\n\n" " -u, --udid UDID\ttarget device by its 40-digit device UDID\n" " -d, --debug\t\tenable communication debugging\n", (name ? name + 1 : argv[0])); return (is_help ? 0 : 1); } } // connect to device char *device_id2 = NULL; int recv_timeout = 1000; int fd = wi_connect(device_id, &device_id2, NULL, recv_timeout); if (fd < 0) { return -1; } // create inspector my_wi_t my_wi = (my_wi_t)malloc(sizeof(struct my_wi_struct)); wi_t wi = wi_new(false); memset(my_wi, 0, sizeof(struct my_wi_struct)); my_wi->device_id = device_id2; my_wi->fd = fd; my_wi->wi = wi; wi->send_packet = send_packet; wi->recv_plist = recv_plist; wi->state = my_wi; wi->is_debug = &is_debug; // send "reportIdentifier" const char *xml = "" "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<plist version=\"1.0\"><dict>\n" " <key>__selector</key><string>_rpc_reportIdentifier:</string>\n" " <key>__argument</key><dict>\n" " <key>WIRConnectionIdentifierKey</key>\n" " <string>077BA242-564F-443B-B83A-EFBB337DAE35</string>\n" "</dict></dict></plist>"; plist_t rpc_dict = NULL; plist_from_xml(xml, strlen(xml), &rpc_dict); wi->send_plist(wi, rpc_dict); plist_free(rpc_dict); // read responses until user presses ctrl-c char buf[1024]; size_t buf_length = 1024; while (!quit_flag) { ssize_t read_bytes = recv(fd, buf, buf_length, 0); if (read_bytes < 0 && errno == EWOULDBLOCK) { continue; } if (wi->on_recv(wi, buf, read_bytes)) { break; } } // cleanup free(my_wi->device_id); wi_free(my_wi->wi); memset(my_wi, 0, sizeof(struct my_wi_struct)); free(my_wi); if (fd >= 0) { close(fd); } return 0; }
int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, unsigned char* nonce, int nonce_size, plist_t build_identity, plist_t* tss) { plist_t request = NULL; plist_t response = NULL; *tss = NULL; if ((client->build[0] <= '8') || (client->flags & FLAG_CUSTOM)) { error("checking for local shsh\n"); /* first check for local copy */ char zfn[512]; if (client->version) { sprintf(zfn, "shsh/" FMT_qu "-%s-%s.shsh", (long long int)client->ecid, client->device->product, client->version); struct stat fst; if (stat(zfn, &fst) == 0) { gzFile zf = gzopen(zfn, "rb"); if (zf) { unsigned char bin[65536]; int blen = gzread(zf, bin, sizeof(bin)); if (blen > 0) { if (memcmp(bin, "bplist00", 8) == 0) { plist_from_bin(bin, blen, tss); } else { plist_from_xml(bin, blen, tss); } } gzclose(zf); } } else { error("no local file %s\n", zfn); } } else { error("No version found?!\n"); } } if (*tss) { info("Using cached SHSH\n"); return 0; } else { info("Trying to fetch new SHSH blob\n"); } request = tss_create_request(build_identity, ecid, nonce, nonce_size); if (request == NULL) { error("ERROR: Unable to create TSS request\n"); return -1; } info("Sending TSS request... "); response = tss_send_request(request); if (response == NULL) { info("ERROR: Unable to send TSS request\n"); plist_free(request); return -1; } info("received SHSH blobs\n"); plist_free(request); *tss = response; return 0; }
plist_t tss_request_send(plist_t tss_request, const char* server_url_string) { if (idevicerestore_debug) { debug_plist(tss_request); } char* request = NULL; int status_code = -1; int retry = 0; int max_retries = 15; unsigned int size = 0; char curl_error_message[CURL_ERROR_SIZE]; const char* urls[6] = { "https://gs.apple.com/TSS/controller?action=2", "https://17.171.36.30/TSS/controller?action=2", "https://17.151.36.30/TSS/controller?action=2", "http://gs.apple.com/TSS/controller?action=2", "http://17.171.36.30/TSS/controller?action=2", "http://17.151.36.30/TSS/controller?action=2" }; plist_to_xml(tss_request, &request, &size); tss_response* response = NULL; memset(curl_error_message, '\0', CURL_ERROR_SIZE); while (retry++ < max_retries) { response = NULL; CURL* handle = curl_easy_init(); if (handle == NULL) { break; } struct curl_slist* header = NULL; header = curl_slist_append(header, "Cache-Control: no-cache"); header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\""); header = curl_slist_append(header, "Expect:"); response = malloc(sizeof(tss_response)); if (response == NULL) { fprintf(stderr, "Unable to allocate sufficent memory\n"); return NULL; } response->length = 0; response->content = malloc(1); response->content[0] = '\0'; /* disable SSL verification to allow download from untrusted https locations */ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request); curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); if (server_url_string) { curl_easy_setopt(handle, CURLOPT_URL, server_url_string); } else { int url_index = (retry - 1) % 6; curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]); info("Request URL set to %s\n", urls[url_index]); } info("Sending TSS request attempt %d... ", retry); curl_easy_perform(handle); curl_slist_free_all(header); curl_easy_cleanup(handle); if (strstr(response->content, "MESSAGE=SUCCESS")) { status_code = 0; info("response successfully received\n"); break; } if (response->length > 0) { error("TSS server returned: %s\n", response->content); } char* status = strstr(response->content, "STATUS="); if (status) { sscanf(status+7, "%d&%*s", &status_code); } if (status_code == -1) { error("%s\n", curl_error_message); // no status code in response. retry free(response->content); free(response); sleep(2); continue; } else if (status_code == 8) { // server error (invalid bb request?) break; } else if (status_code == 49) { // server error (invalid bb data, e.g. BbSNUM?) break; } else if (status_code == 69 || status_code == 94) { // This device isn't eligible for the requested build. break; } else if (status_code == 100) { // server error, most likely the request was malformed break; } else if (status_code == 126) { // An internal error occured, most likely the request was malformed break; } else { error("ERROR: tss_send_request: Unhandled status code %d\n", status_code); } } if (status_code != 0) { if (strstr(response->content, "MESSAGE=") != NULL) { char* message = strstr(response->content, "MESSAGE=") + strlen("MESSAGE="); error("ERROR: TSS request failed (status=%d, message=%s)\n", status_code, message); } else { error("ERROR: TSS request failed: %s (status=%d)\n", curl_error_message, status_code); } free(request); free(response->content); free(response); return NULL; } char* tss_data = strstr(response->content, "<?xml"); if (tss_data == NULL) { error("ERROR: Incorrectly formatted TSS response\n"); free(request); free(response->content); free(response); return NULL; } uint32_t tss_size = 0; plist_t tss_response = NULL; tss_size = response->length - (tss_data - response->content); plist_from_xml(tss_data, tss_size, &tss_response); free(response->content); free(response); if (idevicerestore_debug) { debug_plist(tss_response); } free(request); return tss_response; }
int activate_fetch_record(lockdownd_client_t client, plist_t* record) { int size = 0; char* request = NULL; struct curl_httppost* post = NULL; struct curl_httppost* last = NULL; activate_response* response = NULL; char* imei = NULL; char* imsi = NULL; char* iccid = NULL; char* serial_number = NULL; char* activation_info = NULL; plist_t imei_node = NULL; plist_t imsi_node = NULL; plist_t iccid_node = NULL; plist_t serial_number_node = NULL; plist_t activation_info_node = NULL; char* device_class = NULL; plist_t device_class_node = NULL; lockdownd_get_value(client, NULL, "DeviceClass", &device_class_node); if (!device_class_node || plist_get_node_type(device_class_node) != PLIST_STRING) { fprintf(stderr, "Unable to get DeviceClass from lockdownd\n"); return -1; } plist_get_string_val(device_class_node, &device_class); plist_free(device_class_node); if (!strcmp(device_class, "iPhone")) { lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &iccid_node); if (!iccid_node || plist_get_node_type(iccid_node) != PLIST_STRING) { fprintf(stderr, "Unable to get ICCID from lockdownd\n"); return -1; } plist_get_string_val(iccid_node, &iccid); plist_free(iccid_node); lockdownd_get_value(client, NULL, "InternationalMobileEquipmentIdentity", &imei_node); if (!imei_node || plist_get_node_type(imei_node) != PLIST_STRING) { fprintf(stderr, "Unable to get IMEI from lockdownd\n"); return -1; } plist_get_string_val(imei_node, &imei); plist_free(imei_node); lockdownd_get_value(client, NULL, "InternationalMobileSubscriberIdentity", &imsi_node); if (!imsi_node || plist_get_node_type(imsi_node) != PLIST_STRING) { fprintf(stderr, "Unable to get IMSI from lockdownd\n"); return -1; } plist_get_string_val(imsi_node, &imsi); plist_free(imsi_node); } lockdownd_get_value(client, NULL, "SerialNumber", &serial_number_node); if (!serial_number_node || plist_get_node_type(serial_number_node) != PLIST_STRING) { fprintf(stderr, "Unable to get SerialNumber from lockdownd\n"); return -1; } plist_get_string_val(serial_number_node, &serial_number); plist_free(serial_number_node); lockdownd_get_value(client, NULL, "ActivationInfo", &activation_info_node); int type = plist_get_node_type(activation_info_node); if (!activation_info_node || plist_get_node_type(activation_info_node) != PLIST_DICT) { fprintf(stderr, "Unable to get ActivationInfo from lockdownd\n"); return -1; } //plist_get_string_val(activation_info_node, &activation_info); uint32_t activation_info_size = 0; char* activation_info_data = NULL; plist_to_xml(activation_info_node, &activation_info_data, &activation_info_size); plist_free(activation_info_node); printf("%s\n\n", activation_info_data); char* activation_info_start = strstr(activation_info_data, "<dict>"); if (activation_info_start == NULL) { fprintf(stderr, "Unable to locate beginning of ActivationInfo\n"); return -1; } char* activation_info_stop = strstr(activation_info_data, "</dict>"); if (activation_info_stop == NULL) { fprintf(stderr, "Unable to locate end of ActivationInfo\n"); return -1; } activation_info_stop += strlen("</dict>"); activation_info_size = activation_info_stop - activation_info_start; activation_info = malloc(activation_info_size + 1); memset(activation_info, '\0', activation_info_size + 1); memcpy(activation_info, activation_info_start, activation_info_size); free(activation_info_data); curl_global_init(CURL_GLOBAL_ALL); CURL* handle = curl_easy_init(); if (handle == NULL) { fprintf(stderr, "Unable to initialize libcurl\n"); curl_global_cleanup(); return -1; } curl_formadd(&post, &last, CURLFORM_COPYNAME, "machineName", CURLFORM_COPYCONTENTS, "linux", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "InStoreActivation", CURLFORM_COPYCONTENTS, "false", CURLFORM_END); if (imei != NULL) { curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMEI", CURLFORM_COPYCONTENTS, imei, CURLFORM_END); free(imei); } if (imsi != NULL) { curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMSI", CURLFORM_COPYCONTENTS, imsi, CURLFORM_END); free(imsi); } if (iccid != NULL) { curl_formadd(&post, &last, CURLFORM_COPYNAME, "ICCID", CURLFORM_COPYCONTENTS, iccid, CURLFORM_END); free(iccid); } if (serial_number != NULL) { curl_formadd(&post, &last, CURLFORM_COPYNAME, "AppleSerialNumber", CURLFORM_COPYCONTENTS, serial_number, CURLFORM_END); free(serial_number); } if (activation_info != NULL) { curl_formadd(&post, &last, CURLFORM_COPYNAME, "activation-info", CURLFORM_COPYCONTENTS, activation_info, CURLFORM_END); free(activation_info); } struct curl_slist* header = NULL; header = curl_slist_append(header, "X-Apple-Tz: -14400"); header = curl_slist_append(header, "X-Apple-Store-Front: 143441-1"); response = malloc(sizeof(activate_response)); if (response == NULL) { fprintf(stderr, "Unable to allocate sufficent memory\n"); return -1; } response->length = 0; response->content = malloc(1); curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &activate_write_callback); curl_easy_setopt(handle, CURLOPT_USERAGENT, "iTunes/9.1 (Macintosh; U; Intel Mac OS X 10.5.6)"); curl_easy_setopt(handle, CURLOPT_URL, "https://albert.apple.com/WebObjects/ALUnbrick.woa/wa/deviceActivation"); curl_easy_perform(handle); curl_slist_free_all(header); curl_easy_cleanup(handle); curl_global_cleanup(); uint32_t ticket_size = response->length; char* ticket_data = response->content; char* ticket_start = strstr(ticket_data, "<plist"); if (ticket_start == NULL) { fprintf(stderr, "Unable to locate beginning of ActivationInfo\n"); return -1; } char* ticket_stop = strstr(ticket_data, "</plist>"); if (ticket_stop == NULL) { fprintf(stderr, "Unable to locate end of ActivationInfo\n"); return -1; } ticket_stop += strlen("</plist>"); ticket_size = ticket_stop - ticket_start; char* ticket = malloc(ticket_size + 1); memset(ticket, '\0', ticket_size + 1); memcpy(ticket, ticket_start, ticket_size); //free(ticket_data); printf("%s\n\n", ticket); plist_t ticket_dict = NULL; plist_from_xml(ticket, ticket_size, &ticket_dict); if (ticket_dict == NULL) { printf("Unable to convert activation ticket into plist\n"); return -1; } plist_t iphone_activation_node = plist_dict_get_item(ticket_dict, "iphone-activation"); if (!iphone_activation_node) { iphone_activation_node = plist_dict_get_item(ticket_dict, "device-activation"); if (!iphone_activation_node) { printf("Unable to find device activation node\n"); return -1; } } plist_t activation_record = plist_dict_get_item(iphone_activation_node, "activation-record"); if (!activation_record) { printf("Unable to find activation record node"); return -1; } *record = plist_copy(activation_record); //free(response->content); //free(response); //free(request); return 0; }
static int load_version_data(struct idevicerestore_client_t* client) { if (!client) { return -1; } struct stat fst; int cached = 0; char version_xml[1024]; if (client->cache_dir) { if (stat(client->cache_dir, &fst) < 0) { mkdir_with_parents(client->cache_dir, 0755); } strcpy(version_xml, client->cache_dir); strcat(version_xml, "/"); strcat(version_xml, VERSION_XML); } else { strcpy(version_xml, VERSION_XML); } if ((stat(version_xml, &fst) < 0) || ((time(NULL)-86400) > fst.st_mtime)) { char version_xml_tmp[1024]; strcpy(version_xml_tmp, version_xml); strcat(version_xml_tmp, ".tmp"); if (download_to_file("http://itunes.apple.com/check/version", version_xml_tmp, 0) == 0) { remove(version_xml); if (rename(version_xml_tmp, version_xml) < 0) { error("ERROR: Could not update '%s'\n", version_xml); } else { info("NOTE: Updated version data.\n"); } } } else { cached = 1; } char *verbuf = NULL; size_t verlen = 0; read_file(version_xml, (void**)&verbuf, &verlen); if (!verbuf) { error("ERROR: Could not load '%s'\n", version_xml); return -1; } client->version_data = NULL; plist_from_xml(verbuf, verlen, &client->version_data); free(verbuf); if (!client->version_data) { error("ERROR: Cannot parse plist data from '%s'.\n", version_xml); return -1; } if (cached) { info("NOTE: using cached version data\n"); } return 0; }
plist_t tss_send_request(plist_t tss_request) { curl_global_init(CURL_GLOBAL_ALL); int status_code = -1; char* request = NULL; int retry = 0; int max_retries = 15; unsigned int size = 0; plist_to_xml(tss_request, &request, &size); tss_response* response = NULL; while (retry++ < max_retries) { response = NULL; CURL* handle = curl_easy_init(); if (handle == NULL) { break; } struct curl_slist* header = NULL; header = curl_slist_append(header, "Cache-Control: no-cache"); header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\""); header = curl_slist_append(header, "Expect:"); response = malloc(sizeof(tss_response)); if (response == NULL) { fprintf(stderr, "Unable to allocate sufficent memory\n"); return NULL; } response->length = 0; response->content = malloc(1); response->content[0] = '\0'; curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request); curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); if (use_apple_server==0) { curl_easy_setopt(handle, CURLOPT_URL, "http://cydia.saurik.com/TSS/controller?action=2"); } else { curl_easy_setopt(handle, CURLOPT_URL, "http://gs.apple.com/TSS/controller?action=2"); } curl_easy_perform(handle); curl_slist_free_all(header); curl_easy_cleanup(handle); if (strstr(response->content, "MESSAGE=SUCCESS")) { status_code = 0; break; } if (response->length > 0) { error("TSS server returned: %s\n", response->content); } char* status = strstr(response->content, "STATUS="); if (status) { sscanf(status+7, "%d&%*s", &status_code); } if (status_code == -1) { // no status code in response. retry free(response->content); free(response); sleep(2); continue; } else if (status_code == 94) { // This device isn't eligible for the requested build. break; } else if (status_code == 100) { // server error, most likely the request was malformed break; } else { error("ERROR: tss_send_request: Unhandled status code %d\n", status_code); } } if (status_code != 0) { error("ERROR: TSS request failed (status=%d)\n", status_code); free(response->content); free(response); free(request); return NULL; } char* tss_data = strstr(response->content, "<?xml"); if (tss_data == NULL) { error("ERROR: Incorrectly formatted TSS response\n"); free(response->content); free(response); free(request); return NULL; } uint32_t tss_size = 0; plist_t tss_response = NULL; tss_size = response->length - (tss_data - response->content); plist_from_xml(tss_data, tss_size, &tss_response); free(response->content); free(response); if (idevicerestore_debug) { debug_plist(tss_response); } free(request); curl_global_cleanup(); return tss_response; }
int main(int argc, char **argv) { idevice_t phone = NULL; lockdownd_client_t client = NULL; instproxy_client_t ipc = NULL; instproxy_error_t err; np_client_t np = NULL; afc_client_t afc = NULL; #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 lockdownd_service_descriptor_t service = NULL; #else uint16_t service = 0; #endif int res = 0; char *bundleidentifier = NULL; parse_opts(argc, argv); argc -= optind; argv += optind; if (IDEVICE_E_SUCCESS != idevice_new(&phone, udid)) { fprintf(stderr, "No iOS device found, is it plugged in?\n"); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "ideviceinstaller")) { fprintf(stderr, "Could not connect to lockdownd. Exiting.\n"); goto leave_cleanup; } if ((lockdownd_start_service (client, "com.apple.mobile.notification_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.mobile.notification_proxy!\n"); goto leave_cleanup; } np_error_t nperr = np_client_new(phone, service, &np); #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if (nperr != NP_E_SUCCESS) { fprintf(stderr, "Could not connect to notification_proxy!\n"); goto leave_cleanup; } #ifdef HAVE_LIBIMOBILEDEVICE_1_1 np_set_notify_callback(np, notifier, NULL); #else np_set_notify_callback(np, notifier); #endif const char *noties[3] = { NP_APP_INSTALLED, NP_APP_UNINSTALLED, NULL }; np_observe_notifications(np, noties); run_again: #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.mobile.installation_proxy!\n"); goto leave_cleanup; } err = instproxy_client_new(phone, service, &ipc); #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to installation_proxy!\n"); goto leave_cleanup; } setbuf(stdout, NULL); if (last_status) { free(last_status); last_status = NULL; } notification_expected = 0; if (cmd == CMD_LIST_APPS) { int xml_mode = 0; plist_t client_opts = instproxy_client_options_new(); instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL); plist_t apps = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "list_system")) { if (!client_opts) { client_opts = instproxy_client_options_new(); } instproxy_client_options_add(client_opts, "ApplicationType", "System", NULL); } else if (!strcmp(elem, "list_all")) { instproxy_client_options_free(client_opts); client_opts = NULL; } else if (!strcmp(elem, "list_user")) { /* do nothing, we're already set */ } else if (!strcmp(elem, "xml")) { xml_mode = 1; } elem = strtok(NULL, ","); } free(opts); } err = instproxy_browse(ipc, client_opts, &apps); instproxy_client_options_free(client_opts); if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "ERROR: instproxy_browse returned %d\n", err); goto leave_cleanup; } if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n"); goto leave_cleanup; } if (xml_mode) { char *xml = NULL; uint32_t len = 0; plist_to_xml(apps, &xml, &len); if (xml) { puts(xml); free(xml); } plist_free(apps); goto leave_cleanup; } printf("Total: %d apps\n", plist_array_get_size(apps)); uint32_t i = 0; for (i = 0; i < plist_array_get_size(apps); i++) { plist_t app = plist_array_get_item(apps, i); plist_t p_appid = plist_dict_get_item(app, "CFBundleIdentifier"); char *s_appid = NULL; char *s_dispName = NULL; char *s_version = NULL; plist_t dispName = plist_dict_get_item(app, "CFBundleDisplayName"); plist_t version = plist_dict_get_item(app, "CFBundleVersion"); if (p_appid) { plist_get_string_val(p_appid, &s_appid); } if (!s_appid) { fprintf(stderr, "ERROR: Failed to get APPID!\n"); break; } if (dispName) { plist_get_string_val(dispName, &s_dispName); } if (version) { plist_get_string_val(version, &s_version); } if (!s_dispName) { s_dispName = strdup(s_appid); } if (s_version) { printf("%s - %s %s\n", s_appid, s_dispName, s_version); free(s_version); } else { printf("%s - %s\n", s_appid, s_dispName); } free(s_dispName); free(s_appid); } plist_free(apps); } else if (cmd == CMD_INSTALL || cmd == CMD_UPGRADE) { plist_t sinf = NULL; plist_t meta = NULL; char *pkgname = NULL; struct stat fst; uint64_t af = 0; char buf[8192]; #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.afc!\n"); goto leave_cleanup; } lockdownd_client_free(client); client = NULL; if (afc_client_new(phone, service, &afc) != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to AFC!\n"); goto leave_cleanup; } if (stat(appid, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", appid, strerror(errno)); goto leave_cleanup; } char **strs = NULL; if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); } } if (strs) { int i = 0; while (strs[i]) { free(strs[i]); i++; } free(strs); } plist_t client_opts = instproxy_client_options_new(); /* open install package */ int errp = 0; struct zip *zf = NULL; if ((strlen(appid) > 5) && (strcmp(&appid[strlen(appid)-5], ".ipcc") == 0)) { zf = zip_open(appid, 0, &errp); if (!zf) { fprintf(stderr, "ERROR: zip_open: %s: %d\n", appid, errp); goto leave_cleanup; } char* ipcc = strdup(appid); if ((asprintf(&pkgname, "%s/%s", PKG_PATH, basename(ipcc)) > 0) && pkgname) { afc_make_directory(afc, pkgname); } printf("Uploading %s package contents... ", basename(ipcc)); /* extract the contents of the .ipcc file to PublicStaging/<name>.ipcc directory */ zip_uint64_t numzf = zip_get_num_entries(zf, 0); zip_uint64_t i = 0; for (i = 0; numzf > 0 && i < numzf; i++) { const char* zname = zip_get_name(zf, i, 0); char* dstpath = NULL; if (!zname) continue; if (zname[strlen(zname)-1] == '/') { // directory if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) > 0) && dstpath) { afc_make_directory(afc, dstpath); } free(dstpath); dstpath = NULL; } else { // file struct zip_file* zfile = zip_fopen_index(zf, i, 0); if (!zfile) continue; if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) <= 0) || !dstpath || (afc_file_open(afc, dstpath, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS)) { fprintf(stderr, "ERROR: can't open afc://%s for writing\n", dstpath); free(dstpath); dstpath = NULL; zip_fclose(zfile); continue; } struct zip_stat zs; zip_stat_init(&zs); if (zip_stat_index(zf, i, 0, &zs) != 0) { fprintf(stderr, "ERROR: zip_stat_index %" PRIu64 " failed!\n", i); free(dstpath); dstpath = NULL; zip_fclose(zfile); continue; } free(dstpath); dstpath = NULL; zip_uint64_t zfsize = 0; while (zfsize < zs.size) { zip_int64_t amount = zip_fread(zfile, buf, sizeof(buf)); if (amount == 0) { break; } if (amount > 0) { uint32_t written, total = 0; while (total < amount) { written = 0; if (afc_file_write(afc, af, buf, amount, &written) != AFC_E_SUCCESS) { fprintf(stderr, "AFC Write error!\n"); break; } total += written; } if (total != amount) { fprintf(stderr, "Error: wrote only %d of %" PRIi64 "\n", total, amount); afc_file_close(afc, af); zip_fclose(zfile); free(dstpath); goto leave_cleanup; } } zfsize += amount; } afc_file_close(afc, af); af = 0; zip_fclose(zfile); } } free(ipcc); printf("DONE.\n"); instproxy_client_options_add(client_opts, "PackageType", "CarrierBundle", NULL); } else if (S_ISDIR(fst.st_mode)) { /* upload developer app directory */ instproxy_client_options_add(client_opts, "PackageType", "Developer", NULL); if (asprintf(&pkgname, "%s/%s", PKG_PATH, basename(appid)) < 0) { fprintf(stderr, "ERROR: Out of memory allocating pkgname!?\n"); goto leave_cleanup; } printf("Uploading %s package contents... ", basename(appid)); afc_upload_dir(afc, appid, pkgname); printf("DONE.\n"); } else { zf = zip_open(appid, 0, &errp); if (!zf) { fprintf(stderr, "ERROR: zip_open: %s: %d\n", appid, errp); goto leave_cleanup; } /* extract iTunesMetadata.plist from package */ char *zbuf = NULL; uint32_t len = 0; plist_t meta_dict = NULL; if (zip_get_contents(zf, ITUNES_METADATA_PLIST_FILENAME, 0, &zbuf, &len) == 0) { meta = plist_new_data(zbuf, len); if (memcmp(zbuf, "bplist00", 8) == 0) { plist_from_bin(zbuf, len, &meta_dict); } else { plist_from_xml(zbuf, len, &meta_dict); } } else { fprintf(stderr, "WARNING: could not locate %s in archive!\n", ITUNES_METADATA_PLIST_FILENAME); } if (zbuf) { free(zbuf); } /* determine .app directory in archive */ zbuf = NULL; len = 0; plist_t info = NULL; char* filename = NULL; char* app_directory_name = NULL; if (zip_get_app_directory(zf, &app_directory_name)) { fprintf(stderr, "Unable to locate app directory in archive!\n"); goto leave_cleanup; } /* construct full filename to Info.plist */ filename = (char*)malloc(strlen(app_directory_name)+10+1); strcpy(filename, app_directory_name); free(app_directory_name); app_directory_name = NULL; strcat(filename, "Info.plist"); if (zip_get_contents(zf, filename, 0, &zbuf, &len) < 0) { fprintf(stderr, "WARNING: could not locate %s in archive!\n", filename); free(filename); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } free(filename); if (memcmp(zbuf, "bplist00", 8) == 0) { plist_from_bin(zbuf, len, &info); } else { plist_from_xml(zbuf, len, &info); } free(zbuf); if (!info) { fprintf(stderr, "Could not parse Info.plist!\n"); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } char *bundleexecutable = NULL; plist_t bname = plist_dict_get_item(info, "CFBundleExecutable"); if (bname) { plist_get_string_val(bname, &bundleexecutable); } bname = plist_dict_get_item(info, "CFBundleIdentifier"); if (bname) { plist_get_string_val(bname, &bundleidentifier); } plist_free(info); info = NULL; if (!bundleexecutable) { fprintf(stderr, "Could not determine value for CFBundleExecutable!\n"); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } char *sinfname = NULL; if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundleexecutable, bundleexecutable) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } free(bundleexecutable); /* extract .sinf from package */ zbuf = NULL; len = 0; if (zip_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) { sinf = plist_new_data(zbuf, len); } else { fprintf(stderr, "WARNING: could not locate %s in archive!\n", sinfname); } free(sinfname); if (zbuf) { free(zbuf); } /* copy archive to device */ pkgname = NULL; if (asprintf(&pkgname, "%s/%s", PKG_PATH, bundleidentifier) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } printf("Copying '%s' to device... ", appid); if (afc_upload_file(afc, appid, pkgname) < 0) { free(pkgname); goto leave_cleanup; } printf("DONE.\n"); if (bundleidentifier) { instproxy_client_options_add(client_opts, "CFBundleIdentifier", bundleidentifier, NULL); } if (sinf) { instproxy_client_options_add(client_opts, "ApplicationSINF", sinf, NULL); } if (meta) { instproxy_client_options_add(client_opts, "iTunesMetadata", meta, NULL); } } if (zf) { zip_unchange_all(zf); zip_close(zf); } /* perform installation or upgrade */ if (cmd == CMD_INSTALL) { printf("Installing '%s'\n", bundleidentifier); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_install(ipc, pkgname, client_opts, status_cb, NULL); #else instproxy_install(ipc, pkgname, client_opts, status_cb); #endif } else { printf("Upgrading '%s'\n", bundleidentifier); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_upgrade(ipc, pkgname, client_opts, status_cb, NULL); #else instproxy_upgrade(ipc, pkgname, client_opts, status_cb); #endif } instproxy_client_options_free(client_opts); free(pkgname); wait_for_op_complete = 1; notification_expected = 1; } else if (cmd == CMD_UNINSTALL) { printf("Uninstalling '%s'\n", appid); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_uninstall(ipc, appid, NULL, status_cb, NULL); #else instproxy_uninstall(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; notification_expected = 0; } else if (cmd == CMD_LIST_ARCHIVES) { int xml_mode = 0; plist_t dict = NULL; plist_t lres = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "xml")) { xml_mode = 1; } elem = strtok(NULL, ","); } } err = instproxy_lookup_archives(ipc, NULL, &dict); if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "ERROR: lookup_archives returned %d\n", err); goto leave_cleanup; } if (!dict) { fprintf(stderr, "ERROR: lookup_archives did not return a plist!?\n"); goto leave_cleanup; } lres = plist_dict_get_item(dict, "LookupResult"); if (!lres || (plist_get_node_type(lres) != PLIST_DICT)) { plist_free(dict); fprintf(stderr, "ERROR: Could not get dict 'LookupResult'\n"); goto leave_cleanup; } if (xml_mode) { char *xml = NULL; uint32_t len = 0; plist_to_xml(lres, &xml, &len); if (xml) { puts(xml); free(xml); } plist_free(dict); goto leave_cleanup; } plist_dict_iter iter = NULL; plist_t node = NULL; char *key = NULL; printf("Total: %d archived apps\n", plist_dict_get_size(lres)); plist_dict_new_iter(lres, &iter); if (!iter) { plist_free(dict); fprintf(stderr, "ERROR: Could not create plist_dict_iter!\n"); goto leave_cleanup; } do { key = NULL; node = NULL; plist_dict_next_item(lres, iter, &key, &node); if (key && (plist_get_node_type(node) == PLIST_DICT)) { char *s_dispName = NULL; char *s_version = NULL; plist_t dispName = plist_dict_get_item(node, "CFBundleDisplayName"); plist_t version = plist_dict_get_item(node, "CFBundleVersion"); if (dispName) { plist_get_string_val(dispName, &s_dispName); } if (version) { plist_get_string_val(version, &s_version); } if (!s_dispName) { s_dispName = strdup(key); } if (s_version) { printf("%s - %s %s\n", key, s_dispName, s_version); free(s_version); } else { printf("%s - %s\n", key, s_dispName); } free(s_dispName); free(key); } } while (node); plist_free(dict); } else if (cmd == CMD_ARCHIVE) { char *copy_path = NULL; int remove_after_copy = 0; int skip_uninstall = 1; int app_only = 0; int docs_only = 0; plist_t client_opts = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "uninstall")) { skip_uninstall = 0; } else if (!strcmp(elem, "app_only")) { app_only = 1; docs_only = 0; } else if (!strcmp(elem, "docs_only")) { docs_only = 1; app_only = 0; } else if ((strlen(elem) > 5) && !strncmp(elem, "copy=", 5)) { copy_path = strdup(elem+5); } else if (!strcmp(elem, "remove")) { remove_after_copy = 1; } elem = strtok(NULL, ","); } } if (skip_uninstall || app_only || docs_only) { client_opts = instproxy_client_options_new(); if (skip_uninstall) { instproxy_client_options_add(client_opts, "SkipUninstall", 1, NULL); } if (app_only) { instproxy_client_options_add(client_opts, "ArchiveType", "ApplicationOnly", NULL); } else if (docs_only) { instproxy_client_options_add(client_opts, "ArchiveType", "DocumentsOnly", NULL); } } if (copy_path) { struct stat fst; if (stat(copy_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", copy_path, strerror(errno)); free(copy_path); goto leave_cleanup; } if (!S_ISDIR(fst.st_mode)) { fprintf(stderr, "ERROR: '%s' is not a directory as expected.\n", copy_path); free(copy_path); goto leave_cleanup; } #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.afc!\n"); free(copy_path); goto leave_cleanup; } lockdownd_client_free(client); client = NULL; if (afc_client_new(phone, service, &afc) != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to AFC!\n"); goto leave_cleanup; } } #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_archive(ipc, appid, client_opts, status_cb, NULL); #else instproxy_archive(ipc, appid, client_opts, status_cb); #endif instproxy_client_options_free(client_opts); wait_for_op_complete = 1; if (skip_uninstall) { notification_expected = 0; } else { notification_expected = 1; } idevice_wait_for_operation_to_complete(); if (copy_path) { if (err_occured) { afc_client_free(afc); afc = NULL; goto leave_cleanup; } FILE *f = NULL; uint64_t af = 0; /* local filename */ char *localfile = NULL; if (asprintf(&localfile, "%s/%s.ipa", copy_path, appid) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } free(copy_path); f = fopen(localfile, "wb"); if (!f) { fprintf(stderr, "ERROR: fopen: %s: %s\n", localfile, strerror(errno)); free(localfile); goto leave_cleanup; } /* remote filename */ char *remotefile = NULL; if (asprintf(&remotefile, "%s/%s.zip", APPARCH_PATH, appid) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } uint32_t fsize = 0; char **fileinfo = NULL; if ((afc_get_file_info(afc, remotefile, &fileinfo) != AFC_E_SUCCESS) || !fileinfo) { fprintf(stderr, "ERROR getting AFC file info for '%s' on device!\n", remotefile); fclose(f); free(remotefile); free(localfile); goto leave_cleanup; } int i; for (i = 0; fileinfo[i]; i+=2) { if (!strcmp(fileinfo[i], "st_size")) { fsize = atoi(fileinfo[i+1]); break; } } i = 0; while (fileinfo[i]) { free(fileinfo[i]); i++; } free(fileinfo); if (fsize == 0) { fprintf(stderr, "Hm... remote file length could not be determined. Cannot copy.\n"); fclose(f); free(remotefile); free(localfile); goto leave_cleanup; } if ((afc_file_open(afc, remotefile, AFC_FOPEN_RDONLY, &af) != AFC_E_SUCCESS) || !af) { fclose(f); fprintf(stderr, "ERROR: could not open '%s' on device for reading!\n", remotefile); free(remotefile); free(localfile); goto leave_cleanup; } /* copy file over */ printf("Copying '%s' --> '%s'... ", remotefile, localfile); free(remotefile); free(localfile); uint32_t amount = 0; uint32_t total = 0; char buf[8192]; do { if (afc_file_read(afc, af, buf, sizeof(buf), &amount) != AFC_E_SUCCESS) { fprintf(stderr, "AFC Read error!\n"); break; } if (amount > 0) { size_t written = fwrite(buf, 1, amount, f); if (written != amount) { fprintf(stderr, "Error when writing %d bytes to local file!\n", amount); break; } total += written; } } while (amount > 0); afc_file_close(afc, af); fclose(f); printf("DONE.\n"); if (total != fsize) { fprintf(stderr, "WARNING: remote and local file sizes don't match (%d != %d)\n", fsize, total); if (remove_after_copy) { fprintf(stderr, "NOTE: archive file will NOT be removed from device\n"); remove_after_copy = 0; } } if (remove_after_copy) { /* remove archive if requested */ printf("Removing '%s'\n", appid); cmd = CMD_REMOVE_ARCHIVE; free(options); options = NULL; if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "ideviceinstaller")) { fprintf(stderr, "Could not connect to lockdownd. Exiting.\n"); goto leave_cleanup; } goto run_again; } } goto leave_cleanup; } else if (cmd == CMD_RESTORE) { #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_restore(ipc, appid, NULL, status_cb, NULL); #else instproxy_restore(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; notification_expected = 1; } else if (cmd == CMD_REMOVE_ARCHIVE) { #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_remove_archive(ipc, appid, NULL, status_cb, NULL); #else instproxy_remove_archive(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; } else { printf ("ERROR: no operation selected?! This should not be reached!\n"); res = -2; goto leave_cleanup; } if (client) { /* not needed anymore */ lockdownd_client_free(client); client = NULL; } idevice_wait_for_operation_to_complete(); leave_cleanup: if (bundleidentifier) { free(bundleidentifier); } if (np) { np_client_free(np); } if (ipc) { instproxy_client_free(ipc); } if (afc) { afc_client_free(afc); } if (client) { lockdownd_client_free(client); } idevice_free(phone); if (udid) { free(udid); } if (appid) { free(appid); } if (options) { free(options); } return res; }
int main(int argc, char *argv[]) { FILE *iplist = NULL; plist_t root_node1 = NULL; plist_t root_node2 = NULL; char *plist_xml = NULL; char *plist_xml2 = NULL; char *plist_bin = NULL; int size_in = 0; uint32_t size_out = 0; uint32_t size_out2 = 0; char *file_in = NULL; char *file_out = NULL; struct stat *filestats = (struct stat *) malloc(sizeof(struct stat)); if (argc != 3) { printf("Wrong input\n"); return 1; } file_in = argv[1]; file_out = argv[2]; //read input file iplist = fopen(file_in, "rb"); if (!iplist) { printf("File does not exists\n"); return 2; } printf("File %s is open\n", file_in); stat(file_in, filestats); size_in = filestats->st_size; plist_xml = (char *) malloc(sizeof(char) * (size_in + 1)); fread(plist_xml, sizeof(char), size_in, iplist); fclose(iplist); //convert one format to another plist_from_xml(plist_xml, size_in, &root_node1); if (!root_node1) { printf("PList XML parsing failed\n"); return 3; } else printf("PList XML parsing succeeded\n"); plist_to_bin(root_node1, &plist_bin, &size_out); if (!plist_bin) { printf("PList BIN writing failed\n"); return 4; } else printf("PList BIN writing succeeded\n"); plist_from_bin(plist_bin, size_out, &root_node2); if (!root_node2) { printf("PList BIN parsing failed\n"); return 5; } else printf("PList BIN parsing succeeded\n"); plist_to_xml(root_node2, &plist_xml2, &size_out2); if (!plist_xml2) { printf("PList XML writing failed\n"); return 8; } else printf("PList XML writing succeeded\n"); if (plist_xml2) { FILE *oplist = NULL; oplist = fopen(file_out, "wb"); fwrite(plist_xml2, size_out2, sizeof(char), oplist); fclose(oplist); } plist_free(root_node1); plist_free(root_node2); free(plist_bin); free(plist_xml); free(plist_xml2); free(filestats); if ((uint32_t)size_in != size_out2) { printf("Size of input and output is different\n"); printf("Input size : %i\n", size_in); printf("Output size : %i\n", size_out2); } //success return 0; }
dl_status dl_recv_packet(dl_t self, const char *packet, size_t length) { dl_private_t my = self->private_state; const char *tail = packet; uint32_t len = dl_sscanf_uint32(tail); tail += 4; if (len != length || len < 16) { return DL_ERROR; } uint32_t version = dl_sscanf_uint32(tail); tail += 4; uint32_t type = dl_sscanf_uint32(tail); tail += 4; (void)dl_sscanf_uint32(tail); tail += 4; const char *xml = tail; size_t xml_length = length - 16; if (version != 1 || type != TYPE_PLIST) { return DL_SUCCESS; // ignore? } plist_t dict = NULL; plist_from_xml(xml, xml_length, &dict); char *message = NULL; if (dict) { plist_t node = plist_dict_get_item(dict, "MessageType"); if (plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &message); } } dl_status ret = DL_ERROR; if (!message) { ret = DL_ERROR; } else if (!strcmp(message, "Result")) { plist_t node = plist_dict_get_item(dict, "Number"); if (node) { uint64_t value = 0; plist_get_uint_val(node, &value); // just an ack of our Listen? ret = (value ? DL_ERROR : DL_SUCCESS); } } else if (!strcmp(message, "Attached")) { plist_t props = plist_dict_get_item(dict, "Properties"); if (props) { uint64_t device_num = 0; plist_t node = plist_dict_get_item(props, "DeviceID"); plist_get_uint_val(node, &device_num); uint64_t product_id = 0; node = plist_dict_get_item(props, "ProductID"); plist_get_uint_val(node, &product_id); char *device_id = NULL; node = plist_dict_get_item(props, "SerialNumber"); if (node) { plist_get_string_val(node, &device_id); } uint64_t location = 0; node = plist_dict_get_item(props, "LocationID"); plist_get_uint_val(node, &location); ht_t d_ht = my->device_num_to_device_id; ht_put(d_ht, HT_KEY(device_num), device_id); ret = self->on_attach(self, device_id, (int)device_num); } } else if (strcmp(message, "Detached") == 0) { plist_t node = plist_dict_get_item(dict, "DeviceID"); if (node) { uint64_t device_num = 0; plist_get_uint_val(node, &device_num); ht_t d_ht = my->device_num_to_device_id; char *device_id = (char *)ht_remove(d_ht, HT_KEY(device_num)); if (device_id) { ret = self->on_detach(self, device_id, (int)device_num); free(device_id); } } } free(message); plist_free(dict); return ret; }
void scan_itunes_itml(const char *file, time_t mtime, int dir_id) { struct playlist_info *pli; struct stat sb; char buf[PATH_MAX]; char *itml_xml; plist_t itml; plist_t node; int fd; int ret; // This is special playlist that is disabled and only used for saving a timestamp pli = db_pl_fetch_bytitlepath(file, file); if (pli) { // mtime == db_timestamp is also treated as a modification because some editors do // stuff like 1) close the file with no changes (leading us to update db_timestamp), // 2) copy over a modified version from a tmp file (which may result in a mtime that // is equal to the newly updated db_timestamp) if (mtime && (pli->db_timestamp > mtime)) { DPRINTF(E_LOG, L_SCAN, "Unchanged iTunes XML found, not processing '%s'\n", file); // TODO Protect the radio stations from purge after scan db_pl_ping_bymatch(file, 0); free_pli(pli, 0); return; } DPRINTF(E_LOG, L_SCAN, "Modified iTunes XML found, processing '%s'\n", file); // Clear out everything, we will recreate db_pl_delete_bypath(file); free_pli(pli, 0); } else { DPRINTF(E_LOG, L_SCAN, "New iTunes XML found, processing: '%s'\n", file); } CHECK_NULL(L_SCAN, pli = calloc(1, sizeof(struct playlist_info))); pli->type = PL_PLAIN; pli->title = strdup(file); pli->path = strdup(file); snprintf(buf, sizeof(buf), "/file:%s", file); pli->virtual_path = strip_extension(buf); pli->directory_id = dir_id; ret = db_pl_add(pli, (int *)&pli->id); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error adding iTunes XML meta playlist '%s'\n", file); free_pli(pli, 0); return; } // Disable, only used for saving timestamp db_pl_disable_bypath(file, STRIP_NONE, 0); free_pli(pli, 0); fd = open(file, O_RDONLY); if (fd < 0) { DPRINTF(E_LOG, L_SCAN, "Could not open iTunes library '%s': %s\n", file, strerror(errno)); return; } ret = fstat(fd, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not stat iTunes library '%s': %s\n", file, strerror(errno)); close(fd); return; } itml_xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (itml_xml == MAP_FAILED) { DPRINTF(E_LOG, L_SCAN, "Could not map iTunes library '%s': %s\n", file, strerror(errno)); close(fd); return; } itml = NULL; plist_from_xml(itml_xml, sb.st_size, &itml); ret = munmap(itml_xml, sb.st_size); if (ret < 0) DPRINTF(E_LOG, L_SCAN, "Could not unmap iTunes library '%s': %s\n", file, strerror(errno)); close(fd); if (!itml) { DPRINTF(E_LOG, L_SCAN, "iTunes XML playlist '%s' failed to parse\n", file); return; } if (plist_get_node_type(itml) != PLIST_DICT) { DPRINTF(E_LOG, L_SCAN, "Malformed iTunes XML playlist '%s'\n", file); plist_free(itml); return; } /* Meta data */ ret = check_meta(itml); if (ret < 0) { plist_free(itml); return; } /* Tracks */ ret = get_dictval_dict_from_key(itml, "Tracks", &node); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not find Tracks dict in '%s'\n", file); plist_free(itml); return; } id_map = calloc(ID_MAP_SIZE, sizeof(struct itml_to_db_map *)); if (!id_map) { DPRINTF(E_FATAL, L_SCAN, "iTunes library parser could not allocate ID map\n"); plist_free(itml); return; } ret = process_tracks(node); if (ret <= 0) { DPRINTF(E_LOG, L_SCAN, "No tracks loaded from iTunes XML '%s'\n", file); id_map_free(); plist_free(itml); return; } DPRINTF(E_LOG, L_SCAN, "Loaded %d tracks from iTunes XML '%s'\n", ret, file); /* Playlists */ ret = get_dictval_array_from_key(itml, "Playlists", &node); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not find Playlists dict in '%s'\n", file); id_map_free(); plist_free(itml); return; } process_pls(node, file); id_map_free(); plist_free(itml); }
void scan_itunes_itml(char *file) { struct stat sb; char *itml_xml; char *ptr; plist_t itml; plist_t node; int fd; int size; int ret; DPRINTF(E_LOG, L_SCAN, "Processing iTunes library: %s\n", file); fd = open(file, O_RDONLY); if (fd < 0) { DPRINTF(E_LOG, L_SCAN, "Could not open iTunes library '%s': %s\n", file, strerror(errno)); return; } ret = fstat(fd, &sb); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not stat iTunes library '%s': %s\n", file, strerror(errno)); close(fd); return; } itml_xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (itml_xml == MAP_FAILED) { DPRINTF(E_LOG, L_SCAN, "Could not map iTunes library: %s\n", strerror(errno)); close(fd); return; } itml = NULL; plist_from_xml(itml_xml, sb.st_size, &itml); ret = munmap(itml_xml, sb.st_size); if (ret < 0) DPRINTF(E_LOG, L_SCAN, "Could not unmap iTunes library: %s\n", strerror(errno)); close(fd); if (!itml) { DPRINTF(E_LOG, L_SCAN, "iTunes XML playlist '%s' failed to parse\n", file); return; } if (plist_get_node_type(itml) != PLIST_DICT) { DPRINTF(E_LOG, L_SCAN, "Malformed iTunes XML playlist '%s'\n", file); plist_free(itml); return; } /* Meta data */ ret = check_meta(itml); if (ret < 0) { plist_free(itml); return; } /* Tracks */ ret = get_dictval_dict_from_key(itml, "Tracks", &node); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not find Tracks dict\n"); plist_free(itml); return; } size = ID_MAP_SIZE * sizeof(struct itml_to_db_map *); id_map = malloc(size); if (!id_map) { DPRINTF(E_FATAL, L_SCAN, "iTunes library parser could not allocate ID map\n"); plist_free(itml); return; } memset(id_map, 0, size); ptr = strrchr(file, '/'); if (!ptr) { DPRINTF(E_FATAL, L_SCAN, "Invalid filename\n"); id_map_free(); plist_free(itml); return; } *ptr = '\0'; ret = process_tracks(node); if (ret <= 0) { DPRINTF(E_LOG, L_SCAN, "No tracks loaded\n"); id_map_free(); plist_free(itml); return; } *ptr = '/'; DPRINTF(E_INFO, L_SCAN, "Loaded %d tracks from iTunes library\n", ret); /* Playlists */ ret = get_dictval_array_from_key(itml, "Playlists", &node); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Could not find Playlists dict\n"); id_map_free(); plist_free(itml); return; } process_pls(node, file); id_map_free(); plist_free(itml); }
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 tssrequest(plist_t *tssrequest, char *buildManifest, char *device, uint64_t ecid, int checkBaseband){ #define reterror(a) {error(a); error = -1; goto error;} int error = 0; plist_t manifest = NULL; plist_t tssparameter = plist_new_dict(); plist_t tssreq = tss_request_new(NULL); plist_from_xml(buildManifest, (unsigned)strlen(buildManifest), &manifest); plist_t buildidentities = plist_dict_get_item(manifest, "BuildIdentities"); if (!buildidentities || plist_get_node_type(buildidentities) != PLIST_ARRAY){ reterror("[TSSR] Error: could not get BuildIdentities\n"); } plist_t id0 = plist_array_get_item(buildidentities, 0); if (!id0 || plist_get_node_type(id0) != PLIST_DICT){ reterror("[TSSR] Error: could not get id0\n"); } plist_t manifestdict = plist_dict_get_item(id0, "Manifest"); if (!manifestdict || plist_get_node_type(manifestdict) != PLIST_DICT){ reterror("[TSSR] Error: could not get manifest\n"); } plist_t sep = plist_dict_get_item(manifestdict, "SEP"); int is64Bit = !(!sep || plist_get_node_type(sep) != PLIST_DICT); tss_populate_random(tssparameter,is64Bit,ecid); tss_parameters_add_from_manifest(tssparameter, id0); if (tss_request_add_common_tags(tssreq, tssparameter, NULL) < 0) { reterror("[TSSR] ERROR: Unable to add common tags to TSS request\n"); } if (tss_request_add_ap_tags(tssreq, tssparameter, NULL) < 0) { reterror("[TSSR] ERROR: Unable to add common tags to TSS request\n"); } if (is64Bit) { if (tss_request_add_ap_img4_tags(tssreq, tssparameter) < 0) { reterror("[TSSR] ERROR: Unable to add img4 tags to TSS request\n"); } } else { if (tss_request_add_ap_img3_tags(tssreq, tssparameter) < 0) { reterror("[TSSR] ERROR: Unable to add img3 tags to TSS request\n"); } } if (checkBaseband) { int64_t BbGoldCertId = getBBGCIDForDevice(device); if (BbGoldCertId < 0) { warning("[TSSR] WARNING: there was an error getting BasebandGoldCertID, continuing without requesting Baseband ticket\n"); }else if (BbGoldCertId) { tss_populate_basebandvals(tssreq,tssparameter,BbGoldCertId); tss_request_add_baseband_tags(tssreq, tssparameter, NULL); }else{ log("[TSSR] LOG: device %s doesn't need a Baseband ticket, continuing without requesting a Baseband ticket\n",device); } }else{ info("[TSSR] User specified not to request a Baseband ticket.\n"); } *tssrequest = tssreq; error: if (manifest) plist_free(manifest); if (tssparameter) plist_free(tssparameter); if (error) plist_free(tssreq), *tssrequest = NULL; return error; #undef reterror }
/** * Checks if a notification has been sent. * * @param client NP to get a notification from * @param notification Pointer to a buffer that will be allocated and filled * with the notification that has been received. * * @return 0 if a notification has been received or nothing has been received, * or an error value if an error occured. * * @note You probably want to check out np_set_notify_callback * @see np_set_notify_callback */ static int np_get_notification(np_client_t client, char **notification) { uint32_t bytes = 0; int res = 0; uint32_t pktlen = 0; char *XML_content = NULL; plist_t dict = NULL; if (!client || !client->connection || *notification) return -1; np_lock(client); iphone_device_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500); log_debug_msg("NotificationProxy: initial read=%i\n", bytes); if (bytes < 4) { log_debug_msg("NotificationProxy: no notification received!\n"); res = 0; } else { if ((char)pktlen == 0) { pktlen = ntohl(pktlen); log_debug_msg("NotificationProxy: %d bytes following\n", pktlen); XML_content = (char*)malloc(pktlen); log_debug_msg("pointer %p\n", XML_content); iphone_device_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000); if (bytes <= 0) { res = -1; } else { log_debug_msg("NotificationProxy: received data:\n"); log_debug_buffer(XML_content, pktlen); plist_from_xml(XML_content, bytes, &dict); if (!dict) { np_unlock(client); return -2; } plist_t cmd_key_node = plist_find_node_by_key(dict, "Command"); plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node); char *cmd_value = NULL; 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, "RelayNotification")) { plist_t name_key_node = plist_get_next_sibling(cmd_value_node); plist_t name_value_node = plist_get_next_sibling(name_key_node); char *name_key = NULL; char *name_value = NULL; if (plist_get_node_type(name_key_node) == PLIST_KEY) { plist_get_key_val(name_key_node, &name_key); } if (plist_get_node_type(name_value_node) == PLIST_STRING) { plist_get_string_val(name_value_node, &name_value); } res = -2; if (name_key && name_value && !strcmp(name_key, "Name")) { *notification = name_value; log_debug_msg("%s: got notification %s\n", __func__, name_value); res = 0; } free(name_key); } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__); res = -1; } else if (cmd_value) { log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__); res = -1; } else { res = -2; } if (cmd_value) { free(cmd_value); } plist_free(dict); dict = NULL; free(XML_content); XML_content = NULL; } } else { res = -1; } } np_unlock(client); return res; }
int main(int argc, char *argv[]) { FILE *iplist1 = NULL; FILE *iplist2 = NULL; plist_t root_node1 = NULL; plist_t root_node2 = NULL; char *plist_1 = NULL; char *plist_2 = NULL; int size_in1 = 0; int size_in2 = 0; char *file_in1 = NULL; char *file_in2 = NULL; int res = 0; struct stat *filestats1 = (struct stat *) malloc(sizeof(struct stat)); struct stat *filestats2 = (struct stat *) malloc(sizeof(struct stat)); if (argc!= 3) { printf("Wrong input\n"); return 1; } file_in1 = argv[1]; file_in2 = argv[2]; //read input file iplist1 = fopen(file_in1, "rb"); iplist2 = fopen(file_in2, "rb"); if (!iplist1 || !iplist2) { printf("File does not exists\n"); return 2; } stat(file_in1, filestats1); stat(file_in2, filestats2); size_in1 = filestats1->st_size; size_in2 = filestats2->st_size; plist_1 = (char *) malloc(sizeof(char) * (size_in1 + 1)); plist_2 = (char *) malloc(sizeof(char) * (size_in2 + 1)); fread(plist_1, sizeof(char), size_in1, iplist1); fread(plist_2, sizeof(char), size_in2, iplist2); fclose(iplist1); fclose(iplist2); if (memcmp(plist_1, "bplist00", 8) == 0) plist_from_bin(plist_1, size_in1, &root_node1); else plist_from_xml(plist_1, size_in1, &root_node1); if (memcmp(plist_2, "bplist00", 8) == 0) plist_from_bin(plist_2, size_in2, &root_node2); else plist_from_xml(plist_2, size_in2, &root_node2); if (!root_node1 || !root_node2) { printf("PList parsing failed\n"); return 3; } else printf("PList parsing succeeded\n"); res = compare_plist(root_node1, root_node2); plist_free(root_node1); plist_free(root_node2); free(plist_1); free(plist_2); free(filestats1); free(filestats2); return !res; }
/** * Receives a plist using the given property list service client. * Internally used generic plist receive function. * * @param client The property list service client to use for receiving * @param plist pointer to a plist_t that will point to the received plist * upon successful return * @param timeout Maximum time in milliseconds to wait for data. * * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success, * PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL, * PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be * converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a * communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR * when an unspecified error occurs. */ static property_list_service_error_t internal_plist_receive_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout) { property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; uint32_t pktlen = 0; uint32_t bytes = 0; if (!client || (client && !client->parent) || !plist) { return PROPERTY_LIST_SERVICE_E_INVALID_ARG; } *plist = NULL; service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout); if ((serr == SERVICE_E_SUCCESS) && (bytes == 0)) { return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT; } debug_info("initial read=%i", bytes); if (bytes < 4) { debug_info("initial read failed!"); return PROPERTY_LIST_SERVICE_E_MUX_ERROR; } else { uint32_t curlen = 0; char *content = NULL; pktlen = be32toh(pktlen); debug_info("%d bytes following", pktlen); content = (char*)malloc(pktlen); if (!content) { debug_info("out of memory when allocating %d bytes", pktlen); return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; } while (curlen < pktlen) { service_receive(client->parent, content+curlen, pktlen-curlen, &bytes); if (bytes <= 0) { res = PROPERTY_LIST_SERVICE_E_MUX_ERROR; break; } debug_info("received %d bytes", bytes); curlen += bytes; } if (curlen < pktlen) { debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen); if (curlen > 0) { debug_info("incomplete packet following:"); debug_buffer(content, curlen); } free(content); return res; } if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) { plist_from_bin(content, pktlen, plist); } else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) { /* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */ for (bytes = 0; bytes < pktlen-1; bytes++) { if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d)) content[bytes] = 0x20; } plist_from_xml(content, pktlen, plist); } else { debug_info("WARNING: received unexpected non-plist content"); debug_buffer(content, pktlen); } if (*plist) { debug_plist(*plist); res = PROPERTY_LIST_SERVICE_E_SUCCESS; } else { res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR; } free(content); content = NULL; } return res; }
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; }
int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, unsigned char* nonce, int nonce_size, plist_t build_identity, plist_t* tss) { plist_t request = NULL; plist_t response = NULL; *tss = NULL; if ((client->build_major <= 8) || (client->flags & FLAG_CUSTOM)) { error("checking for local shsh\n"); /* first check for local copy */ char zfn[1024]; if (client->version) { if (client->cache_dir) { sprintf(zfn, "%s/shsh/" FMT_qu "-%s-%s.shsh", client->cache_dir, (long long int)client->ecid, client->device->product_type, client->version); } else { sprintf(zfn, "shsh/" FMT_qu "-%s-%s.shsh", (long long int)client->ecid, client->device->product_type, client->version); } struct stat fst; if (stat(zfn, &fst) == 0) { gzFile zf = gzopen(zfn, "rb"); if (zf) { int blen = 0; int readsize = 16384; int bufsize = readsize; char* bin = (char*)malloc(bufsize); char* p = bin; do { int bytes_read = gzread(zf, p, readsize); if (bytes_read < 0) { fprintf(stderr, "Error reading gz compressed data\n"); exit(EXIT_FAILURE); } blen += bytes_read; if (bytes_read < readsize) { if (gzeof(zf)) { bufsize += bytes_read; break; } } bufsize += readsize; bin = realloc(bin, bufsize); p = bin + blen; } while (!gzeof(zf)); gzclose(zf); if (blen > 0) { if (memcmp(bin, "bplist00", 8) == 0) { plist_from_bin(bin, blen, tss); } else { plist_from_xml(bin, blen, tss); } } free(bin); } } else { error("no local file %s\n", zfn); } } else { error("No version found?!\n"); } } if (*tss) { info("Using cached SHSH\n"); return 0; } else { info("Trying to fetch new SHSH blob\n"); } request = tss_create_request(build_identity, ecid, nonce, nonce_size); if (request == NULL) { error("ERROR: Unable to create TSS request\n"); return -1; } response = tss_send_request(request, client->tss_url); if (response == NULL) { info("ERROR: Unable to send TSS request\n"); plist_free(request); return -1; } info("Received SHSH blobs\n"); plist_free(request); *tss = response; return 0; }