summaryrefslogtreecommitdiffstats
path: root/src/mobileactivation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mobileactivation.c')
-rw-r--r--src/mobileactivation.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/mobileactivation.c b/src/mobileactivation.c
new file mode 100644
index 0000000..fce5f16
--- /dev/null
+++ b/src/mobileactivation.c
@@ -0,0 +1,314 @@
1/*
2 * mobileactivation.c
3 * com.apple.mobileactivationd service implementation.
4 *
5 * Copyright (c) 2016-2017 Nikias Bassen, All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27#include "mobileactivation.h"
28#include "property_list_service.h"
29#include "common/debug.h"
30
31/**
32 * Convert a property_list_service_error_t value to a mobileactivation_error_t value.
33 * Used internally to get correct error codes.
34 *
35 * @param err An property_list_service_error_t error code
36 *
37 * @return A matching mobileactivation_error_t error code,
38 * MOBILEACTIVATION_E_UNKNOWN_ERROR otherwise.
39 */
40static mobileactivation_error_t mobileactivation_error(property_list_service_error_t err)
41{
42 switch (err) {
43 case PROPERTY_LIST_SERVICE_E_SUCCESS:
44 return MOBILEACTIVATION_E_SUCCESS;
45 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
46 return MOBILEACTIVATION_E_INVALID_ARG;
47 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
48 return MOBILEACTIVATION_E_PLIST_ERROR;
49 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
50 return MOBILEACTIVATION_E_MUX_ERROR;
51 default:
52 break;
53 }
54 return MOBILEACTIVATION_E_UNKNOWN_ERROR;
55}
56
57mobileactivation_error_t mobileactivation_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobileactivation_client_t *client)
58{
59 if (!device || !service || service->port == 0 || !client || *client) {
60 return MOBILEACTIVATION_E_INVALID_ARG;
61 }
62
63 property_list_service_client_t plistclient = NULL;
64 if (property_list_service_client_new(device, service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
65 return MOBILEACTIVATION_E_MUX_ERROR;
66 }
67
68 /* create client object */
69 mobileactivation_client_t client_loc = (mobileactivation_client_t) malloc(sizeof(struct mobileactivation_client_private));
70 client_loc->parent = plistclient;
71
72 /* all done, return success */
73 *client = client_loc;
74 return MOBILEACTIVATION_E_SUCCESS;
75}
76
77mobileactivation_error_t mobileactivation_client_start_service(idevice_t device, mobileactivation_client_t * client, const char* label)
78{
79 mobileactivation_error_t err = MOBILEACTIVATION_E_UNKNOWN_ERROR;
80 service_client_factory_start_service(device, MOBILEACTIVATION_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobileactivation_client_new), &err);
81 return err;
82}
83
84mobileactivation_error_t mobileactivation_client_free(mobileactivation_client_t client)
85{
86 if (!client)
87 return MOBILEACTIVATION_E_INVALID_ARG;
88
89 if (property_list_service_client_free(client->parent) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
90 return MOBILEACTIVATION_E_UNKNOWN_ERROR;
91 }
92 free(client);
93 return MOBILEACTIVATION_E_SUCCESS;
94}
95
96static plist_t plist_data_from_plist(plist_t plist)
97{
98 if (plist && plist_get_node_type(plist) == PLIST_DATA) {
99 return plist_copy(plist);
100 }
101 plist_t result = NULL;
102 char *xml = NULL;
103 uint32_t xml_len = 0;
104 plist_to_xml(plist, &xml, &xml_len);
105 result = plist_new_data(xml, xml_len);
106 free(xml);
107 return result;
108}
109
110static mobileactivation_error_t mobileactivation_check_result(plist_t dict, const char *command)
111{
112 if (!dict || plist_get_node_type(dict) != PLIST_DICT) {
113 return MOBILEACTIVATION_E_PLIST_ERROR;
114 }
115
116 plist_t err_node = plist_dict_get_item(dict, "Error");
117 if (!err_node) {
118 return MOBILEACTIVATION_E_SUCCESS;
119 }
120
121 char *errmsg = NULL;
122 plist_get_string_val(err_node, &errmsg);
123 debug_info("ERROR: %s: %s", command, errmsg);
124 free(errmsg);
125 return MOBILEACTIVATION_E_REQUEST_FAILED;
126}
127
128static mobileactivation_error_t mobileactivation_send_command_plist(mobileactivation_client_t client, plist_t command, plist_t *result)
129{
130 if (!client || !command)
131 return MOBILEACTIVATION_E_INVALID_ARG;
132
133 plist_t cmd = plist_dict_get_item(command, "Command");
134 char* command_str = NULL;
135 if (cmd) {
136 plist_get_string_val(cmd, &command_str);
137 }
138 if (!command_str)
139 return MOBILEACTIVATION_E_INVALID_ARG;
140
141 mobileactivation_error_t ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
142 *result = NULL;
143
144 ret = mobileactivation_error(property_list_service_send_binary_plist(client->parent, command));
145
146 plist_t dict = NULL;
147 ret = mobileactivation_error(property_list_service_receive_plist(client->parent, &dict));
148 if (!dict) {
149 debug_info("ERROR: Did not get reply for %s command", command_str);
150 free(command_str);
151 return MOBILEACTIVATION_E_PLIST_ERROR;
152 }
153
154 *result = dict;
155 ret = mobileactivation_check_result(dict, command_str);
156 free(command_str);
157 return ret;
158}
159
160static mobileactivation_error_t mobileactivation_send_command(mobileactivation_client_t client, const char* command, plist_t value, plist_t *result)
161{
162 if (!client || !command || !result)
163 return MOBILEACTIVATION_E_INVALID_ARG;
164
165 mobileactivation_error_t ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
166 *result = NULL;
167
168 plist_t dict = plist_new_dict();
169 plist_dict_set_item(dict, "Command", plist_new_string(command));
170 if (value) {
171 plist_dict_set_item(dict, "Value", plist_copy(value));
172 }
173
174 ret = mobileactivation_send_command_plist(client, dict, result);
175 plist_free(dict);
176 return ret;
177}
178
179mobileactivation_error_t mobileactivation_get_activation_state(mobileactivation_client_t client, plist_t *state)
180{
181 if (!client || !state)
182 return MOBILEACTIVATION_E_INVALID_ARG;
183
184 plist_t result = NULL;
185 mobileactivation_error_t ret = mobileactivation_send_command(client, "GetActivationStateRequest", NULL, &result);
186 if (ret == MOBILEACTIVATION_E_SUCCESS) {
187 plist_t node = plist_dict_get_item(result, "Value");
188 if (!node) {
189 debug_info("ERROR: GetActivationStateRequest command returned success but has no value in reply");
190 ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
191 } else {
192 *state = plist_copy(node);
193 }
194 }
195 plist_free(result);
196 result = NULL;
197
198 return ret;
199}
200
201mobileactivation_error_t mobileactivation_create_activation_session_info(mobileactivation_client_t client, plist_t *blob)
202{
203 if (!client || !blob)
204 return MOBILEACTIVATION_E_INVALID_ARG;
205
206 plist_t result = NULL;
207 mobileactivation_error_t ret = mobileactivation_send_command(client, "CreateTunnel1SessionInfoRequest", NULL, &result);
208 if (ret == MOBILEACTIVATION_E_SUCCESS) {
209 plist_t node = plist_dict_get_item(result, "Value");
210 if (!node) {
211 debug_info("ERROR: CreateTunnel1SessionInfoRequest command returned success but has no value in reply");
212 ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
213 } else {
214 *blob = plist_copy(node);
215 }
216 }
217
218 return ret;
219}
220
221mobileactivation_error_t mobileactivation_create_activation_info(mobileactivation_client_t client, plist_t *info)
222{
223 if (!client || !info)
224 return MOBILEACTIVATION_E_INVALID_ARG;
225
226 plist_t result = NULL;
227 mobileactivation_error_t ret = mobileactivation_send_command(client, "CreateActivationInfoRequest", NULL, &result);
228 if (ret == MOBILEACTIVATION_E_SUCCESS) {
229 plist_t node = plist_dict_get_item(result, "Value");
230 if (!node) {
231 debug_info("ERROR: CreateActivationInfoRequest command returned success but has no value in reply");
232 ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
233 } else {
234 *info = plist_copy(node);
235 }
236 }
237 plist_free(result);
238 result = NULL;
239
240 return ret;
241}
242
243mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info)
244{
245 if (!client || !info)
246 return MOBILEACTIVATION_E_INVALID_ARG;
247
248 plist_t result = NULL;
249 plist_t data = plist_data_from_plist(handshake_response);
250 mobileactivation_error_t ret = mobileactivation_send_command(client, "CreateTunnel1ActivationInfoRequest", data, &result);
251 plist_free(data);
252 if (ret == MOBILEACTIVATION_E_SUCCESS) {
253 plist_t node = plist_dict_get_item(result, "Value");
254 if (!node) {
255 debug_info("ERROR: CreateTunnel1ActivationInfoRequest command returned success but has no value in reply");
256 ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
257 } else {
258 *info = plist_copy(node);
259 }
260 }
261 plist_free(result);
262 result = NULL;
263
264 return ret;
265}
266
267mobileactivation_error_t mobileactivation_activate(mobileactivation_client_t client, plist_t activation_record)
268{
269 if (!client || !activation_record)
270 return MOBILEACTIVATION_E_INVALID_ARG;
271
272 plist_t result = NULL;
273 mobileactivation_error_t ret = mobileactivation_send_command(client, "HandleActivationInfoRequest", activation_record, &result);
274 plist_free(result);
275 result = NULL;
276
277 return ret;
278}
279
280mobileactivation_error_t mobileactivation_activate_with_session(mobileactivation_client_t client, plist_t activation_record, plist_t headers)
281{
282 if (!client || !activation_record)
283 return MOBILEACTIVATION_E_INVALID_ARG;
284
285 plist_t result = NULL;
286
287 plist_t dict = plist_new_dict();
288 plist_dict_set_item(dict, "Command", plist_new_string("HandleActivationInfoWithSessionRequest"));
289 plist_dict_set_item(dict, "Value", plist_data_from_plist(activation_record));
290 if (headers) {
291 plist_dict_set_item(dict, "ActivationResponseHeaders", plist_copy(headers));
292 }
293
294 mobileactivation_error_t ret = mobileactivation_send_command_plist(client, dict, &result);
295 plist_free(dict);
296 plist_free(result);
297 result = NULL;
298
299 return ret;
300}
301
302
303mobileactivation_error_t mobileactivation_deactivate(mobileactivation_client_t client)
304{
305 if (!client)
306 return MOBILEACTIVATION_E_INVALID_ARG;
307
308 plist_t result = NULL;
309 mobileactivation_error_t ret = mobileactivation_send_command(client, "DeactivateRequest", NULL, &result);
310 plist_free(result);
311 result = NULL;
312
313 return ret;
314}