summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am4
-rw-r--r--common/debug.c169
-rw-r--r--common/debug.h59
-rw-r--r--common/userpref.c1161
-rw-r--r--common/userpref.h73
5 files changed, 1465 insertions, 1 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index dfa6852..664e13b 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -8,7 +8,9 @@ libinternalcommon_la_LIBADD =
8libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined 8libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined
9libinternalcommon_la_SOURCES = \ 9libinternalcommon_la_SOURCES = \
10 socket.c socket.h \ 10 socket.c socket.h \
11 thread.c thread.h 11 thread.c thread.h \
12 debug.c debug.h \
13 userpref.c userpref.h
12 14
13if WIN32 15if WIN32
14libinternalcommon_la_LIBADD += -lole32 16libinternalcommon_la_LIBADD += -lole32
diff --git a/common/debug.c b/common/debug.c
new file mode 100644
index 0000000..0bb87a2
--- /dev/null
+++ b/common/debug.c
@@ -0,0 +1,169 @@
1/*
2 * debug.c
3 * contains utilitary functions for debugging
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 * Copyright (c) 2010 Martin S. All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26#include <stdarg.h>
27#define _GNU_SOURCE 1
28#define __USE_GNU 1
29#include <stdio.h>
30#include <stdint.h>
31#include <stdlib.h>
32#include <time.h>
33
34#include "debug.h"
35#include "libimobiledevice/libimobiledevice.h"
36
37#ifndef STRIP_DEBUG_CODE
38#include "asprintf.h"
39#endif
40
41int debug_level = 0;
42
43/**
44 * Sets the level of debugging. Currently the only acceptable values are 0 and
45 * 1.
46 *
47 * @param level Set to 0 for no debugging or 1 for debugging.
48 */
49void idevice_set_debug_level(int level)
50{
51 debug_level = level;
52}
53
54#ifndef STRIP_DEBUG_CODE
55static void debug_print_line(const char *func, const char *file, int line, const char *buffer)
56{
57 char *str_time = NULL;
58 char *header = NULL;
59 time_t the_time;
60
61 time(&the_time);
62 str_time = (char*)malloc(255);
63 strftime(str_time, 254, "%H:%M:%S", localtime (&the_time));
64
65 /* generate header text */
66 (void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func);
67 free (str_time);
68
69 /* trim ending newlines */
70
71 /* print header */
72 printf ("%s: ", header);
73
74 /* print actual debug content */
75 printf ("%s\n", buffer);
76
77 /* flush this output, as we need to debug */
78 fflush (stdout);
79
80 free (header);
81}
82#endif
83
84inline void debug_info_real(const char *func, const char *file, int line, const char *format, ...)
85{
86#ifndef STRIP_DEBUG_CODE
87 va_list args;
88 char *buffer = NULL;
89
90 if (!debug_level)
91 return;
92
93 /* run the real fprintf */
94 va_start(args, format);
95 (void)vasprintf(&buffer, format, args);
96 va_end(args);
97
98 debug_print_line(func, file, line, buffer);
99
100 free(buffer);
101#endif
102}
103
104inline void debug_buffer(const char *data, const int length)
105{
106#ifndef STRIP_DEBUG_CODE
107 int i;
108 int j;
109 unsigned char c;
110
111 if (debug_level) {
112 for (i = 0; i < length; i += 16) {
113 fprintf(stderr, "%04x: ", i);
114 for (j = 0; j < 16; j++) {
115 if (i + j >= length) {
116 fprintf(stderr, " ");
117 continue;
118 }
119 fprintf(stderr, "%02hhx ", *(data + i + j));
120 }
121 fprintf(stderr, " | ");
122 for (j = 0; j < 16; j++) {
123 if (i + j >= length)
124 break;
125 c = *(data + i + j);
126 if ((c < 32) || (c > 127)) {
127 fprintf(stderr, ".");
128 continue;
129 }
130 fprintf(stderr, "%c", c);
131 }
132 fprintf(stderr, "\n");
133 }
134 fprintf(stderr, "\n");
135 }
136#endif
137}
138
139inline void debug_buffer_to_file(const char *file, const char *data, const int length)
140{
141#ifndef STRIP_DEBUG_CODE
142 if (debug_level) {
143 FILE *f = fopen(file, "wb");
144 fwrite(data, 1, length, f);
145 fflush(f);
146 fclose(f);
147 }
148#endif
149}
150
151inline void debug_plist_real(const char *func, const char *file, int line, plist_t plist)
152{
153#ifndef STRIP_DEBUG_CODE
154 if (!plist)
155 return;
156
157 char *buffer = NULL;
158 uint32_t length = 0;
159 plist_to_xml(plist, &buffer, &length);
160
161 /* get rid of ending newline as one is already added in the debug line */
162 if (buffer[length-1] == '\n')
163 buffer[length-1] = '\0';
164
165 debug_info_real(func, file, line, "printing %i bytes plist:\n%s", length, buffer);
166 free(buffer);
167#endif
168}
169
diff --git a/common/debug.h b/common/debug.h
new file mode 100644
index 0000000..b7cff80
--- /dev/null
+++ b/common/debug.h
@@ -0,0 +1,59 @@
1/*
2 * debug.h
3 * contains utilitary functions for debugging
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 * Copyright (c) 2010 Martin S. All Rights Reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef __DEBUG_H
24#define __DEBUG_H
25
26#include <plist/plist.h>
27
28#ifndef LIBIMOBILEDEVICE_INTERNAL
29#ifdef WIN32
30#define LIBIMOBILEDEVICE_INTERNAL
31#else
32#define LIBIMOBILEDEVICE_INTERNAL __attribute__((visibility("hidden")))
33#endif
34#endif
35
36#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE)
37#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__)
38#define debug_plist(a) debug_plist_real (__func__, __FILE__, __LINE__, a)
39#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE)
40#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
41#define debug_plist(a) debug_plist_real (__FUNCTION__, __FILE__, __LINE__, a)
42#else
43#define debug_info(...)
44#define debug_plist(a)
45#endif
46
47LIBIMOBILEDEVICE_INTERNAL inline void debug_info_real(const char *func,
48 const char *file,
49 int line,
50 const char *format, ...);
51
52LIBIMOBILEDEVICE_INTERNAL inline void debug_buffer(const char *data, const int length);
53LIBIMOBILEDEVICE_INTERNAL inline void debug_buffer_to_file(const char *file, const char *data, const int length);
54LIBIMOBILEDEVICE_INTERNAL inline void debug_plist_real(const char *func,
55 const char *file,
56 int line,
57 plist_t plist);
58
59#endif
diff --git a/common/userpref.c b/common/userpref.c
new file mode 100644
index 0000000..0e774b7
--- /dev/null
+++ b/common/userpref.c
@@ -0,0 +1,1161 @@
1/*
2 * userpref.c
3 * contains methods to access user specific certificates IDs and more.
4 *
5 * Copyright (c) 2008 Jonathan Beck 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 <stdio.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#ifdef HAVE_OPENSSL
30#include <openssl/pem.h>
31#include <openssl/rsa.h>
32#include <openssl/x509.h>
33#include <openssl/x509v3.h>
34#else
35#include <gnutls/gnutls.h>
36#include <gnutls/x509.h>
37#include <gcrypt.h>
38#endif
39
40#include <dirent.h>
41#include <libgen.h>
42#include <sys/stat.h>
43#include <errno.h>
44
45#ifdef WIN32
46#include <shlobj.h>
47#endif
48
49#include "userpref.h"
50#include "debug.h"
51
52#define LIBIMOBILEDEVICE_CONF_DIR "libimobiledevice"
53#define LIBIMOBILEDEVICE_CONF_FILE "libimobiledevicerc"
54
55#define LIBIMOBILEDEVICE_ROOT_PRIVKEY "RootPrivateKey.pem"
56#define LIBIMOBILEDEVICE_HOST_PRIVKEY "HostPrivateKey.pem"
57#define LIBIMOBILEDEVICE_ROOT_CERTIF "RootCertificate.pem"
58#define LIBIMOBILEDEVICE_HOST_CERTIF "HostCertificate.pem"
59
60#ifdef WIN32
61#define DIR_SEP '\\'
62#define DIR_SEP_S "\\"
63#else
64#define DIR_SEP '/'
65#define DIR_SEP_S "/"
66#endif
67
68static char __config_dir[512] = {0, };
69
70#ifdef WIN32
71static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)
72{
73 if (!unistr || (len <= 0)) return NULL;
74 char *outbuf = (char*)malloc(3*(len+1));
75 int p = 0;
76 int i = 0;
77
78 wchar_t wc;
79
80 while (i < len) {
81 wc = unistr[i++];
82 if (wc >= 0x800) {
83 outbuf[p++] = (char)(0xE0 + ((wc >> 12) & 0xF));
84 outbuf[p++] = (char)(0x80 + ((wc >> 6) & 0x3F));
85 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
86 } else if (wc >= 0x80) {
87 outbuf[p++] = (char)(0xC0 + ((wc >> 6) & 0x1F));
88 outbuf[p++] = (char)(0x80 + (wc & 0x3F));
89 } else {
90 outbuf[p++] = (char)(wc & 0x7F);
91 }
92 }
93 if (items_read) {
94 *items_read = i;
95 }
96 if (items_written) {
97 *items_written = p;
98 }
99 outbuf[p] = 0;
100
101 return outbuf;
102}
103#endif
104
105static const char *userpref_get_tmp_dir()
106{
107 const char *cdir = getenv("TMPDIR");
108 if (cdir && cdir[0])
109 return cdir;
110 cdir = getenv("TMP");
111 if (cdir && cdir[0])
112 return cdir;
113 cdir = getenv("TEMP");
114 if (cdir && cdir[0])
115 return cdir;
116 return "/tmp";
117}
118
119static const char *userpref_get_config_dir()
120{
121 if (__config_dir[0]) return __config_dir;
122#ifdef WIN32
123 wchar_t path[MAX_PATH+1];
124 HRESULT hr;
125 LPITEMIDLIST pidl = NULL;
126 BOOL b = FALSE;
127
128 hr = SHGetSpecialFolderLocation (NULL, CSIDL_LOCAL_APPDATA, &pidl);
129 if (hr == S_OK) {
130 b = SHGetPathFromIDListW (pidl, path);
131 if (b) {
132 char *cdir = userpref_utf16_to_utf8 (path, wcslen(path), NULL, NULL);
133 strcpy(__config_dir, cdir);
134 free(cdir);
135 CoTaskMemFree (pidl);
136 }
137 }
138#else
139 const char *cdir = getenv("XDG_CONFIG_HOME");
140 if (!cdir) {
141 cdir = getenv("HOME");
142 if (!cdir || !cdir[0]) {
143 const char *tdir = userpref_get_tmp_dir();
144 strcpy(__config_dir, tdir);
145 strcat(__config_dir, DIR_SEP_S);
146 strcat(__config_dir, "root");
147 } else {
148 strcpy(__config_dir, cdir);
149 }
150 strcat(__config_dir, DIR_SEP_S);
151 strcat(__config_dir, ".config");
152 } else {
153 strcpy(__config_dir, cdir);
154 }
155#endif
156 strcat(__config_dir, DIR_SEP_S);
157 strcat(__config_dir, LIBIMOBILEDEVICE_CONF_DIR);
158
159 int i = strlen(__config_dir)-1;
160 while ((i > 0) && (__config_dir[i] == DIR_SEP)) {
161 __config_dir[i--] = '\0';
162 }
163
164 return __config_dir;
165}
166
167static int __mkdir(const char *dir, int mode)
168{
169#ifdef WIN32
170 return mkdir(dir);
171#else
172 return mkdir(dir, mode);
173#endif
174}
175
176static int mkdir_with_parents(const char *dir, int mode)
177{
178 if (!dir) return -1;
179 if (__mkdir(dir, mode) == 0) {
180 return 0;
181 } else {
182 if (errno == EEXIST) return 0;
183 }
184 int res;
185 char *parent = strdup(dir);
186 parent = dirname(parent);
187 if (parent) {
188 res = mkdir_with_parents(parent, mode);
189 } else {
190 res = -1;
191 }
192 free(parent);
193 if (res == 0) {
194 mkdir_with_parents(dir, mode);
195 }
196 return res;
197}
198
199static int config_write(const char *cfgfile, plist_t dict)
200{
201 if (!cfgfile || !dict || (plist_get_node_type(dict) != PLIST_DICT)) {
202 return -1;
203 }
204 int res = -1;
205
206#if 1 // old style config
207 plist_t hostid = plist_dict_get_item(dict, "HostID");
208 if (hostid && (plist_get_node_type(hostid) == PLIST_STRING)) {
209 char *hostidstr = NULL;
210 plist_get_string_val(hostid, &hostidstr);
211 if (hostidstr) {
212 FILE *fd = fopen(cfgfile, "wb");
213 if (fd) {
214 fprintf(fd, "\n[Global]\nHostID=%s\n", hostidstr);
215 fclose(fd);
216 res = 0;
217 } else {
218 debug_info("could not open '%s' for writing: %s", cfgfile, strerror(errno));
219 }
220 free(hostidstr);
221 }
222 }
223#endif
224#if 0
225 char *xml = NULL;
226 uint32_t length = 0;
227
228 plist_to_xml(dict, &xml, &length);
229 if (!xml) {
230 return res;
231 }
232
233 FILE *fd = fopen(cfgfile, "wb");
234 if (!fd) {
235 free(xml);
236 return res;
237 }
238
239 if (fwrite(xml, 1, length, fd) == length) {
240 res = 0;
241 } else {
242 fprintf(stderr, "%s: ERROR: failed to write configuration to '%s'\n", __func__, cfgfile);
243 }
244 fclose(fd);
245
246 free(xml);
247#endif
248 return res;
249}
250
251static int config_read(const char *cfgfile, plist_t *dict)
252{
253 if (!cfgfile || !dict) {
254 return -1;
255 }
256
257 int res = -1;
258 FILE *fd = fopen(cfgfile, "rb");
259 if (!fd) {
260 debug_info("could not open '%s' for reading: %s", cfgfile, strerror(errno));
261 return -1;
262 }
263
264 fseek(fd, 0, SEEK_END);
265 unsigned long int size = ftell(fd);
266 fseek(fd, 0, SEEK_SET);
267 unsigned char *contents = NULL;
268
269 contents = malloc(size);
270 if (fread(contents, 1, size, fd) != size) {
271 free(contents);
272 fclose(fd);
273 return -1;
274 }
275 plist_t plist = NULL;
276
277 if (!memcmp(contents, "bplist00", 8)) {
278 plist_from_bin((const char*)contents, (uint32_t)size, &plist);
279 fclose(fd);
280 } else {
281 if (memchr(contents, '<', size)) {
282 plist_from_xml((const char*)contents, (uint32_t)size, &plist);
283 }
284 if (plist) {
285 fclose(fd);
286 } else {
287 // try parsing old format config file
288 char line[256];
289 fseek(fd, 0, SEEK_SET);
290 while (fgets(line, 256, fd)) {
291 char *p = &line[0];
292 size_t llen = strlen(p)-1;
293 while ((llen > 0) && ((p[llen] == '\n') || (p[llen] == '\r'))) {
294 p[llen] = '\0';
295 llen--;
296 }
297 if (llen == 0) continue;
298 while ((p[0] == '\n') || (p[0] == '\r')) {
299 p++;
300 }
301 if (!strncmp(p, "HostID=", 7)) {
302 plist = plist_new_dict();
303 plist_dict_insert_item(plist, "HostID", plist_new_string(p+7));
304 break;
305 }
306 }
307 fclose(fd);
308#if 0
309 if (plist) {
310 // write new format config
311 config_write(cfgfile, plist);
312 }
313#endif
314 }
315 }
316 free(contents);
317 if (plist) {
318 *dict = plist;
319 res = 0;
320 }
321 return res;
322}
323
324/**
325 * Creates a freedesktop compatible configuration directory.
326 */
327static void userpref_create_config_dir(void)
328{
329 const char *config_path = userpref_get_config_dir();
330 struct stat st;
331 if (stat(config_path, &st) != 0) {
332 mkdir_with_parents(config_path, 0755);
333 }
334}
335
336static int get_rand(int min, int max)
337{
338 int retval = (rand() % (max - min)) + min;
339 return retval;
340}
341
342/**
343 * Generates a valid HostID (which is actually a UUID).
344 *
345 * @return A null terminated string containing a valid HostID.
346 */
347static char *userpref_generate_host_id()
348{
349 /* HostID's are just UUID's, and UUID's are 36 characters long */
350 char *hostid = (char *) malloc(sizeof(char) * 37);
351 const char *chars = "ABCDEF0123456789";
352 srand(time(NULL));
353 int i = 0;
354
355 for (i = 0; i < 36; i++) {
356 if (i == 8 || i == 13 || i == 18 || i == 23) {
357 hostid[i] = '-';
358 continue;
359 } else {
360 hostid[i] = chars[get_rand(0, 16)];
361 }
362 }
363 /* make it a real string */
364 hostid[36] = '\0';
365 return hostid;
366}
367
368/**
369 * Store HostID in config file.
370 *
371 * @param host_id A null terminated string containing a valid HostID.
372 */
373static int userpref_set_host_id(const char *host_id)
374{
375 const char *config_path;
376 char *config_file;
377
378 if (!host_id)
379 return 0;
380
381 /* Make sure config directory exists */
382 userpref_create_config_dir();
383
384 config_path = userpref_get_config_dir();
385 config_file = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_CONF_FILE)+1);
386 strcpy(config_file, config_path);
387 strcat(config_file, DIR_SEP_S);
388 strcat(config_file, LIBIMOBILEDEVICE_CONF_FILE);
389
390 /* Now parse file to get the HostID */
391 plist_t config = NULL;
392 config_read(config_file, &config);
393 if (!config) {
394 config = plist_new_dict();
395 plist_dict_insert_item(config, "HostID", plist_new_string(host_id));
396 } else {
397 plist_t n = plist_dict_get_item(config, "HostID");
398 if (n) {
399 plist_set_string_val(n, host_id);
400 } else {
401 plist_dict_insert_item(config, "HostID", plist_new_string(host_id));
402 }
403 }
404
405 /* Store in config file */
406 debug_info("setting hostID to %s", host_id);
407
408 config_write(config_file, config);
409 plist_free(config);
410
411 free(config_file);
412 return 1;
413}
414
415/**
416 * Reads the HostID from a previously generated configuration file.
417 *
418 * @note It is the responsibility of the calling function to free the returned host_id
419 *
420 * @return The string containing the HostID or NULL
421 */
422void userpref_get_host_id(char **host_id)
423{
424 const char *config_path;
425 char *config_file;
426
427 config_path = userpref_get_config_dir();
428 config_file = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_CONF_FILE)+1);
429 strcpy(config_file, config_path);
430 strcat(config_file, DIR_SEP_S);
431 strcat(config_file, LIBIMOBILEDEVICE_CONF_FILE);
432
433 /* now parse file to get the HostID */
434 plist_t config = NULL;
435 if (config_read(config_file, &config) == 0) {
436 plist_t n_host_id = plist_dict_get_item(config, "HostID");
437 if (n_host_id && (plist_get_node_type(n_host_id) == PLIST_STRING)) {
438 plist_get_string_val(n_host_id, host_id);
439 }
440 }
441 plist_free(config);
442 free(config_file);
443
444 if (!*host_id) {
445 /* no config, generate host_id */
446 *host_id = userpref_generate_host_id();
447 userpref_set_host_id(*host_id);
448 }
449
450 debug_info("Using %s as HostID", *host_id);
451}
452
453/**
454 * Determines whether this device has been connected to this system before.
455 *
456 * @param udid The device UDID as given by the device.
457 *
458 * @return 1 if the device has been connected previously to this configuration
459 * or 0 otherwise.
460 */
461int userpref_has_device_public_key(const char *udid)
462{
463 int ret = 0;
464 const char *config_path;
465 char *config_file;
466 struct stat st;
467
468 if (!udid) return 0;
469
470 /* first get config file */
471 config_path = userpref_get_config_dir();
472 config_file = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1);
473 strcpy(config_file, config_path);
474 strcat(config_file, DIR_SEP_S);
475 strcat(config_file, udid);
476 strcat(config_file, ".pem");
477
478 if ((stat(config_file, &st) == 0) && S_ISREG(st.st_mode))
479 ret = 1;
480 free(config_file);
481 return ret;
482}
483
484/**
485 * Fills a list with UDIDs of devices that have been connected to this
486 * system before, i.e. for which a public key file exists.
487 *
488 * @param list A pointer to a char** initially pointing to NULL that will
489 * hold a newly allocated list of UDIDs upon successful return.
490 * The caller is responsible for freeing the memory. Note that if
491 * no public key file was found the list has to be freed too as it
492 * points to a terminating NULL element.
493 * @param count The number of UDIDs found. This parameter can be NULL if it
494 * is not required.
495 *
496 * @return USERPREF_E_SUCCESS on success, or USERPREF_E_INVALID_ARG if the
497 * list parameter is not pointing to NULL.
498 */
499userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
500{
501 struct slist_t {
502 char *name;
503 void *next;
504 };
505 DIR *config_dir;
506 const char *config_path;
507 struct slist_t *udids = NULL;
508 unsigned int i;
509 unsigned int found = 0;
510
511 if (!list || (list && *list)) {
512 debug_info("ERROR: The list parameter needs to point to NULL!");
513 return USERPREF_E_INVALID_ARG;
514 }
515
516 if (count) {
517 *count = 0;
518 }
519
520 config_path = userpref_get_config_dir();
521 config_dir = opendir(config_path);
522 if (config_dir) {
523 struct dirent *entry;
524 struct slist_t *listp = udids;
525 while ((entry = readdir(config_dir))) {
526 char *ext = strstr(entry->d_name, ".pem");
527 if (ext && ((ext - entry->d_name) == 40) && (strlen(entry->d_name) == 44)) {
528 struct slist_t *ne = (struct slist_t*)malloc(sizeof(struct slist_t));
529 ne->name = (char*)malloc(41);
530 strncpy(ne->name, entry->d_name, 40);
531 ne->name[40] = 0;
532 ne->next = NULL;
533 if (!listp) {
534 listp = ne;
535 udids = listp;
536 } else {
537 listp->next = ne;
538 listp = listp->next;
539 }
540 found++;
541 }
542 }
543 closedir(config_dir);
544 }
545 *list = (char**)malloc(sizeof(char*) * (found+1));
546 i = 0;
547 while (udids) {
548 (*list)[i++] = udids->name;
549 struct slist_t *old = udids;
550 udids = udids->next;
551 free(old);
552 }
553 (*list)[i] = NULL;
554
555 if (count) {
556 *count = found;
557 }
558
559 return USERPREF_E_SUCCESS;
560}
561
562/**
563 * Mark the device (as represented by the key) as having connected to this
564 * configuration.
565 *
566 * @param udid The device UDID as given by the device
567 * @param public_key The public key given by the device
568 *
569 * @return 1 on success and 0 if no public key is given or if it has already
570 * been marked as connected previously.
571 */
572userpref_error_t userpref_set_device_public_key(const char *udid, key_data_t public_key)
573{
574 if (NULL == public_key.data)
575 return USERPREF_E_INVALID_ARG;
576
577 if (userpref_has_device_public_key(udid))
578 return USERPREF_E_SUCCESS;
579
580 /* ensure config directory exists */
581 userpref_create_config_dir();
582
583 /* build file path */
584 const char *config_path = userpref_get_config_dir();
585 char *pem = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1);
586 strcpy(pem, config_path);
587 strcat(pem, DIR_SEP_S);
588 strcat(pem, udid);
589 strcat(pem, ".pem");
590
591 /* store file */
592 FILE *pFile = fopen(pem, "wb");
593 if (pFile) {
594 fwrite(public_key.data, 1, public_key.size, pFile);
595 fclose(pFile);
596 } else {
597 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
598 }
599 free(pem);
600
601 return USERPREF_E_SUCCESS;
602}
603
604/**
605 * Remove the public key stored for the device with udid from this host.
606 *
607 * @param udid The udid of the device
608 *
609 * @return USERPREF_E_SUCCESS on success.
610 */
611userpref_error_t userpref_remove_device_public_key(const char *udid)
612{
613 if (!userpref_has_device_public_key(udid))
614 return USERPREF_E_SUCCESS;
615
616 /* build file path */
617 const char *config_path = userpref_get_config_dir();
618 char *pem = (char*)malloc(strlen(config_path)+1+strlen(udid)+4+1);
619 strcpy(pem, config_path);
620 strcat(pem, DIR_SEP_S);
621 strcat(pem, udid);
622 strcat(pem, ".pem");
623
624 /* remove file */
625 remove(pem);
626
627 free(pem);
628
629 return USERPREF_E_SUCCESS;
630}
631
632/**
633 * Private function which reads the given file into a key_data_t structure.
634 *
635 * @param file The filename of the file to read
636 * @param data The pointer at which to store the data.
637 *
638 * @return 1 if the file contents where read successfully and 0 otherwise.
639 */
640static int userpref_get_file_contents(const char *file, key_data_t * data)
641{
642 int success = 0;
643 unsigned long int size = 0;
644 unsigned char *content = NULL;
645 const char *config_path;
646 char *filepath;
647 FILE *fd;
648
649 if (NULL == file || NULL == data)
650 return 0;
651
652 /* Read file */
653 config_path = userpref_get_config_dir();
654 filepath = (char*)malloc(strlen(config_path)+1+strlen(file)+1);
655 strcpy(filepath, config_path);
656 strcat(filepath, DIR_SEP_S);
657 strcat(filepath, file);
658
659 fd = fopen(filepath, "rb");
660 if (fd) {
661 fseek(fd, 0, SEEK_END);
662 size = ftell(fd);
663 fseek(fd, 0, SEEK_SET);
664
665 // prevent huge files
666 if (size > 0xFFFFFF) {
667 fprintf(stderr, "%s: file is too big (> 16MB). Refusing to read the contents to memory!", __func__);
668 } else {
669 size_t p = 0;
670 content = (unsigned char*)malloc(size);
671 while (!feof(fd)) {
672 p += fread(content+p, 1, size-p, fd);
673 if (ferror(fd) != 0) {
674 break;
675 }
676 if (p >= size) {
677 success = 1;
678 break;
679 }
680 }
681 }
682 fclose(fd);
683 }
684
685 free(filepath);
686
687 /* Add it to the key_data_t structure */
688 if (success) {
689 data->data = (uint8_t*) content;
690 data->size = size;
691 }
692
693 return success;
694}
695
696/**
697 * Private function which generate private keys and certificates.
698 *
699 * @return 1 if keys were successfully generated, 0 otherwise
700 */
701static userpref_error_t userpref_gen_keys_and_cert(void)
702{
703 userpref_error_t ret = USERPREF_E_SSL_ERROR;
704
705 key_data_t root_key_pem = { NULL, 0 };
706 key_data_t root_cert_pem = { NULL, 0 };
707 key_data_t host_key_pem = { NULL, 0 };
708 key_data_t host_cert_pem = { NULL, 0 };
709
710 debug_info("Generating keys and certificates");
711#ifdef HAVE_OPENSSL
712 RSA* root_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
713 RSA* host_keypair = RSA_generate_key(2048, 65537, NULL, NULL);
714
715 EVP_PKEY* root_pkey = EVP_PKEY_new();
716 EVP_PKEY_assign_RSA(root_pkey, root_keypair);
717
718 EVP_PKEY* host_pkey = EVP_PKEY_new();
719 EVP_PKEY_assign_RSA(host_pkey, host_keypair);
720
721 /* generate root certificate */
722 X509* root_cert = X509_new();
723 {
724 /* set serial number */
725 ASN1_INTEGER* sn = ASN1_INTEGER_new();
726 ASN1_INTEGER_set(sn, 0);
727 X509_set_serialNumber(root_cert, sn);
728 ASN1_INTEGER_free(sn);
729
730 /* set version */
731 X509_set_version(root_cert, 2);
732
733 /* set x509v3 basic constraints */
734 X509_EXTENSION* ext;
735 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:TRUE"))) {
736 debug_info("ERROR: X509V3_EXT_conf_nid failed");
737 }
738 X509_add_ext(root_cert, ext, -1);
739
740 /* set key validity */
741 ASN1_TIME* asn1time = ASN1_TIME_new();
742 ASN1_TIME_set(asn1time, time(NULL));
743 X509_set_notBefore(root_cert, asn1time);
744 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
745 X509_set_notAfter(root_cert, asn1time);
746 ASN1_TIME_free(asn1time);
747
748 /* use root public key for root cert */
749 X509_set_pubkey(root_cert, root_pkey);
750 /* sign root cert with root private key */
751 X509_sign(root_cert, root_pkey, EVP_sha1());
752 }
753
754 /* create host certificate */
755 X509* host_cert = X509_new();
756 {
757 /* set serial number */
758 ASN1_INTEGER* sn = ASN1_INTEGER_new();
759 ASN1_INTEGER_set(sn, 0);
760 X509_set_serialNumber(host_cert, sn);
761 ASN1_INTEGER_free(sn);
762
763 /* set version */
764 X509_set_version(host_cert, 2);
765
766 /* set x509v3 basic constraints */
767 X509_EXTENSION* ext;
768 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
769 debug_info("ERROR: X509V3_EXT_conf_nid failed");
770 }
771 X509_add_ext(host_cert, ext, -1);
772
773 /* set x509v3 key usage */
774 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"digitalSignature,keyEncipherment"))) {
775 debug_info("ERROR: X509V3_EXT_conf_nid failed");
776 }
777 X509_add_ext(host_cert, ext, -1);
778
779 /* set key validity */
780 ASN1_TIME* asn1time = ASN1_TIME_new();
781 ASN1_TIME_set(asn1time, time(NULL));
782 X509_set_notBefore(host_cert, asn1time);
783 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
784 X509_set_notAfter(host_cert, asn1time);
785 ASN1_TIME_free(asn1time);
786
787 /* use host public key for host cert */
788 X509_set_pubkey(host_cert, host_pkey);
789
790 /* sign host cert with root private key */
791 X509_sign(host_cert, root_pkey, EVP_sha1());
792 }
793
794 if (root_cert && root_pkey && host_cert && host_pkey) {
795 BIO* membp;
796
797 membp = BIO_new(BIO_s_mem());
798 if (PEM_write_bio_X509(membp, root_cert) > 0) {
799 root_cert_pem.size = BIO_get_mem_data(membp, &root_cert_pem.data);
800 }
801 membp = BIO_new(BIO_s_mem());
802 if (PEM_write_bio_PrivateKey(membp, root_pkey, NULL, NULL, 0, 0, NULL) > 0) {
803 root_key_pem.size = BIO_get_mem_data(membp, &root_key_pem.data);
804 }
805 membp = BIO_new(BIO_s_mem());
806 if (PEM_write_bio_X509(membp, host_cert) > 0) {
807 host_cert_pem.size = BIO_get_mem_data(membp, &host_cert_pem.data);
808 }
809 membp = BIO_new(BIO_s_mem());
810 if (PEM_write_bio_PrivateKey(membp, host_pkey, NULL, NULL, 0, 0, NULL) > 0) {
811 host_key_pem.size = BIO_get_mem_data(membp, &host_key_pem.data);
812 }
813 }
814
815 EVP_PKEY_free(root_pkey);
816 EVP_PKEY_free(host_pkey);
817
818 X509_free(host_cert);
819 X509_free(root_cert);
820#else
821 gnutls_x509_privkey_t root_privkey;
822 gnutls_x509_crt_t root_cert;
823 gnutls_x509_privkey_t host_privkey;
824 gnutls_x509_crt_t host_cert;
825
826 gnutls_global_deinit();
827 gnutls_global_init();
828
829 //use less secure random to speed up key generation
830 gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM);
831
832 gnutls_x509_privkey_init(&root_privkey);
833 gnutls_x509_privkey_init(&host_privkey);
834
835 gnutls_x509_crt_init(&root_cert);
836 gnutls_x509_crt_init(&host_cert);
837
838 /* generate root key */
839 gnutls_x509_privkey_generate(root_privkey, GNUTLS_PK_RSA, 2048, 0);
840 gnutls_x509_privkey_generate(host_privkey, GNUTLS_PK_RSA, 2048, 0);
841
842 /* generate certificates */
843 gnutls_x509_crt_set_key(root_cert, root_privkey);
844 gnutls_x509_crt_set_serial(root_cert, "\x00", 1);
845 gnutls_x509_crt_set_version(root_cert, 3);
846 gnutls_x509_crt_set_ca_status(root_cert, 1);
847 gnutls_x509_crt_set_activation_time(root_cert, time(NULL));
848 gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
849 gnutls_x509_crt_sign(root_cert, root_cert, root_privkey);
850
851 gnutls_x509_crt_set_key(host_cert, host_privkey);
852 gnutls_x509_crt_set_serial(host_cert, "\x00", 1);
853 gnutls_x509_crt_set_version(host_cert, 3);
854 gnutls_x509_crt_set_ca_status(host_cert, 0);
855 gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);
856 gnutls_x509_crt_set_activation_time(host_cert, time(NULL));
857 gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
858 gnutls_x509_crt_sign(host_cert, root_cert, root_privkey);
859
860 /* export to PEM format */
861 size_t root_key_export_size = 0;
862 size_t host_key_export_size = 0;
863
864 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_export_size);
865 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_export_size);
866
867 root_key_pem.data = gnutls_malloc(root_key_export_size);
868 host_key_pem.data = gnutls_malloc(host_key_export_size);
869
870 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, root_key_pem.data, &root_key_export_size);
871 root_key_pem.size = root_key_export_size;
872 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, host_key_pem.data, &host_key_export_size);
873 host_key_pem.size = host_key_export_size;
874
875 size_t root_cert_export_size = 0;
876 size_t host_cert_export_size = 0;
877
878 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_export_size);
879 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_export_size);
880
881 root_cert_pem.data = gnutls_malloc(root_cert_export_size);
882 host_cert_pem.data = gnutls_malloc(host_cert_export_size);
883
884 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_export_size);
885 root_cert_pem.size = root_cert_export_size;
886 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size);
887 host_cert_pem.size = host_cert_export_size;
888
889 //restore gnutls env
890 gnutls_global_deinit();
891 gnutls_global_init();
892#endif
893 if (NULL != root_cert_pem.data && 0 != root_cert_pem.size &&
894 NULL != host_cert_pem.data && 0 != host_cert_pem.size)
895 ret = USERPREF_E_SUCCESS;
896
897 /* store values in config file */
898 userpref_set_keys_and_certs( &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem);
899
900 if (root_key_pem.data)
901 free(root_key_pem.data);
902 if (root_cert_pem.data)
903 free(root_cert_pem.data);
904 if (host_key_pem.data)
905 free(host_key_pem.data);
906 if (host_cert_pem.data)
907 free(host_cert_pem.data);
908
909 return ret;
910}
911
912/**
913 * Private function which import the given key into a gnutls structure.
914 *
915 * @param key_name The filename of the private key to import.
916 * @param key the gnutls key structure.
917 *
918 * @return 1 if the key was successfully imported.
919 */
920#ifdef HAVE_OPENSSL
921static userpref_error_t userpref_import_key(const char* key_name, key_data_t* key)
922#else
923static userpref_error_t userpref_import_key(const char* key_name, gnutls_x509_privkey_t key)
924#endif
925{
926#ifdef HAVE_OPENSSL
927 if (!key)
928 return USERPREF_E_SUCCESS;
929#endif
930 userpref_error_t ret = USERPREF_E_INVALID_CONF;
931 key_data_t pem_key = { NULL, 0 };
932 if (userpref_get_file_contents(key_name, &pem_key)) {
933#ifdef HAVE_OPENSSL
934 key->data = (unsigned char*)malloc(pem_key.size);
935 memcpy(key->data, pem_key.data, pem_key.size);
936 key->size = pem_key.size;
937 ret = USERPREF_E_SUCCESS;
938#else
939 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM))
940 ret = USERPREF_E_SUCCESS;
941 else
942 ret = USERPREF_E_SSL_ERROR;
943#endif
944 }
945 if (pem_key.data)
946 free(pem_key.data);
947 return ret;
948}
949
950/**
951 * Private function which import the given certificate into a gnutls structure.
952 *
953 * @param crt_name The filename of the certificate to import.
954 * @param cert the gnutls certificate structure.
955 *
956 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
957 */
958#ifdef HAVE_OPENSSL
959static userpref_error_t userpref_import_crt(const char* crt_name, key_data_t* cert)
960#else
961static userpref_error_t userpref_import_crt(const char* crt_name, gnutls_x509_crt_t cert)
962#endif
963{
964#ifdef HAVE_OPENSSL
965 if (!cert)
966 return USERPREF_E_SUCCESS;
967#endif
968 userpref_error_t ret = USERPREF_E_INVALID_CONF;
969 key_data_t pem_cert = { NULL, 0 };
970
971 if (userpref_get_file_contents(crt_name, &pem_cert)) {
972#ifdef HAVE_OPENSSL
973 cert->data = (unsigned char*)malloc(pem_cert.size);
974 memcpy(cert->data, pem_cert.data, pem_cert.size);
975 cert->size = pem_cert.size;
976 ret = USERPREF_E_SUCCESS;
977#else
978 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM))
979 ret = USERPREF_E_SUCCESS;
980 else
981 ret = USERPREF_E_SSL_ERROR;
982#endif
983 }
984 if (pem_cert.data)
985 free(pem_cert.data);
986 return ret;
987}
988
989/**
990 * Function to retrieve host keys and certificates.
991 * This function trigger key generation if they do not exists yet or are invalid.
992 *
993 * @note This function can take few seconds to complete (typically 5 seconds)
994 *
995 * @param root_privkey The root private key.
996 * @param root_crt The root certificate.
997 * @param host_privkey The host private key.
998 * @param host_crt The host certificate.
999 *
1000 * @return 1 if the keys and certificates were successfully retrieved, 0 otherwise
1001 */
1002#ifdef HAVE_OPENSSL
1003userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt)
1004#else
1005userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
1006#endif
1007{
1008 userpref_error_t ret = USERPREF_E_SUCCESS;
1009
1010 if (ret == USERPREF_E_SUCCESS)
1011 ret = userpref_import_key(LIBIMOBILEDEVICE_ROOT_PRIVKEY, root_privkey);
1012
1013 if (ret == USERPREF_E_SUCCESS)
1014 ret = userpref_import_key(LIBIMOBILEDEVICE_HOST_PRIVKEY, host_privkey);
1015
1016 if (ret == USERPREF_E_SUCCESS)
1017 ret = userpref_import_crt(LIBIMOBILEDEVICE_ROOT_CERTIF, root_crt);
1018
1019 if (ret == USERPREF_E_SUCCESS)
1020 ret = userpref_import_crt(LIBIMOBILEDEVICE_HOST_CERTIF, host_crt);
1021
1022 if (USERPREF_E_SUCCESS != ret) {
1023 //we had problem reading or importing root cert
1024 //try with a new ones.
1025 ret = userpref_gen_keys_and_cert();
1026
1027 if (ret == USERPREF_E_SUCCESS)
1028 ret = userpref_import_key(LIBIMOBILEDEVICE_ROOT_PRIVKEY, root_privkey);
1029
1030 if (ret == USERPREF_E_SUCCESS)
1031 ret = userpref_import_key(LIBIMOBILEDEVICE_HOST_PRIVKEY, host_privkey);
1032
1033 if (ret == USERPREF_E_SUCCESS)
1034 ret = userpref_import_crt(LIBIMOBILEDEVICE_ROOT_CERTIF, root_crt);
1035
1036 if (ret == USERPREF_E_SUCCESS)
1037 ret = userpref_import_crt(LIBIMOBILEDEVICE_HOST_CERTIF, host_crt);
1038 }
1039
1040 return ret;
1041}
1042
1043/**
1044 * Function to retrieve certificates encoded in PEM format.
1045 *
1046 * @param pem_root_cert The root certificate.
1047 * @param pem_host_cert The host certificate.
1048 *
1049 * @return 1 if the certificates were successfully retrieved, 0 otherwise
1050 */
1051userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert)
1052{
1053 if (!pem_root_cert || !pem_host_cert)
1054 return USERPREF_E_INVALID_ARG;
1055
1056 if (userpref_get_file_contents(LIBIMOBILEDEVICE_ROOT_CERTIF, pem_root_cert) && userpref_get_file_contents(LIBIMOBILEDEVICE_HOST_CERTIF, pem_host_cert))
1057 return USERPREF_E_SUCCESS;
1058 else {
1059 if (pem_root_cert->data) {
1060 free(pem_root_cert->data);
1061 pem_root_cert->size = 0;
1062 }
1063 if (pem_host_cert->data) {
1064 free(pem_host_cert->data);
1065 pem_host_cert->size = 0;
1066 }
1067 }
1068 debug_info("configuration invalid");
1069 return USERPREF_E_INVALID_CONF;
1070}
1071
1072/**
1073 * Create and save a configuration file containing the given data.
1074 *
1075 * @note: All fields must specified and be non-null
1076 *
1077 * @param root_key The root key
1078 * @param root_cert The root certificate
1079 * @param host_key The host key
1080 * @param host_cert The host certificate
1081 *
1082 * @return 1 on success and 0 otherwise.
1083 */
1084userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert)
1085{
1086 FILE *pFile;
1087 char *pem;
1088 const char *config_path;
1089 userpref_error_t ret = USERPREF_E_SUCCESS;
1090
1091 debug_info("saving keys and certs");
1092
1093 if (!root_key || !host_key || !root_cert || !host_cert) {
1094 debug_info("missing key or cert (root_key=%p, host_key=%p, root=cert=%p, host_cert=%p", root_key, host_key, root_cert, host_cert);
1095 return USERPREF_E_INVALID_ARG;
1096 }
1097
1098 /* Make sure config directory exists */
1099 userpref_create_config_dir();
1100
1101 config_path = userpref_get_config_dir();
1102
1103 /* Now write keys and certificates to disk */
1104 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_ROOT_PRIVKEY)+1);
1105 strcpy(pem, config_path);
1106 strcat(pem, DIR_SEP_S);
1107 strcat(pem, LIBIMOBILEDEVICE_ROOT_PRIVKEY);
1108 pFile = fopen(pem, "wb");
1109 if (pFile) {
1110 fwrite(root_key->data, 1, root_key->size, pFile);
1111 fclose(pFile);
1112 } else {
1113 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1114 ret = USERPREF_E_WRITE_ERROR;
1115 }
1116 free(pem);
1117
1118 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_HOST_PRIVKEY)+1);
1119 strcpy(pem, config_path);
1120 strcat(pem, DIR_SEP_S);
1121 strcat(pem, LIBIMOBILEDEVICE_HOST_PRIVKEY);
1122 pFile = fopen(pem, "wb");
1123 if (pFile) {
1124 fwrite(host_key->data, 1, host_key->size, pFile);
1125 fclose(pFile);
1126 } else {
1127 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1128 ret = USERPREF_E_WRITE_ERROR;
1129 }
1130 free(pem);
1131
1132 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_ROOT_CERTIF)+1);
1133 strcpy(pem, config_path);
1134 strcat(pem, DIR_SEP_S);
1135 strcat(pem, LIBIMOBILEDEVICE_ROOT_CERTIF);
1136 pFile = fopen(pem, "wb");
1137 if (pFile) {
1138 fwrite(root_cert->data, 1, root_cert->size, pFile);
1139 fclose(pFile);
1140 } else {
1141 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1142 ret = USERPREF_E_WRITE_ERROR;
1143 }
1144 free(pem);
1145
1146 pem = (char*)malloc(strlen(config_path)+1+strlen(LIBIMOBILEDEVICE_HOST_CERTIF)+1);
1147 strcpy(pem, config_path);
1148 strcat(pem, DIR_SEP_S);
1149 strcat(pem, LIBIMOBILEDEVICE_HOST_CERTIF);
1150 pFile = fopen(pem, "wb");
1151 if (pFile) {
1152 fwrite(host_cert->data, 1, host_cert->size, pFile);
1153 fclose(pFile);
1154 } else {
1155 debug_info("could not open '%s' for writing: %s", pem, strerror(errno));
1156 ret = USERPREF_E_WRITE_ERROR;
1157 }
1158 free(pem);
1159
1160 return ret;
1161}
diff --git a/common/userpref.h b/common/userpref.h
new file mode 100644
index 0000000..14db985
--- /dev/null
+++ b/common/userpref.h
@@ -0,0 +1,73 @@
1/*
2 * userpref.h
3 * contains methods to access user specific certificates IDs and more.
4 *
5 * Copyright (c) 2008 Jonathan Beck 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#ifndef __USERPREF_H
23#define __USERPREF_H
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#ifdef HAVE_OPENSSL
30typedef struct {
31 unsigned char *data;
32 unsigned int size;
33} key_data_t;
34#else
35#include <gnutls/gnutls.h>
36typedef gnutls_datum_t key_data_t;
37#endif
38
39#include <stdint.h>
40
41#ifndef LIBIMOBILEDEVICE_INTERNAL
42#ifdef WIN32
43#define LIBIMOBILEDEVICE_INTERNAL
44#else
45#define LIBIMOBILEDEVICE_INTERNAL __attribute__((visibility("hidden")))
46#endif
47#endif
48
49#define USERPREF_E_SUCCESS 0
50#define USERPREF_E_INVALID_ARG -1
51#define USERPREF_E_INVALID_CONF -2
52#define USERPREF_E_SSL_ERROR -3
53#define USERPREF_E_READ_ERROR -4
54#define USERPREF_E_WRITE_ERROR -5
55
56#define USERPREF_E_UNKNOWN_ERROR -256
57
58typedef int16_t userpref_error_t;
59
60#ifdef HAVE_OPENSSL
61LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt);
62#else
63LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt);
64#endif
65LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_keys_and_certs(key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert);
66LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_get_certs_as_pem(key_data_t *pem_root_cert, key_data_t *pem_host_cert);
67LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_public_key(const char *udid, key_data_t public_key);
68userpref_error_t userpref_remove_device_public_key(const char *udid);
69LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_public_key(const char *udid);
70userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count);
71void userpref_get_host_id(char **host_id);
72
73#endif