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