summaryrefslogtreecommitdiffstats
path: root/src/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf.c')
-rw-r--r--src/conf.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..2e6c97f
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,535 @@
1/*
2 * conf.c
3 *
4 * Copyright (C) 2013 Nikias Bassen <nikias@gmx.li>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 or version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <stdio.h>
25#include <stdint.h>
26#include <stdlib.h>
27#include <string.h>
28#include <time.h>
29#ifdef HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32
33#include <dirent.h>
34#include <libgen.h>
35#include <sys/stat.h>
36#include <errno.h>
37
38#ifdef WIN32
39#include <shlobj.h>
40#endif
41
42#include <libimobiledevice-glue/utils.h>
43#include <plist/plist.h>
44
45#include "conf.h"
46#include "utils.h"
47#include "log.h"
48
49#ifdef WIN32
50#define DIR_SEP '\\'
51#define DIR_SEP_S "\\"
52#else
53#define DIR_SEP '/'
54#define DIR_SEP_S "/"
55#endif
56
57#define CONFIG_SYSTEM_BUID_KEY "SystemBUID"
58#define CONFIG_HOST_ID_KEY "HostID"
59
60#define CONFIG_EXT ".plist"
61
62#ifdef WIN32
63#define CONFIG_DIR "Apple"DIR_SEP_S"Lockdown"
64#else
65#define CONFIG_DIR "lockdown"
66#endif
67
68#define CONFIG_FILE "SystemConfiguration"CONFIG_EXT
69
70static char *__config_dir = NULL;
71
72#ifdef WIN32
73static char *config_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)
74{
75 if (!unistr || (len <= 0)) return NULL;
76 char *outbuf = (char*)malloc(3*(len+1));
77 int p = 0;
78 int i = 0;
79
80 wchar_t wc;
81
82 while (i < len) {
83 wc = unistr[i++];
84 if (wc >= 0x800) {
85 outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF));
86 outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F));
87 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
88 } else if (wc >= 0x80) {
89 outbuf[p++] = (char)(0xC0 + ((wc >> 6) & 0x1F));
90 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
91 } else {
92 outbuf[p++] = (char)(wc & 0x7F);
93 }
94 }
95 if (items_read) {
96 *items_read = i;
97 }
98 if (items_written) {
99 *items_written = p;
100 }
101 outbuf[p] = 0;
102
103 return outbuf;
104}
105#endif
106
107const char *config_get_config_dir()
108{
109 char *base_config_dir = NULL;
110
111 if (__config_dir)
112 return __config_dir;
113
114#ifdef WIN32
115 wchar_t path[MAX_PATH+1];
116 HRESULT hr;
117 LPITEMIDLIST pidl = NULL;
118 BOOL b = FALSE;
119
120 hr = SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_APPDATA, &pidl);
121 if (hr == S_OK) {
122 b = SHGetPathFromIDListW (pidl, path);
123 if (b) {
124 base_config_dir = config_utf16_to_utf8 (path, wcslen(path), NULL, NULL);
125 CoTaskMemFree (pidl);
126 }
127 }
128#else
129#ifdef __APPLE__
130 base_config_dir = strdup("/var/db");
131#else
132 base_config_dir = strdup("/var/lib");
133#endif
134#endif
135 __config_dir = string_concat(base_config_dir, DIR_SEP_S, CONFIG_DIR, NULL);
136
137 if (__config_dir) {
138 int i = strlen(__config_dir)-1;
139 while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
140 __config_dir[i--] = '\0';
141 }
142 }
143
144 free(base_config_dir);
145
146 usbmuxd_log(LL_DEBUG, "Initialized config_dir to %s", __config_dir);
147
148 return __config_dir;
149}
150
151static int __mkdir(const char *dir, int mode)
152{
153#ifdef WIN32
154 return mkdir(dir);
155#else
156 return mkdir(dir, mode);
157#endif
158}
159
160static int mkdir_with_parents(const char *dir, int mode)
161{
162 if (!dir) return -1;
163 if (__mkdir(dir, mode) == 0) {
164 return 0;
165 } else {
166 if (errno == EEXIST) return 0;
167 }
168 int res;
169 char *parent = strdup(dir);
170 char* parentdir = dirname(parent);
171 if (parentdir) {
172 res = mkdir_with_parents(parentdir, mode);
173 } else {
174 res = -1;
175 }
176 free(parent);
177 return res;
178}
179
180/**
181 * Creates a freedesktop compatible configuration directory.
182 */
183static void config_create_config_dir(void)
184{
185 const char *config_path = config_get_config_dir();
186 struct stat st;
187 if (stat(config_path, &st) != 0) {
188 mkdir_with_parents(config_path, 0755);
189 }
190}
191
192static int get_rand(int min, int max)
193{
194 int retval = (rand() % (max - min)) + min;
195 return retval;
196}
197
198static char *config_generate_uuid(int idx)
199{
200 char *uuid = (char *) malloc(sizeof(char) * 37);
201 const char *chars = "ABCDEF0123456789";
202 srand(time(NULL) - idx);
203 int i = 0;
204
205 for (i = 0; i < 36; i++) {
206 if (i == 8 || i == 13 || i == 18 || i == 23) {
207 uuid[i] = '-';
208 continue;
209 } else {
210 uuid[i] = chars[get_rand(0, 16)];
211 }
212 }
213 /* make it a real string */
214 uuid[36] = '\0';
215 return uuid;
216}
217
218/**
219 * Generates a valid BUID for this system (which is actually a UUID).
220 *
221 * @return A null terminated string containing a valid BUID.
222 */
223static char *config_generate_system_buid()
224{
225 return config_generate_uuid(1);
226}
227
228static int internal_set_value(const char *config_file, const char *key, plist_t value)
229{
230 if (!config_file)
231 return 0;
232
233 /* read file into plist */
234 plist_t config = NULL;
235
236 plist_read_from_file(config_file, &config, NULL);
237 if (!config) {
238 config = plist_new_dict();
239 plist_dict_set_item(config, key, value);
240 } else {
241 plist_t n = plist_dict_get_item(config, key);
242 if (n) {
243 plist_dict_remove_item(config, key);
244 }
245 plist_dict_set_item(config, key, value);
246 remove(config_file);
247 }
248
249 /* store in config file */
250 char *value_string = NULL;
251 if (plist_get_node_type(value) == PLIST_STRING) {
252 plist_get_string_val(value, &value_string);
253 usbmuxd_log(LL_DEBUG, "Setting key %s to %s in config file %s", key, value_string, config_file);
254 if (value_string)
255 free(value_string);
256 } else {
257 usbmuxd_log(LL_DEBUG, "Setting key %s in config file %s", key, config_file);
258 }
259
260 int res = (plist_write_to_file(config, config_file, PLIST_FORMAT_XML, 0) == PLIST_ERR_SUCCESS);
261
262 plist_free(config);
263
264 return res;
265}
266
267static int config_set_value(const char *key, plist_t value)
268{
269 const char *config_path = NULL;
270 char *config_file = NULL;
271
272 /* Make sure config directory exists */
273 config_create_config_dir();
274
275 config_path = config_get_config_dir();
276 config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL);
277
278 int result = internal_set_value(config_file, key, value);
279 if (!result) {
280 usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s'", config_file);
281 }
282
283 free(config_file);
284
285 return result;
286}
287
288static int internal_get_value(const char* config_file, const char *key, plist_t *value)
289{
290 *value = NULL;
291
292 /* now parse file to get the SystemBUID */
293 plist_t config = NULL;
294 if (plist_read_from_file(config_file, &config, NULL) == PLIST_ERR_SUCCESS) {
295 usbmuxd_log(LL_DEBUG, "Reading key %s from config file %s", key, config_file);
296 plist_t n = plist_dict_get_item(config, key);
297 if (n) {
298 *value = plist_copy(n);
299 n = NULL;
300 }
301 }
302 plist_free(config);
303
304 return 1;
305}
306
307static int config_get_value(const char *key, plist_t *value)
308{
309 const char *config_path = NULL;
310 char *config_file = NULL;
311
312 config_path = config_get_config_dir();
313 config_file = string_concat(config_path, DIR_SEP_S, CONFIG_FILE, NULL);
314
315 int result = internal_get_value(config_file, key, value);
316
317 free(config_file);
318
319 return result;
320}
321
322/**
323 * Store SystemBUID in config file.
324 *
325 * @param system_buid A null terminated string containing a valid SystemBUID.
326 */
327static int config_set_system_buid(const char *system_buid)
328{
329 return config_set_value(CONFIG_SYSTEM_BUID_KEY, plist_new_string(system_buid));
330}
331
332/**
333 * Determines whether a pairing record is present for the given device.
334 *
335 * @param udid The device UDID as given by the device.
336 *
337 * @return 1 if there's a pairing record for the given udid or 0 otherwise.
338 */
339int config_has_device_record(const char *udid)
340{
341 int res = 0;
342 if (!udid) return 0;
343
344 /* ensure config directory exists */
345 config_create_config_dir();
346
347 /* build file path */
348 const char *config_path = config_get_config_dir();
349 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
350
351 struct stat st;
352
353 if ((stat(device_record_file, &st) == 0) && S_ISREG(st.st_mode))
354 res = 1;
355
356 free(device_record_file);
357
358 return res;
359}
360
361/**
362 * Reads the BUID from a previously generated configuration file.
363 *
364 * @param system_buid pointer to a variable that will be set to point to a
365 * newly allocated string containing the BUID.
366 *
367 * @note It is the responsibility of the calling function to free the returned system_buid
368 */
369void config_get_system_buid(char **system_buid)
370{
371 plist_t value = NULL;
372
373 config_get_value(CONFIG_SYSTEM_BUID_KEY, &value);
374
375 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
376 plist_get_string_val(value, system_buid);
377 usbmuxd_log(LL_DEBUG, "Got %s %s", CONFIG_SYSTEM_BUID_KEY, *system_buid);
378 }
379
380 if (value)
381 plist_free(value);
382
383 if (!*system_buid) {
384 /* no config, generate system_buid */
385 usbmuxd_log(LL_DEBUG, "No previous %s found", CONFIG_SYSTEM_BUID_KEY);
386 *system_buid = config_generate_system_buid();
387 if (!config_set_system_buid(*system_buid)) {
388 usbmuxd_log(LL_WARNING, "WARNING: Failed to store SystemBUID, this might be a problem");
389 }
390 }
391
392 usbmuxd_log(LL_DEBUG, "Using %s as %s", *system_buid, CONFIG_SYSTEM_BUID_KEY);
393}
394
395/**
396 * Store a pairing record for the given device identifier.
397 *
398 * @param udid device identifier
399 * @param record_data buffer containing a pairing record
400 * @param record_size size of buffer passed in record_data
401 *
402 * @return 0 on success or a negative errno otherwise.
403 */
404int config_set_device_record(const char *udid, char* record_data, uint64_t record_size)
405{
406 int res = 0;
407
408 if (!udid || !record_data || record_size < 8)
409 return -EINVAL;
410
411 plist_t plist = NULL;
412 if (memcmp(record_data, "bplist00", 8) == 0) {
413 plist_from_bin(record_data, record_size, &plist);
414 } else {
415 plist_from_xml(record_data, record_size, &plist);
416 }
417
418 if (!plist || plist_get_node_type(plist) != PLIST_DICT) {
419 if (plist)
420 plist_free(plist);
421 return -EINVAL;
422 }
423
424 /* ensure config directory exists */
425 config_create_config_dir();
426
427 /* build file path */
428 const char *config_path = config_get_config_dir();
429 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
430
431 remove(device_record_file);
432
433 /* store file */
434 if (!plist_write_to_file(plist, device_record_file, PLIST_FORMAT_XML, 0)) {
435 usbmuxd_log(LL_DEBUG, "Could not open '%s' for writing: %s", device_record_file, strerror(errno));
436 res = -ENOENT;
437 }
438 free(device_record_file);
439 if (plist)
440 plist_free(plist);
441
442 return res;
443}
444
445/**
446 * Retrieve a pairing record for the given device identifier
447 *
448 * @param udid device identifier
449 * @param record_data pointer to a variable that will be set to point to a
450 * newly allocated buffer holding the pairing record
451 * @param record_size pointer to a variable that will be set to the size
452 * of the buffer given in record_data.
453 *
454 * @return 0 on success or a negative errno otherwise.
455 */
456int config_get_device_record(const char *udid, char **record_data, uint64_t *record_size)
457{
458 int res = 0;
459
460 /* ensure config directory exists */
461 config_create_config_dir();
462
463 /* build file path */
464 const char *config_path = config_get_config_dir();
465 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
466
467 /* read file */
468 buffer_read_from_filename(device_record_file, record_data, record_size);
469 if (!*record_data) {
470 usbmuxd_log(LL_ERROR, "ERROR: Failed to read '%s': %s", device_record_file, strerror(errno));
471 res = -ENOENT;
472 }
473 free(device_record_file);
474
475 return res;
476}
477
478/**
479 * Remove the pairing record stored for a device from this host.
480 *
481 * @param udid The udid of the device
482 *
483 * @return 0 on success or a negative errno otherwise.
484 */
485int config_remove_device_record(const char *udid)
486{
487 int res = 0;
488
489 /* build file path */
490 const char *config_path = config_get_config_dir();
491 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
492
493 /* remove file */
494 if (remove(device_record_file) != 0) {
495 res = -errno;
496 usbmuxd_log(LL_DEBUG, "Could not remove %s: %s", device_record_file, strerror(errno));
497 }
498
499 free(device_record_file);
500
501 return res;
502}
503
504static int config_device_record_get_value(const char *udid, const char *key, plist_t *value)
505{
506 const char *config_path = NULL;
507 char *config_file = NULL;
508
509 config_path = config_get_config_dir();
510 config_file = string_concat(config_path, DIR_SEP_S, udid, CONFIG_EXT, NULL);
511
512 int result = internal_get_value(config_file, key, value);
513
514 free(config_file);
515
516 return result;
517}
518
519void config_device_record_get_host_id(const char *udid, char **host_id)
520{
521 plist_t value = NULL;
522
523 config_device_record_get_value(udid, CONFIG_HOST_ID_KEY, &value);
524
525 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
526 plist_get_string_val(value, host_id);
527 }
528
529 if (value)
530 plist_free(value);
531
532 if (!*host_id) {
533 usbmuxd_log(LL_ERROR, "ERROR: Could not get HostID from pairing record for udid %s", udid);
534 }
535}