1 /* Copyright (c) 2009, Martin S. <opensuse@sukimashita.com>
2  *
3  * The code contained in this file is free software; you can redistribute
4  * it and/or modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either version
6  * 2.1 of the License, or (at your option) any later version.
7  *
8  * This file is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this code; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  * iTunes and iPod are trademarks of Apple
18  *
19  * This product is not supported/written/published by Apple!
20  *
21  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include <glib.h>
31 #include <libxml/xmlmemory.h>
32 
33 #include <libimobiledevice/afc.h>
34 #include <libimobiledevice/libimobiledevice.h>
35 #include <libimobiledevice/lockdown.h>
36 
37 #include "itdb-syslog.h"
38 
39 extern char *read_sysinfo_extended_by_uuid (const char *uuid);
40 extern gboolean iphone_write_sysinfo_extended (const char *uuid, const char *xml);
41 
42 G_GNUC_INTERNAL char *
read_sysinfo_extended_by_uuid(const char * uuid)43 read_sysinfo_extended_by_uuid (const char *uuid)
44 {
45 	lockdownd_client_t client = NULL;
46 	idevice_t device = NULL;
47 	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
48 	lockdownd_error_t lockdown_ret;
49 	char *xml = NULL; char *str = NULL;
50 	char *gxml = NULL;
51 	uint32_t xml_length = 0;
52 	plist_t value = NULL;
53 	plist_t global = NULL;
54 	plist_t ptr = NULL;
55 	int cnt = 0;
56 
57 	/* usbmuxd needs some time to start up so we try several times
58 	 * to open the device before finally returning with an error */
59 	while (cnt++ < 20) {
60 		ret = idevice_new(&device, uuid);
61 		if (ret == IDEVICE_E_SUCCESS) {
62 			break;
63 		}
64 		if (ret != IDEVICE_E_NO_DEVICE) {
65 			break;
66 		}
67 		g_usleep (G_USEC_PER_SEC / 2);
68 	}
69 	if (ret != IDEVICE_E_SUCCESS) {
70 		itdb_syslog("No device found with uuid %s, is it plugged in?\n", uuid);
71 		goto error;
72 	}
73 
74 	lockdown_ret = lockdownd_client_new_with_handshake(device, &client, "libgpod");
75 	if (lockdown_ret != LOCKDOWN_E_SUCCESS) {
76 		itdb_syslog("Client creation/handshake failed: %d\n", lockdown_ret);
77 		goto error;
78 	}
79 
80 	/* run query and get format plist */
81 	lockdown_ret = lockdownd_get_value(client, NULL, NULL, &global);
82 	if (lockdown_ret != LOCKDOWN_E_SUCCESS) {
83 		itdb_syslog("Could not get global domain plist: %d\n", lockdown_ret);
84 		goto error;
85 	}
86 	lockdown_ret = lockdownd_get_value(client, "com.apple.mobile.iTunes",
87 					   NULL, &value);
88 	if (lockdown_ret != LOCKDOWN_E_SUCCESS) {
89 		itdb_syslog("Could not get 'com.apple.mobile.iTunes' domain plist: %d\n",
90 			    lockdown_ret);
91 		goto error;
92 	}
93 
94 	/* add some required values manually to emulate old plist format */
95 	ptr = plist_dict_get_item(global, "SerialNumber");
96 	if (ptr == NULL) {
97 		itdb_syslog("Global domain has no 'SerialNumber' key\n");
98 		goto error;
99 	}
100 	plist_get_string_val(ptr, &str);
101 	if (str != NULL) {
102 	    ptr = plist_new_string(str);
103 	    plist_dict_insert_item(value, "SerialNumber", ptr);
104 	    free(str);
105 	}
106 
107 	ptr = plist_dict_get_item(global, "ProductVersion");
108 	if (ptr == NULL) {
109 		itdb_syslog("Global domain has no 'ProductVersion' key\n");
110 		goto error;
111 	}
112 	plist_get_string_val(ptr, &str);
113 	if (str != NULL) {
114 	    ptr = plist_new_string(str);
115 	    plist_dict_insert_item(value, "VisibleBuildID", ptr);
116 	    free(str);
117 	}
118 
119 	ptr = plist_new_string(uuid);
120 	plist_dict_insert_item(value, "FireWireGUID", ptr);
121 
122 	ptr = plist_new_string(uuid);
123 	plist_dict_insert_item(value, "UniqueDeviceID", ptr);
124 
125 	plist_to_xml(value, &xml, &xml_length);
126 
127 	ptr = NULL;
128 
129 	/* Jump through hoops since libxml will say to free mem it allocated
130 	 * with xmlFree while memory freed with g_free has to be allocated
131 	 * by glib.
132 	 */
133 	if (xml != NULL) {
134 		gxml = g_strdup(xml);
135 		xmlFree(xml);
136 	}
137 error:
138 	if (global != NULL)
139 		plist_free(global);
140 	if (value != NULL)
141 		plist_free(value);
142 	if (client != NULL)
143 	    lockdownd_client_free(client);
144 	if (device != NULL)
145 	    idevice_free(device);
146 
147 	return gxml;
148 
149 }
150 
151 G_GNUC_INTERNAL gboolean
iphone_write_sysinfo_extended(const char * uuid,const char * xml)152 iphone_write_sysinfo_extended (const char *uuid, const char *xml)
153 {
154 	lockdownd_client_t client = NULL;
155 	idevice_t device = NULL;
156 	afc_client_t afc = NULL;
157 	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
158 	afc_error_t afc_ret;
159 #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5
160 	lockdownd_service_descriptor_t service;
161 #else
162 	uint16_t afcport = 0;
163 #endif
164 	uint64_t handle;
165 	uint32_t bytes_written;
166 	const char device_dir[] = "/iTunes_Control/Device";
167 	const char sysinfoextended_path[] = "/iTunes_Control/Device/SysInfoExtended";
168 
169 	ret = idevice_new(&device, uuid);
170 	if (IDEVICE_E_SUCCESS != ret) {
171 		itdb_syslog("No device found with uuid %s, is it plugged in?\n", uuid);
172 		return FALSE;
173 	}
174 
175 	if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "libgpod")) {
176 		idevice_free(device);
177 		return FALSE;
178 	}
179 
180 #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5
181 	if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.afc", &service)) {
182 		lockdownd_client_free(client);
183 		idevice_free(device);
184 		return FALSE;
185 	}
186 	g_assert ((service != NULL) && (service->port != 0));
187 	if (AFC_E_SUCCESS != afc_client_new(device, service, &afc)) {
188 		lockdownd_client_free(client);
189 		idevice_free(device);
190 		return FALSE;
191 	}
192 #else
193 	if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.afc", &afcport)) {
194 		lockdownd_client_free(client);
195 		idevice_free(device);
196 		return FALSE;
197 	}
198 	g_assert (afcport != 0);
199 	if (AFC_E_SUCCESS != afc_client_new(device, afcport, &afc)) {
200 		lockdownd_client_free(client);
201 		idevice_free(device);
202 		return FALSE;
203 	}
204 #endif
205 	afc_ret = afc_make_directory(afc, device_dir);
206 	if ((AFC_E_SUCCESS != afc_ret) && (AFC_E_OBJECT_EXISTS != afc_ret)) {
207 		afc_client_free(afc);
208 		lockdownd_client_free(client);
209 		idevice_free(device);
210 		return FALSE;
211 	}
212 	if (AFC_E_SUCCESS != afc_file_open(afc, sysinfoextended_path,
213 					   AFC_FOPEN_WRONLY, &handle)) {
214 		afc_client_free(afc);
215 		lockdownd_client_free(client);
216 		idevice_free(device);
217 		return FALSE;
218 	}
219 
220 	if (AFC_E_SUCCESS != afc_file_write(afc, handle, xml, strlen(xml), &bytes_written)) {
221 		afc_file_close(afc, handle);
222 		afc_client_free(afc);
223 		lockdownd_client_free(client);
224 		idevice_free(device);
225 		return FALSE;
226 	}
227 
228 	afc_file_close(afc, handle);
229 	afc_client_free(afc);
230 	lockdownd_client_free(client);
231 	idevice_free(device);
232 
233 	return TRUE;
234 }
235