summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/misagent.c306
-rw-r--r--src/misagent.h32
3 files changed, 339 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c7ab0cf..d26baf1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,4 +22,5 @@ libimobiledevice_la_SOURCES = idevice.c idevice.h \
22 mobilebackup.c mobilebackup.h\ 22 mobilebackup.c mobilebackup.h\
23 house_arrest.c house_arrest.h\ 23 house_arrest.c house_arrest.h\
24 mobilebackup2.c mobilebackup2.h\ 24 mobilebackup2.c mobilebackup2.h\
25 misagent.c misagent.h\
25 restore.c restore.h 26 restore.c restore.h
diff --git a/src/misagent.c b/src/misagent.c
new file mode 100644
index 0000000..45f1391
--- /dev/null
+++ b/src/misagent.c
@@ -0,0 +1,306 @@
1/*
2 * misagent.c
3 * com.apple.misagent service implementation.
4 *
5 * Copyright (c) 2012 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#include <string.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <plist/plist.h>
26#include <stdio.h>
27
28#include "misagent.h"
29#include "property_list_service.h"
30#include "debug.h"
31
32/**
33 * Convert a property_list_service_error_t value to a misagent_error_t
34 * value. Used internally to get correct error codes.
35 *
36 * @param err A property_list_service_error_t error code
37 *
38 * @return A matching misagent_error_t error code,
39 * MISAGENT_E_UNKNOWN_ERROR otherwise.
40 */
41static misagent_error_t misagent_error(property_list_service_error_t err)
42{
43 switch (err) {
44 case PROPERTY_LIST_SERVICE_E_SUCCESS:
45 return MISAGENT_E_SUCCESS;
46 case PROPERTY_LIST_SERVICE_E_INVALID_ARG:
47 return MISAGENT_E_INVALID_ARG;
48 case PROPERTY_LIST_SERVICE_E_PLIST_ERROR:
49 return MISAGENT_E_PLIST_ERROR;
50 case PROPERTY_LIST_SERVICE_E_MUX_ERROR:
51 return MISAGENT_E_CONN_FAILED;
52 default:
53 break;
54 }
55 return MISAGENT_E_UNKNOWN_ERROR;
56}
57
58/**
59 * Checks the response from misagent to determine if the operation
60 * was successful or an error occured. Internally used only.
61 *
62 * @param response a PLIST_DICT received from device's misagent
63 * @param status_code pointer to an int that will be set to the status code
64 * contained in the response
65 */
66static misagent_error_t misagent_check_result(plist_t response, int* status_code)
67{
68 if (plist_get_node_type(response) != PLIST_DICT) {
69 return MISAGENT_E_PLIST_ERROR;
70 }
71
72 plist_t node = plist_dict_get_item(response, "Status");
73 if (!node || (plist_get_node_type(node) != PLIST_UINT)) {
74 return MISAGENT_E_PLIST_ERROR;
75 }
76
77 uint64_t val = -1LL;
78 plist_get_uint_val(node, &val);
79 if ((int64_t)val == -1LL) {
80 return MISAGENT_E_PLIST_ERROR;
81 }
82 *status_code = (int)(val & 0xFFFFFFFF);
83 if (*status_code == 0) {
84 return MISAGENT_E_SUCCESS;
85 } else {
86 return MISAGENT_E_REQUEST_FAILED;
87 }
88}
89
90/**
91 * Connects to the misagent service on the specified device.
92 *
93 * @param device The device to connect to.
94 * @param port Destination port (usually given by lockdownd_start_service).
95 * @param client Pointer that will point to a newly allocated
96 * misagent_client_t upon successful return.
97 *
98 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
99 * client is NULL, or an MISAGENT_E_* error code otherwise.
100 */
101misagent_error_t misagent_client_new(idevice_t device, uint16_t port, misagent_client_t *client)
102{
103 if (!device)
104 return MISAGENT_E_INVALID_ARG;
105
106 property_list_service_client_t plistclient = NULL;
107 misagent_error_t err = misagent_error(property_list_service_client_new(device, port, &plistclient));
108 if (err != MISAGENT_E_SUCCESS) {
109 return err;
110 }
111
112 misagent_client_t client_loc = (misagent_client_t) malloc(sizeof(struct misagent_client_private));
113 client_loc->parent = plistclient;
114 client_loc->last_error = 0;
115
116 *client = client_loc;
117 return MISAGENT_E_SUCCESS;
118}
119
120/**
121 * Disconnects an misagent client from the device and frees up the
122 * misagent client data.
123 *
124 * @param client The misagent client to disconnect and free.
125 *
126 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
127 * client is NULL, or an MISAGENT_E_* error code otherwise.
128 */
129misagent_error_t misagent_client_free(misagent_client_t client)
130{
131 if (!client)
132 return MISAGENT_E_INVALID_ARG;
133
134 misagent_error_t err = MISAGENT_E_SUCCESS;
135 if (client->parent && client->parent->connection) {
136 misagent_error(property_list_service_client_free(client->parent));
137 }
138 client->parent = NULL;
139 free(client);
140
141 return err;
142}
143
144/**
145 * Installs the given provisioning profile. Only works with valid profiles.
146 *
147 * @param client The connected misagent to use for installation
148 * @param profile The valid provisioning profile to install. This has to be
149 * passed as a PLIST_DATA, otherwise the function will fail.
150 *
151 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
152 * client is invalid, or an MISAGENT_E_* error code otherwise.
153 */
154misagent_error_t misagent_install(misagent_client_t client, plist_t profile)
155{
156 if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA))
157 return MISAGENT_E_INVALID_ARG;
158
159 client->last_error = MISAGENT_E_UNKNOWN_ERROR;
160
161 plist_t dict = plist_new_dict();
162 plist_dict_insert_item(dict, "MessageType", plist_new_string("Install"));
163 plist_dict_insert_item(dict, "Profile", plist_copy(profile));
164 plist_dict_insert_item(dict, "ProfileType", plist_new_string("Provisioning"));
165
166 misagent_error_t res = misagent_error(property_list_service_send_xml_plist(client->parent, dict));
167 plist_free(dict);
168 dict = NULL;
169
170 if (res != MISAGENT_E_SUCCESS) {
171 debug_info("could not send plist, error %d", res);
172 return res;
173 }
174
175 res = misagent_error(property_list_service_receive_plist(client->parent, &dict));
176 if (res != MISAGENT_E_SUCCESS) {
177 debug_info("could not receive response, error %d", res);
178 return res;
179 }
180 if (!dict) {
181 debug_info("could not get response plist");
182 return MISAGENT_E_UNKNOWN_ERROR;
183 }
184
185 res = misagent_check_result(dict, &client->last_error);
186 plist_free(dict);
187
188 return res;
189}
190
191/**
192 * Retrieves an array of all installed provisioning profiles.
193 *
194 * @param client The connected misagent to use.
195 * @param profiles Pointer to a plist_t that will be set to a PLIST_ARRAY
196 * if the function is successful.
197 *
198 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
199 * client is invalid, or an MISAGENT_E_* error code otherwise.
200 *
201 * @note If no provisioning profiles are installed on the device, this function
202 * still returns MISAGENT_E_SUCCESS and profiles will just point to an
203 * empty array.
204 */
205misagent_error_t misagent_copy(misagent_client_t client, plist_t* profiles)
206{
207 if (!client || !client->parent || !profiles)
208 return MISAGENT_E_INVALID_ARG;
209
210 client->last_error = MISAGENT_E_UNKNOWN_ERROR;
211
212 plist_t dict = plist_new_dict();
213 plist_dict_insert_item(dict, "MessageType", plist_new_string("Copy"));
214 plist_dict_insert_item(dict, "ProfileType", plist_new_string("Provisioning"));
215
216 misagent_error_t res = misagent_error(property_list_service_send_xml_plist(client->parent, dict));
217 plist_free(dict);
218 dict = NULL;
219
220 if (res != MISAGENT_E_SUCCESS) {
221 debug_info("could not send plist, error %d", res);
222 return res;
223 }
224
225 res = misagent_error(property_list_service_receive_plist(client->parent, &dict));
226 if (res != MISAGENT_E_SUCCESS) {
227 debug_info("could not receive response, error %d", res);
228 return res;
229 }
230 if (!dict) {
231 debug_info("could not get response plist");
232 return MISAGENT_E_UNKNOWN_ERROR;
233 }
234
235 res = misagent_check_result(dict, &client->last_error);
236 if (res == MISAGENT_E_SUCCESS) {
237 *profiles = plist_copy(plist_dict_get_item(dict, "Payload"));
238 }
239 plist_free(dict);
240
241 return res;
242
243}
244
245/**
246 * Removes a given provisioning profile.
247 *
248 * @param client The connected misagent to use.
249 * @param profileID Identifier of the provisioning profile to remove.
250 * This is a UUID that can be obtained from the provisioning profile data.
251 * @see misagent_copy
252 *
253 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
254 * client is invalid, or an MISAGENT_E_* error code otherwise.
255 */
256misagent_error_t misagent_remove(misagent_client_t client, const char* profileID)
257{
258 if (!client || !client->parent || !profileID)
259 return MISAGENT_E_INVALID_ARG;
260
261 client->last_error = MISAGENT_E_UNKNOWN_ERROR;
262
263 plist_t dict = plist_new_dict();
264 plist_dict_insert_item(dict, "MessageType", plist_new_string("Remove"));
265 plist_dict_insert_item(dict, "ProfileID", plist_new_string(profileID));
266 plist_dict_insert_item(dict, "ProfileType", plist_new_string("Provisioning"));
267
268 misagent_error_t res = misagent_error(property_list_service_send_xml_plist(client->parent, dict));
269 plist_free(dict);
270 dict = NULL;
271
272 if (res != MISAGENT_E_SUCCESS) {
273 debug_info("could not send plist, error %d", res);
274 return res;
275 }
276
277 res = misagent_error(property_list_service_receive_plist(client->parent, &dict));
278 if (res != MISAGENT_E_SUCCESS) {
279 debug_info("could not receive response, error %d", res);
280 return res;
281 }
282 if (!dict) {
283 debug_info("could not get response plist");
284 return MISAGENT_E_UNKNOWN_ERROR;
285 }
286
287 res = misagent_check_result(dict, &client->last_error);
288 plist_free(dict);
289
290 return res;
291}
292
293/**
294 * Retrieves the status code from the last operation.
295 *
296 * @param client The misagent to use.
297 *
298 * @return -1 if client is invalid, or the status code from the last operation
299 */
300int misagent_get_status_code(misagent_client_t client)
301{
302 if (!client) {
303 return -1;
304 }
305 return client->last_error;
306}
diff --git a/src/misagent.h b/src/misagent.h
new file mode 100644
index 0000000..00f5ad1
--- /dev/null
+++ b/src/misagent.h
@@ -0,0 +1,32 @@
1/*
2 * misagent.h
3 * com.apple.misagent service header file.
4 *
5 * Copyright (c) 2012 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#ifndef IMISAGENT_H
22#define IMISAGENT_H
23
24#include "libimobiledevice/misagent.h"
25#include "property_list_service.h"
26
27struct misagent_client_private {
28 property_list_service_client_t parent;
29 int last_error;
30};
31
32#endif