diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/Makefile.am | 27 | ||||
| -rw-r--r-- | common/debug.c | 54 | ||||
| -rw-r--r-- | common/socket.c | 501 | ||||
| -rw-r--r-- | common/socket.h | 65 | ||||
| -rw-r--r-- | common/thread.c | 140 | ||||
| -rw-r--r-- | common/thread.h | 76 | ||||
| -rw-r--r-- | common/userpref.c | 429 | ||||
| -rw-r--r-- | common/userpref.h | 15 | ||||
| -rw-r--r-- | common/utils.c | 483 | ||||
| -rw-r--r-- | common/utils.h | 60 | 
10 files changed, 401 insertions, 1449 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 054e2a1..ba7ed9c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,17 +1,28 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir) +AM_CPPFLAGS = \ +	-I$(top_srcdir)/include \ +	-I$(top_srcdir) -AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusbmuxd_CFLAGS) $(libplist_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(LFS_CFLAGS) -AM_LDFLAGS = $(libusbmuxd_LIBS) $(libplist_LIBS) ${libpthread_LIBS} +AM_CFLAGS = \ +	$(GLOBAL_CFLAGS) \ +	$(ssl_lib_CFLAGS) \ +	$(LFS_CFLAGS) \ +	$(libusbmuxd_CFLAGS) \ +	$(limd_glue_CFLAGS) \ +	$(libplist_CFLAGS) + +AM_LDFLAGS = \ +	$(ssl_lib_LIBS) \ +	${libpthread_LIBS} \ +	$(libusbmuxd_LIBS) \ +	$(limd_glue_LIBS) \ +	$(libplist_LIBS)  noinst_LTLIBRARIES = libinternalcommon.la  libinternalcommon_la_LIBADD =   libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined  libinternalcommon_la_SOURCES = \ -		       socket.c socket.h \ -		       thread.c thread.h \ -		       debug.c debug.h \ -		       userpref.c userpref.h \ -		       utils.c utils.h +	debug.c debug.h \ +	userpref.c userpref.h  if WIN32  libinternalcommon_la_LIBADD += -lole32 -lws2_32 diff --git a/common/debug.c b/common/debug.c index acca456..7a593fc 100644 --- a/common/debug.c +++ b/common/debug.c @@ -30,10 +30,13 @@  #include <stdint.h>  #include <stdlib.h>  #include <time.h> +#ifndef _WIN32 +#include <sys/time.h> +#endif +#include "src/idevice.h"  #include "debug.h"  #include "libimobiledevice/libimobiledevice.h" -#include "src/idevice.h"  #ifndef STRIP_DEBUG_CODE  #include "asprintf.h" @@ -46,35 +49,36 @@ void internal_set_debug_level(int level)  	debug_level = level;  } -#define MAX_PRINT_LEN 16*1024 +#define MAX_PRINT_LEN (16*1024)  #ifndef STRIP_DEBUG_CODE  static void debug_print_line(const char *func, const char *file, int line, const char *buffer)  { -	char *str_time = NULL; -	char *header = NULL; +	char str_time[24]; +#ifdef _WIN32 +	SYSTEMTIME lt; +	GetLocalTime(<); +	snprintf(str_time, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); +#else +#ifdef HAVE_GETTIMEOFDAY +	struct timeval tv; +	struct tm *tp; +	gettimeofday(&tv, NULL); +#ifdef HAVE_LOCALTIME_R +	struct tm tp_; +	tp = localtime_r(&tv.tv_sec, &tp_); +#else +	tp = localtime(&tv.tv_sec); +#endif +	strftime(str_time, 9, "%H:%M:%S", tp); +	snprintf(str_time+8, 10, ".%03d", (int)tv.tv_usec/1000); +#else  	time_t the_time; -  	time(&the_time); -	str_time = (char*)malloc(255); -	strftime(str_time, 254, "%H:%M:%S", localtime (&the_time)); - -	/* generate header text */ -	(void)asprintf(&header, "%s %s:%d %s()", str_time, file, line, func); -	free (str_time); - -	/* trim ending newlines */ - -	/* print header */ -	printf ("%s: ", header); - -	/* print actual debug content */ -	printf ("%s\n", buffer); - -	/* flush this output, as we need to debug */ -	fflush (stdout); - -	free (header); +	strftime(str_time, 15, "%H:%M:%S", localtime (&the_time)); +#endif +#endif +	fprintf(stderr, "%s %s:%d %s(): %s\n", str_time, file, line, func, buffer);  }  #endif @@ -89,7 +93,7 @@ void debug_info_real(const char *func, const char *file, int line, const char *f  	/* run the real fprintf */  	va_start(args, format); -	(void)vasprintf(&buffer, format, args); +	if(vasprintf(&buffer, format, args)<0){}  	va_end(args);  	debug_print_line(func, file, line, buffer); diff --git a/common/socket.c b/common/socket.c deleted file mode 100644 index 0ee8105..0000000 --- a/common/socket.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * socket.c - * - * Copyright (C) 2012-2018 Nikias Bassen <nikias@gmx.li> - * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <sys/time.h> -#include <sys/stat.h> -#ifdef WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> -#include <windows.h> -static int wsa_init = 0; -#else -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <fcntl.h> -#endif -#include "socket.h" - -#define RECV_TIMEOUT 20000 -#define CONNECT_TIMEOUT 5000 - -#ifndef ECONNRESET -#define ECONNRESET 108 -#endif - -static int verbose = 0; - -void socket_set_verbose(int level) -{ -	verbose = level; -} - -#ifndef WIN32 -int socket_create_unix(const char *filename) -{ -	struct sockaddr_un name; -	int sock; -#ifdef SO_NOSIGPIPE -	int yes = 1; -#endif - -	// remove if still present -	unlink(filename); - -	/* Create the socket. */ -	sock = socket(PF_UNIX, SOCK_STREAM, 0); -	if (sock < 0) { -		perror("socket"); -		return -1; -	} - -#ifdef SO_NOSIGPIPE -	if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sock); -		return -1; -	} -#endif - -	/* Bind a name to the socket. */ -	name.sun_family = AF_UNIX; -	strncpy(name.sun_path, filename, sizeof(name.sun_path)); -	name.sun_path[sizeof(name.sun_path) - 1] = '\0'; - -	if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) { -		perror("bind"); -		socket_close(sock); -		return -1; -	} - -	if (listen(sock, 10) < 0) { -		perror("listen"); -		socket_close(sock); -		return -1; -	} - -	return sock; -} - -int socket_connect_unix(const char *filename) -{ -	struct sockaddr_un name; -	int sfd = -1; -	struct stat fst; -#ifdef SO_NOSIGPIPE -	int yes = 1; -#endif -	int bufsize = 0x20000; - -	// check if socket file exists... -	if (stat(filename, &fst) != 0) { -		if (verbose >= 2) -			fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, -					strerror(errno)); -		return -1; -	} -	// ... and if it is a unix domain socket -	if (!S_ISSOCK(fst.st_mode)) { -		if (verbose >= 2) -			fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__, -					filename); -		return -1; -	} -	// make a new socket -	if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { -		if (verbose >= 2) -			fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); -		return -1; -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { -		perror("Could not set send buffer for socket"); -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { -		perror("Could not set receive buffer for socket"); -	} - -#ifdef SO_NOSIGPIPE -	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sfd); -		return -1; -	} -#endif -	// and connect to 'filename' -	name.sun_family = AF_UNIX; -	strncpy(name.sun_path, filename, sizeof(name.sun_path)); -	name.sun_path[sizeof(name.sun_path) - 1] = 0; - -	if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) < 0) { -		socket_close(sfd); -		if (verbose >= 2) -			fprintf(stderr, "%s: connect: %s\n", __func__, -					strerror(errno)); -		return -1; -	} - -	return sfd; -} -#endif - -int socket_create(uint16_t port) -{ -	int sfd = -1; -	int yes = 1; -#ifdef WIN32 -	WSADATA wsa_data; -	if (!wsa_init) { -		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { -			fprintf(stderr, "WSAStartup failed!\n"); -			ExitProcess(-1); -		} -		wsa_init = 1; -	} -#endif -	struct sockaddr_in saddr; - -	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { -		perror("socket()"); -		return -1; -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sfd); -		return -1; -	} - -#ifdef SO_NOSIGPIPE -	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sfd); -		return -1; -	} -#endif - -	memset((void *) &saddr, 0, sizeof(saddr)); -	saddr.sin_family = AF_INET; -	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); -	saddr.sin_port = htons(port); - -	if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) { -		perror("bind()"); -		socket_close(sfd); -		return -1; -	} - -	if (listen(sfd, 1) == -1) { -		perror("listen()"); -		socket_close(sfd); -		return -1; -	} - -	return sfd; -} - -int socket_connect(const char *addr, uint16_t port) -{ -	int sfd = -1; -	int yes = 1; -	int bufsize = 0x20000; -	struct addrinfo hints; -	struct addrinfo *result, *rp; -	char portstr[8]; -	int res; -#ifdef WIN32 -	u_long l_yes = 1; -	u_long l_no = 0; -	WSADATA wsa_data; -	if (!wsa_init) { -		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { -			fprintf(stderr, "WSAStartup failed!\n"); -			ExitProcess(-1); -		} -		wsa_init = 1; -	} -#else -	int flags = 0; -#endif - -	if (!addr) { -		errno = EINVAL; -		return -1; -	} - -	memset(&hints, '\0', sizeof(struct addrinfo)); -	hints.ai_family = AF_UNSPEC; -	hints.ai_socktype = SOCK_STREAM; -	hints.ai_flags = 0; -	hints.ai_protocol = IPPROTO_TCP; - -	sprintf(portstr, "%d", port); - -	res = getaddrinfo(addr, portstr, &hints, &result); -	if (res != 0) { -		fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res)); -		return -1; -	} - -	for (rp = result; rp != NULL; rp = rp->ai_next) { -		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); -		if (sfd == -1) { -			continue; -		} - -		if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { -			perror("setsockopt()"); -			socket_close(sfd); -			continue; -		} - -#ifdef WIN32 -		ioctlsocket(sfd, FIONBIO, &l_yes); -#else -		fcntl(sfd, F_SETFL, O_NONBLOCK); -#endif - -		if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { -			break; -		} -#ifdef WIN32 -		if (WSAGetLastError() == WSAEWOULDBLOCK) -#else -		if (errno == EINPROGRESS) -#endif -		{ -			fd_set fds; -			FD_ZERO(&fds); -			FD_SET(sfd, &fds); - -			struct timeval timeout; -			timeout.tv_sec = CONNECT_TIMEOUT / 1000; -			timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; -			if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { -				int so_error; -				socklen_t len = sizeof(so_error); -				getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); -				if (so_error == 0) { -					break; -				} -			} -		} -		socket_close(sfd); -	} - -	freeaddrinfo(result); - -	if (rp == NULL) { -		if (verbose >= 2) -			fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port); -		return -1; -	} - -#ifdef WIN32 -	ioctlsocket(sfd, FIONBIO, &l_no); -#else -	flags = fcntl(sfd, F_GETFL, 0); -	fcntl(sfd, F_SETFL, flags & (~O_NONBLOCK)); -#endif - -#ifdef SO_NOSIGPIPE -	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { -		perror("setsockopt()"); -		socket_close(sfd); -		return -1; -	} -#endif - -	if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { -		perror("Could not set TCP_NODELAY on socket"); -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { -		perror("Could not set send buffer for socket"); -	} - -	if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { -		perror("Could not set receive buffer for socket"); -	} - -	return sfd; -} - -int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout) -{ -	fd_set fds; -	int sret; -	int eagain; -	struct timeval to; -	struct timeval *pto; - -	if (fd < 0) { -		if (verbose >= 2) -			fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); -		return -1; -	} - -	FD_ZERO(&fds); -	FD_SET(fd, &fds); - -	sret = -1; - -	do { -		if (timeout > 0) { -			to.tv_sec = (time_t) (timeout / 1000); -			to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000); -			pto = &to; -		} else { -			pto = NULL; -		} -		eagain = 0; -		switch (fdm) { -		case FDM_READ: -			sret = select(fd + 1, &fds, NULL, NULL, pto); -			break; -		case FDM_WRITE: -			sret = select(fd + 1, NULL, &fds, NULL, pto); -			break; -		case FDM_EXCEPT: -			sret = select(fd + 1, NULL, NULL, &fds, pto); -			break; -		default: -			return -1; -		} - -		if (sret < 0) { -			switch (errno) { -			case EINTR: -				// interrupt signal in select -				if (verbose >= 2) -					fprintf(stderr, "%s: EINTR\n", __func__); -				eagain = 1; -				break; -			case EAGAIN: -				if (verbose >= 2) -					fprintf(stderr, "%s: EAGAIN\n", __func__); -				break; -			default: -				if (verbose >= 2) -					fprintf(stderr, "%s: select failed: %s\n", __func__, -							strerror(errno)); -				return -1; -			} -		} else if (sret == 0) { -			if (verbose >= 2) -				fprintf(stderr, "%s: timeout\n", __func__); -			return -ETIMEDOUT; -		} -	} while (eagain); - -	return sret; -} - -int socket_accept(int fd, uint16_t port) -{ -#ifdef WIN32 -	int addr_len; -#else -	socklen_t addr_len; -#endif -	int result; -	struct sockaddr_in addr; - -	memset(&addr, 0, sizeof(addr)); -	addr.sin_family = AF_INET; -	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); -	addr.sin_port = htons(port); - -	addr_len = sizeof(addr); -	result = accept(fd, (struct sockaddr*)&addr, &addr_len); - -	return result; -} - -int socket_shutdown(int fd, int how) -{ -	return shutdown(fd, how); -} - -int socket_close(int fd) { -#ifdef WIN32 -	return closesocket(fd); -#else -	return close(fd); -#endif -} - -int socket_receive(int fd, void *data, size_t length) -{ -	return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT); -} - -int socket_peek(int fd, void *data, size_t length) -{ -	return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT); -} - -int socket_receive_timeout(int fd, void *data, size_t length, int flags, -					 unsigned int timeout) -{ -	int res; -	int result; - -	// check if data is available -	res = socket_check_fd(fd, FDM_READ, timeout); -	if (res <= 0) { -		return res; -	} -	// if we get here, there _is_ data available -	result = recv(fd, data, length, flags); -	if (res > 0 && result == 0) { -		// but this is an error condition -		if (verbose >= 3) -			fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); -		return -ECONNRESET; -	} -	if (result < 0) { -		return -errno; -	} -	return result; -} - -int socket_send(int fd, void *data, size_t length) -{ -	int flags = 0; -#ifdef MSG_NOSIGNAL -	flags |= MSG_NOSIGNAL; -#endif -	return send(fd, data, length, flags); -} diff --git a/common/socket.h b/common/socket.h deleted file mode 100644 index e31de6b..0000000 --- a/common/socket.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * socket.h - * - * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> - * Copyright (C) 2012 Nikias Bassen <nikias@gmx.li> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifndef SOCKET_SOCKET_H -#define SOCKET_SOCKET_H - -#include <stdlib.h> -#include <stdint.h> - -enum fd_mode { -	FDM_READ, -	FDM_WRITE, -	FDM_EXCEPT -}; -typedef enum fd_mode fd_mode; - -#ifdef WIN32 -#include <winsock2.h> -#define SHUT_RD SD_READ -#define SHUT_WR SD_WRITE -#define SHUT_RDWR SD_BOTH -#else -#include <sys/socket.h> -#endif - -#ifndef WIN32 -int socket_create_unix(const char *filename); -int socket_connect_unix(const char *filename); -#endif -int socket_create(uint16_t port); -int socket_connect(const char *addr, uint16_t port); -int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout); -int socket_accept(int fd, uint16_t port); - -int socket_shutdown(int fd, int how); -int socket_close(int fd); - -int socket_receive(int fd, void *data, size_t size); -int socket_peek(int fd, void *data, size_t size); -int socket_receive_timeout(int fd, void *data, size_t size, int flags, -					 unsigned int timeout); - -int socket_send(int fd, void *data, size_t size); - -void socket_set_verbose(int level); - -#endif	/* SOCKET_SOCKET_H */ diff --git a/common/thread.c b/common/thread.c deleted file mode 100644 index eb535ab..0000000 --- a/common/thread.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * thread.c - * - * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved. - * Copyright (c) 2012 Martin Szulecki, All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include "thread.h" - -int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data) -{ -#ifdef WIN32 -	HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL); -	if (th == NULL) { -		return -1; -	} -	*thread = th; -	return 0; -#else -	int res = pthread_create(thread, NULL, thread_func, data); -	return res; -#endif -} - -void thread_detach(THREAD_T thread) -{ -#ifdef WIN32 -	CloseHandle(thread); -#else -	pthread_detach(thread); -#endif -} - -void thread_free(THREAD_T thread) -{ -#ifdef WIN32 -	CloseHandle(thread); -#endif -} - -int thread_join(THREAD_T thread) -{ -	/* wait for thread to complete */ -#ifdef WIN32 -	return (int)WaitForSingleObject(thread, INFINITE); -#else -	return pthread_join(thread, NULL); -#endif -} - -int thread_alive(THREAD_T thread) -{ -#ifdef WIN32 -	return WaitForSingleObject(thread, 0) == WAIT_TIMEOUT; -#else -	return pthread_kill(thread, 0) == 0; -#endif -} - -int thread_cancel(THREAD_T thread) -{ -#ifdef WIN32 -	return -1; -#else -#ifdef HAVE_PTHREAD_CANCEL -	return pthread_cancel(thread); -#else -	return -1; -#endif -#endif -} - -void mutex_init(mutex_t* mutex) -{ -#ifdef WIN32 -	InitializeCriticalSection(mutex); -#else -	pthread_mutex_init(mutex, NULL); -#endif -} - -void mutex_destroy(mutex_t* mutex) -{ -#ifdef WIN32 -	DeleteCriticalSection(mutex); -#else -	pthread_mutex_destroy(mutex); -#endif -} - -void mutex_lock(mutex_t* mutex) -{ -#ifdef WIN32 -	EnterCriticalSection(mutex); -#else -	pthread_mutex_lock(mutex); -#endif -} - -void mutex_unlock(mutex_t* mutex) -{ -#ifdef WIN32 -	LeaveCriticalSection(mutex); -#else -	pthread_mutex_unlock(mutex); -#endif -} - -void thread_once(thread_once_t *once_control, void (*init_routine)(void)) -{ -#ifdef WIN32 -	while (InterlockedExchange(&(once_control->lock), 1) != 0) { -		Sleep(1); -	} -	if (!once_control->state) { -		once_control->state = 1; -		init_routine(); -	} -	InterlockedExchange(&(once_control->lock), 0); -#else -	pthread_once(once_control, init_routine); -#endif -} diff --git a/common/thread.h b/common/thread.h deleted file mode 100644 index 23e4510..0000000 --- a/common/thread.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * thread.h - * - * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved. - * Copyright (c) 2012 Martin Szulecki, All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifndef __THREAD_H -#define __THREAD_H - -#include <stddef.h> - -#ifdef WIN32 -#include <windows.h> -typedef HANDLE THREAD_T; -typedef CRITICAL_SECTION mutex_t; -typedef volatile struct { -	LONG lock; -	int state; -} thread_once_t; -#define THREAD_ONCE_INIT {0, 0} -#define THREAD_ID GetCurrentThreadId() -#define THREAD_T_NULL (THREAD_T)NULL -#else -#include <pthread.h> -#include <signal.h> -typedef pthread_t THREAD_T; -typedef pthread_mutex_t mutex_t; -typedef pthread_once_t thread_once_t; -#define THREAD_ONCE_INIT PTHREAD_ONCE_INIT -#define THREAD_ID pthread_self() -#define THREAD_T_NULL (THREAD_T)NULL -#endif - -typedef void* (*thread_func_t)(void* data); - -int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data); -void thread_detach(THREAD_T thread); -void thread_free(THREAD_T thread); -int thread_join(THREAD_T thread); -int thread_alive(THREAD_T thread); - -int thread_cancel(THREAD_T thread); - -#ifdef WIN32 -#undef HAVE_THREAD_CLEANUP -#else -#ifdef HAVE_PTHREAD_CANCEL -#define HAVE_THREAD_CLEANUP 1 -#define thread_cleanup_push(routine, arg) pthread_cleanup_push(routine, arg) -#define thread_cleanup_pop(execute) pthread_cleanup_pop(execute) -#endif -#endif - -void mutex_init(mutex_t* mutex); -void mutex_destroy(mutex_t* mutex); -void mutex_lock(mutex_t* mutex); -void mutex_unlock(mutex_t* mutex); - -void thread_once(thread_once_t *once_control, void (*init_routine)(void)); - -#endif diff --git a/common/userpref.c b/common/userpref.c index a5aa7cb..76945e1 100644 --- a/common/userpref.c +++ b/common/userpref.c @@ -2,6 +2,7 @@   * userpref.c   * contains methods to access user specific certificates IDs and more.   * + * Copyright (c) 2013-2021 Nikias Bassen, All Rights Reserved.   * Copyright (c) 2013-2014 Martin Szulecki All Rights Reserved.   * Copyright (c) 2008 Jonathan Beck All Rights Reserved.   * @@ -28,15 +29,20 @@  #include <stdint.h>  #include <stdlib.h>  #include <string.h> +#include <errno.h> +  #ifdef HAVE_SYS_TYPES_H  #include <sys/types.h>  #endif -#ifndef WIN32 +#include <dirent.h> +#ifndef _WIN32  #include <pwd.h> -#endif  #include <unistd.h> +#include <libgen.h> +#include <sys/stat.h> +#endif  #include <usbmuxd.h> -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL)  #include <openssl/bn.h>  #include <openssl/pem.h>  #include <openssl/rsa.h> @@ -47,28 +53,37 @@  #define X509_set1_notBefore X509_set_notBefore  #define X509_set1_notAfter X509_set_notAfter  #endif -#else +#elif defined(HAVE_GNUTLS)  #include <gnutls/gnutls.h>  #include <gnutls/crypto.h>  #include <gnutls/x509.h>  #include <gcrypt.h>  #include <libtasn1.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/ssl.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/asn1write.h> +#include <mbedtls/oid.h> +#else +#error No supported TLS/SSL library enabled  #endif -#include <dirent.h> -#include <libgen.h> -#include <sys/stat.h> -#include <errno.h> - -#ifdef WIN32 +#ifdef _WIN32  #include <shlobj.h>  #endif +#ifndef ETIMEDOUT +#define ETIMEDOUT 138 +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice-glue/utils.h> +  #include "userpref.h"  #include "debug.h" -#include "utils.h" -#ifndef HAVE_OPENSSL +#if defined(HAVE_GNUTLS)  const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {  	{"PKCS1", 536872976, 0},  	{0, 1073741836, 0}, @@ -79,7 +94,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {  };  #endif -#ifdef WIN32 +#ifdef _WIN32  #define DIR_SEP '\\'  #define DIR_SEP_S "\\"  #else @@ -89,7 +104,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {  #define USERPREF_CONFIG_EXTENSION ".plist" -#ifdef WIN32 +#ifdef _WIN32  #define USERPREF_CONFIG_DIR "Apple"DIR_SEP_S"Lockdown"  #else  #define USERPREF_CONFIG_DIR "lockdown" @@ -99,7 +114,7 @@ const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {  static char *__config_dir = NULL; -#ifdef WIN32 +#ifdef _WIN32  static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written)  {  	if (!unistr || (len <= 0)) return NULL; @@ -141,7 +156,7 @@ const char *userpref_get_config_dir()  	if (__config_dir)  		return __config_dir; -#ifdef WIN32 +#ifdef _WIN32  	wchar_t path[MAX_PATH+1];  	HRESULT hr;  	LPITEMIDLIST pidl = NULL; @@ -300,8 +315,10 @@ userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id,   * @param udid The device UDID as given by the device   * @param pair_record The pair record to read   * - * @return 1 on success and 0 if no device record is given or if it has already - *         been saved previously. + * @return USERPREF_E_SUCCESS on success, + *     USERPREF_E_NOENT if no pairing record was found, + *     USERPREF_E_READ_ERROR if retrieving the pairing record from usbmuxd failed, + *     or USERPREF_E_INVALID_CONF otherwise.   */  userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record)  { @@ -309,24 +326,27 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor  	uint32_t record_size = 0;  	int res = usbmuxd_read_pair_record(udid, &record_data, &record_size); -  	if (res < 0) { -		if (record_data) -			free(record_data); - -		return USERPREF_E_INVALID_CONF; +		free(record_data); +		switch (-res) { +		case ENOENT: +			return USERPREF_E_NOENT; +		case ETIMEDOUT: +			return USERPREF_E_READ_ERROR; +		default: +			return USERPREF_E_INVALID_CONF; +		}  	}  	*pair_record = NULL; -	if (memcmp(record_data, "bplist00", 8) == 0) { -		plist_from_bin(record_data, record_size, pair_record); -	} else { -		plist_from_xml(record_data, record_size, pair_record); -	} - +	plist_from_memory(record_data, record_size, pair_record, NULL);  	free(record_data); -	return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR; +	if (!*pair_record) { +		debug_info("Failed to parse pairing record"); +		return USERPREF_E_INVALID_CONF; +	} +	return USERPREF_E_SUCCESS;  }  /** @@ -343,7 +363,7 @@ userpref_error_t userpref_delete_pair_record(const char *udid)  	return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;  } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL)  static int X509_add_ext_helper(X509 *cert, int nid, char *value)  {  	X509_EXTENSION *ex; @@ -364,6 +384,31 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value)  	return 1;  } +#elif defined(HAVE_MBEDTLS) +static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509write_cert *ctx, int is_ca, int max_pathlen) +{ +	int ret; +	unsigned char buf[9]; +	unsigned char *c = buf + sizeof(buf); +	size_t len = 0; + +	memset( buf, 0, sizeof(buf) ); + +	if (is_ca && max_pathlen > 127) +		return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + +	if (is_ca) { +		if (max_pathlen >= 0) { +			MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) ); +		} +		MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); +	} + +	MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); +	MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + +	return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), 1, buf + sizeof(buf) - len, len ); +}  #endif  /** @@ -375,7 +420,7 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value)   *   * @return 1 if keys were successfully generated, 0 otherwise   */ -userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key) +userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version)  {  	userpref_error_t ret = USERPREF_E_SSL_ERROR; @@ -390,7 +435,11 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  	debug_info("Generating keys and certificates..."); -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +	EVP_PKEY* root_pkey = EVP_RSA_gen(2048); +	EVP_PKEY* host_pkey = EVP_RSA_gen(2048); +#else  	BIGNUM *e = BN_new();  	RSA* root_keypair = RSA_new();  	RSA* host_keypair = RSA_new(); @@ -407,6 +456,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  	EVP_PKEY* host_pkey = EVP_PKEY_new();  	EVP_PKEY_assign_RSA(host_pkey, host_keypair); +#endif  	/* generate root certificate */  	X509* root_cert = X509_new(); @@ -435,7 +485,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  		X509_set_pubkey(root_cert, root_pkey);  		/* sign root cert with root private key */ -		X509_sign(root_cert, root_pkey, EVP_sha1()); +		X509_sign(root_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256());  	}  	/* create host certificate */ @@ -468,7 +518,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  		X509_set_pubkey(host_cert, host_pkey);  		/* sign host cert with root private key */ -		X509_sign(host_cert, root_pkey, EVP_sha1()); +		X509_sign(host_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256());  	}  	if (root_cert && root_pkey && host_cert && host_pkey) { @@ -517,12 +567,22 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  		}  	} -	RSA *pubkey = NULL; +	EVP_PKEY *pubkey = NULL;  	{  		BIO *membp = BIO_new_mem_buf(public_key.data, public_key.size); -		if (!PEM_read_bio_RSAPublicKey(membp, &pubkey, NULL, NULL)) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +		if (!PEM_read_bio_PUBKEY(membp, &pubkey, NULL, NULL)) {  			debug_info("WARNING: Could not read public key");  		} +#else +		RSA *rsa_pubkey = NULL; +		if (!PEM_read_bio_RSAPublicKey(membp, &rsa_pubkey, NULL, NULL)) { +			debug_info("WARNING: Could not read public key"); +		} else { +			pubkey = EVP_PKEY_new(); +			EVP_PKEY_assign_RSA(pubkey, rsa_pubkey); +		} +#endif  		BIO_free(membp);  	} @@ -544,16 +604,13 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  		X509_set1_notAfter(dev_cert, asn1time);  		ASN1_TIME_free(asn1time); -		EVP_PKEY* pkey = EVP_PKEY_new(); -		EVP_PKEY_assign_RSA(pkey, pubkey); -		X509_set_pubkey(dev_cert, pkey); -		EVP_PKEY_free(pkey); +		X509_set_pubkey(dev_cert, pubkey);  		X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash");  		X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");  		/* sign device certificate with root private key */ -		if (X509_sign(dev_cert, root_pkey, EVP_sha1())) { +		if (X509_sign(dev_cert, root_pkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? EVP_sha1() : EVP_sha256())) {  			/* if signing succeeded, export in PEM format */  			BIO* membp = BIO_new(BIO_s_mem());  			if (PEM_write_bio_X509(membp, dev_cert) > 0) { @@ -571,15 +628,15 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  		}  	} -	X509V3_EXT_cleanup();  	X509_free(dev_cert); +	EVP_PKEY_free(pubkey);  	EVP_PKEY_free(root_pkey);  	EVP_PKEY_free(host_pkey);  	X509_free(host_cert);  	X509_free(root_cert); -#else +#elif defined(HAVE_GNUTLS)  	gnutls_x509_privkey_t root_privkey;  	gnutls_x509_crt_t root_cert;  	gnutls_x509_privkey_t host_privkey; @@ -605,7 +662,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  	gnutls_x509_crt_set_ca_status(root_cert, 1);  	gnutls_x509_crt_set_activation_time(root_cert, time(NULL));  	gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); -	gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); +	gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);  	gnutls_x509_crt_set_key(host_cert, host_privkey);  	gnutls_x509_crt_set_serial(host_cert, "\x01", 1); @@ -614,7 +671,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  	gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);  	gnutls_x509_crt_set_activation_time(host_cert, time(NULL));  	gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); -	gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); +	gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);  	/* export to PEM format */  	size_t root_key_export_size = 0; @@ -712,17 +769,17 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  			gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));  			/* use custom hash generation for compatibility with the "Apple ecosystem" */ -			const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; -			size_t hash_size = gnutls_hash_get_len(dig_sha1); +			const gnutls_digest_algorithm_t dig_sha = (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256; +			size_t hash_size = gnutls_hash_get_len(dig_sha);  			unsigned char hash[hash_size]; -			if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { -				debug_info("ERROR: Failed to generate SHA1 for public key"); +			if (gnutls_hash_fast(dig_sha, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { +				debug_info("ERROR: Failed to generate SHA for public key");  			} else {  				gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);  			}  			gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); -			gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0); +			gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);  			if (GNUTLS_E_SUCCESS == gnutls_error) {  				/* if everything went well, export in PEM format */  				size_t export_size = 0; @@ -749,6 +806,211 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da  	gnutls_free(exponent.data);  	gnutls_free(der_pub_key.data); +#elif defined(HAVE_MBEDTLS) +	time_t now = time(NULL); +	struct tm* timestamp = gmtime(&now); +	char notbefore[16]; +	strftime(notbefore, sizeof(notbefore), "%Y%m%d%H%M%S", timestamp); +	time_t then = now + 60 * 60 * 24 * 365 * 10; +	char notafter[16]; +	timestamp = gmtime(&then); +	strftime(notafter, sizeof(notafter), "%Y%m%d%H%M%S", timestamp); + +	mbedtls_mpi sn; +	mbedtls_mpi_init(&sn); +	mbedtls_mpi_lset(&sn, 1); /* 0 doesn't work, so we have to use 1 (like GnuTLS) */ + +	mbedtls_ctr_drbg_context ctr_drbg; +	mbedtls_ctr_drbg_init(&ctr_drbg); + +	mbedtls_pk_context root_pkey; +	mbedtls_pk_init(&root_pkey); + +	mbedtls_pk_context host_pkey; +	mbedtls_pk_init(&host_pkey); + +	mbedtls_pk_context dev_public_key; +	mbedtls_pk_init(&dev_public_key); + +	mbedtls_entropy_context entropy; +	mbedtls_entropy_init(&entropy); + +	mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"limd", 4); + +	/* ----- root key & cert ----- */ +	ret = mbedtls_pk_setup(&root_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); +	if (ret != 0) { +		debug_info("mbedtls_pk_setup returned -0x%04x", -ret); +		goto cleanup; +	} + +	ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(root_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); +	if (ret != 0) { +		debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret); +		goto cleanup; +	} + +	mbedtls_x509write_cert cert; +	mbedtls_x509write_crt_init(&cert); + +	/* set serial number */ +	mbedtls_x509write_crt_set_serial(&cert, &sn); + +	/* set version */ +	mbedtls_x509write_crt_set_version(&cert, 2); + +	/* set x509v3 basic constraints */ +	_mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 1, -1); + +	/* use root public key for root cert */ +	mbedtls_x509write_crt_set_subject_key(&cert, &root_pkey); + +	/* set x509v3 subject key identifier */ +	mbedtls_x509write_crt_set_subject_key_identifier(&cert); + +	/* set key validity */ +	mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + +	/* sign root cert with root private key */ +	mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); +	mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); + +	unsigned char outbuf[16384]; + +	/* write root private key */ +	mbedtls_pk_write_key_pem(&root_pkey, outbuf, sizeof(outbuf)); +	root_key_pem.size = strlen((const char*)outbuf); +	root_key_pem.data = malloc(root_key_pem.size+1); +	memcpy(root_key_pem.data, outbuf, root_key_pem.size); +	root_key_pem.data[root_key_pem.size] = '\0'; + +	/* write root certificate */ +	mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); +	root_cert_pem.size = strlen((const char*)outbuf); +	root_cert_pem.data = malloc(root_cert_pem.size+1); +	memcpy(root_cert_pem.data, outbuf, root_cert_pem.size); +	root_cert_pem.data[root_cert_pem.size] = '\0'; + +	mbedtls_x509write_crt_free(&cert); + + +	/* ----- host key & cert ----- */ +	ret = mbedtls_pk_setup(&host_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); +	if (ret != 0) { +		debug_info("mbedtls_pk_setup returned -0x%04x", -ret); +		goto cleanup; +	} + +	ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(host_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); +	if (ret != 0) { +		debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret); +		goto cleanup; +	} + +	mbedtls_x509write_crt_init(&cert); + +	/* set serial number */ +	mbedtls_x509write_crt_set_serial(&cert, &sn); + +	/* set version */ +	mbedtls_x509write_crt_set_version(&cert, 2); + +	/* set x509v3 basic constraints */ +	_mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1); + +	/* use host public key for host cert */ +	mbedtls_x509write_crt_set_subject_key(&cert, &host_pkey); + +	/* set x509v3 subject key identifier */ +	mbedtls_x509write_crt_set_subject_key_identifier(&cert); + +	/* set x509v3 key usage */ +	mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT); + +	/* set key validity */ +	mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + +	/* sign host cert with root private key */ +	mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); +	mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); + +	/* write host private key */ +	mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf)); +	host_key_pem.size = strlen((const char*)outbuf); +	host_key_pem.data = malloc(host_key_pem.size+1); +	memcpy(host_key_pem.data, outbuf, host_key_pem.size); +	host_key_pem.data[host_key_pem.size] = '\0'; + +	/* write host certificate */ +	mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); +	host_cert_pem.size = strlen((const char*)outbuf); +	host_cert_pem.data = malloc(host_cert_pem.size+1); +	memcpy(host_cert_pem.data, outbuf, host_cert_pem.size); +	host_cert_pem.data[host_cert_pem.size] = '\0'; + +	mbedtls_x509write_crt_free(&cert); + + +	/* ----- device certificate ----- */ +	unsigned char* pubkey_data = malloc(public_key.size+1); +	if (!pubkey_data) { +		debug_info("malloc() failed\n"); +		goto cleanup; +	} +	memcpy(pubkey_data, public_key.data, public_key.size); +	pubkey_data[public_key.size] = '\0'; + +	int pr = mbedtls_pk_parse_public_key(&dev_public_key, pubkey_data, public_key.size+1); +	free(pubkey_data); +	if (pr != 0) { +		debug_info("Failed to read device public key: -0x%x\n", -pr); +		goto cleanup; +	} + +	mbedtls_x509write_crt_init(&cert); + +	/* set serial number */ +	mbedtls_x509write_crt_set_serial(&cert, &sn); + +	/* set version */ +	mbedtls_x509write_crt_set_version(&cert, 2); + +	/* set x509v3 basic constraints */ +	_mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1); + +	/* use root public key for dev cert subject key */ +	mbedtls_x509write_crt_set_subject_key(&cert, &dev_public_key); + +	/* set x509v3 subject key identifier */ +	mbedtls_x509write_crt_set_subject_key_identifier(&cert); + +	/* set x509v3 key usage */ +	mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT); + +	/* set key validity */ +	mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + +	/* sign device certificate with root private key */ +	mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); +	mbedtls_x509write_crt_set_md_alg(&cert, (device_version < IDEVICE_DEVICE_VERSION(4,0,0)) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256); + +	/* write device certificate */ +	mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); +	dev_cert_pem.size = strlen((const char*)outbuf); +	dev_cert_pem.data = malloc(dev_cert_pem.size+1); +	memcpy(dev_cert_pem.data, outbuf, dev_cert_pem.size); +	dev_cert_pem.data[dev_cert_pem.size] = '\0'; + +	mbedtls_x509write_crt_free(&cert); + +	/* cleanup */ +cleanup: +	mbedtls_mpi_free(&sn); +	mbedtls_pk_free(&dev_public_key); +	mbedtls_entropy_free(&entropy); +	mbedtls_pk_free(&host_pkey); +	mbedtls_pk_free(&root_pkey); +	mbedtls_ctr_drbg_free(&ctr_drbg);  #endif  	/* make sure that we have all we need */ @@ -783,32 +1045,31 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da   *   * @return 1 if the key was successfully imported.   */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key) -#else +#elif defined(HAVE_GNUTLS)  userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key)  #endif  { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  	if (!key)  		return USERPREF_E_SUCCESS;  #endif  	userpref_error_t ret = USERPREF_E_INVALID_CONF; -#ifdef HAVE_OPENSSL -		ret = pair_record_get_item_as_key_data(pair_record, name, key); -#else -		key_data_t pem = { NULL, 0 }; -		ret = pair_record_get_item_as_key_data(pair_record, name, &pem); -		if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) -			ret = USERPREF_E_SUCCESS; -		else -			ret = USERPREF_E_SSL_ERROR; - -		if (pem.data) -			free(pem.data); -#endif +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) +	ret = pair_record_get_item_as_key_data(pair_record, name, key); +#elif defined(HAVE_GNUTLS) +	key_data_t pem = { NULL, 0 }; +	ret = pair_record_get_item_as_key_data(pair_record, name, &pem); +	if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) +		ret = USERPREF_E_SUCCESS; +	else +		ret = USERPREF_E_SSL_ERROR; +	if (pem.data) +		free(pem.data); +#endif  	return ret;  } @@ -820,32 +1081,31 @@ userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const cha   *   * @return IDEVICE_E_SUCCESS if the certificate was successfully imported.   */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert)  #else  userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert)  #endif  { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  	if (!cert)  		return USERPREF_E_SUCCESS;  #endif  	userpref_error_t ret = USERPREF_E_INVALID_CONF; -#ifdef HAVE_OPENSSL -		ret = pair_record_get_item_as_key_data(pair_record, name, cert); -#else -		key_data_t pem = { NULL, 0 }; -		ret = pair_record_get_item_as_key_data(pair_record, name, &pem); -		if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) -			ret = USERPREF_E_SUCCESS; -		else -			ret = USERPREF_E_SSL_ERROR; - -		if (pem.data) -			free(pem.data); -#endif +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) +	ret = pair_record_get_item_as_key_data(pair_record, name, cert); +#elif defined(HAVE_GNUTLS) +	key_data_t pem = { NULL, 0 }; +	ret = pair_record_get_item_as_key_data(pair_record, name, &pem); +	if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) +		ret = USERPREF_E_SUCCESS; +	else +		ret = USERPREF_E_SSL_ERROR; +	if (pem.data) +		free(pem.data); +#endif  	return ret;  } @@ -880,9 +1140,10 @@ userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const cha  	if (node && plist_get_node_type(node) == PLIST_DATA) {  		plist_get_data_val(node, &buffer, &length); -		value->data = (unsigned char*)malloc(length); +		value->data = (unsigned char*)malloc(length+1);  		memcpy(value->data, buffer, length); -		value->size = length; +		value->data[length] = '\0'; +		value->size = length+1;  		free(buffer);  		buffer = NULL;  	} else { diff --git a/common/userpref.h b/common/userpref.h index 4ea630f..9a1832c 100644 --- a/common/userpref.h +++ b/common/userpref.h @@ -27,7 +27,7 @@  #include <config.h>  #endif -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  typedef struct {  	unsigned char *data;  	unsigned int size; @@ -54,10 +54,11 @@ typedef gnutls_datum_t key_data_t;  typedef enum {  	USERPREF_E_SUCCESS       =  0,  	USERPREF_E_INVALID_ARG   = -1, -	USERPREF_E_INVALID_CONF  = -2, -	USERPREF_E_SSL_ERROR     = -3, -	USERPREF_E_READ_ERROR    = -4, -	USERPREF_E_WRITE_ERROR   = -5, +	USERPREF_E_NOENT         = -2, +	USERPREF_E_INVALID_CONF  = -3, +	USERPREF_E_SSL_ERROR     = -4, +	USERPREF_E_READ_ERROR    = -5, +	USERPREF_E_WRITE_ERROR   = -6,  	USERPREF_E_UNKNOWN_ERROR = -256  } userpref_error_t; @@ -67,8 +68,8 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor  userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, plist_t pair_record);  userpref_error_t userpref_delete_pair_record(const char *udid); -userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); -#ifdef HAVE_OPENSSL +userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, unsigned int device_version); +#if  defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS)  userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key);  userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert);  #else diff --git a/common/utils.c b/common/utils.c deleted file mode 100644 index 4a45d95..0000000 --- a/common/utils.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * utils.c - * Miscellaneous utilities for string manipulation - * - * Copyright (c) 2013 Federico Mena Quintero - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/time.h> -#include <inttypes.h> -#include <ctype.h> - -#include "utils.h" - -#ifndef HAVE_STPCPY -/** - * Copy characters from one string into another - * - * @note: The strings should not overlap, as the behavior is undefined. - * - * @s1: The source string. - * @s2: The destination string. - * - * @return a pointer to the terminating `\0' character of @s1, - * or NULL if @s1 or @s2 is NULL. - */ -char *stpcpy(char *s1, const char *s2) -{ -	if (s1 == NULL || s2 == NULL) -		return NULL; - -	strcpy(s1, s2); - -	return s1 + strlen(s2); -} -#endif - -/** - * Concatenate strings into a newly allocated string - * - * @note: Specify NULL for the last string in the varargs list - * - * @str: The first string in the list - * @...: Subsequent strings.  Use NULL for the last item. - * - * @return a newly allocated string, or NULL if @str is NULL.  This will also - * return NULL and set errno to ENOMEM if memory is exhausted. - */ -char *string_concat(const char *str, ...) -{ -	size_t len; -	va_list args; -	char *s; -	char *result; -	char *dest; - -	if (!str) -		return NULL; - -	/* Compute final length */ - -	len = strlen(str) + 1; /* plus 1 for the null terminator */ - -	va_start(args, str); -	s = va_arg(args, char *); -	while (s) { -		len += strlen(s); -		s = va_arg(args, char*); -	} -	va_end(args); - -	/* Concat each string */ - -	result = malloc(len); -	if (!result) -		return NULL; /* errno remains set */ - -	dest = result; - -	dest = stpcpy(dest, str); - -	va_start(args, str); -	s = va_arg(args, char *); -	while (s) { -		dest = stpcpy(dest, s); -		s = va_arg(args, char *); -	} -	va_end(args); - -	return result; -} - -char *string_build_path(const char *elem, ...) -{ -	if (!elem) -		return NULL; -	va_list args; -	int len = strlen(elem)+1; -	va_start(args, elem); -	char *arg = va_arg(args, char*); -	while (arg) { -		len += strlen(arg)+1; -		arg = va_arg(args, char*); -	} -	va_end(args); - -	char* out = (char*)malloc(len); -	strcpy(out, elem); - -	va_start(args, elem); -	arg = va_arg(args, char*); -	while (arg) { -		strcat(out, "/"); -		strcat(out, arg); -		arg = va_arg(args, char*); -	} -	va_end(args); -	return out; -} - -char *string_format_size(uint64_t size) -{ -	char buf[80]; -	double sz; -	if (size >= 1000000000000LL) { -		sz = ((double)size / 1000000000000.0f); -		sprintf(buf, "%0.1f TB", sz); -	} else if (size >= 1000000000LL) { -		sz = ((double)size / 1000000000.0f); -		sprintf(buf, "%0.1f GB", sz); -	} else if (size >= 1000000LL) { -		sz = ((double)size / 1000000.0f); -		sprintf(buf, "%0.1f MB", sz); -	} else if (size >= 1000LL) { -		sz = ((double)size / 1000.0f); -		sprintf(buf, "%0.1f KB", sz); -	} else { -		sprintf(buf, "%d Bytes", (int)size); -	} -	return strdup(buf); -} - -char *string_toupper(char* str) -{ -	char *res = strdup(str); -	unsigned int i; -	for (i = 0; i < strlen(res); i++) { -		res[i] = toupper(res[i]); -	} -	return res; -} - -static int get_rand(int min, int max) -{ -	int retval = (rand() % (max - min)) + min; -	return retval; -} - -char *generate_uuid() -{ -	const char *chars = "ABCDEF0123456789"; -	int i = 0; -	char *uuid = (char *) malloc(sizeof(char) * 37); - -	srand(time(NULL)); - -	for (i = 0; i < 36; i++) { -		if (i == 8 || i == 13 || i == 18 || i == 23) { -			uuid[i] = '-'; -			continue; -		} else { -			uuid[i] = chars[get_rand(0, 16)]; -		} -	} - -	/* make it a real string */ -	uuid[36] = '\0'; - -	return uuid; -} - -void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) -{ -	FILE *f; -	uint64_t size; - -	*length = 0; - -	f = fopen(filename, "rb"); -	if (!f) { -		return; -	} - -	fseek(f, 0, SEEK_END); -	size = ftell(f); -	rewind(f); - -	if (size == 0) { -		fclose(f); -		return; -	} - -	*buffer = (char*)malloc(sizeof(char)*(size+1)); -	if (fread(*buffer, sizeof(char), size, f) != size) { -		fclose(f); -		return; -	} -	fclose(f); - -	*length = size; -} - -void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) -{ -	FILE *f; - -	f = fopen(filename, "wb"); -	if (f) { -		fwrite(buffer, sizeof(char), length, f); -		fclose(f); -	} -} - -int plist_read_from_filename(plist_t *plist, const char *filename) -{ -	char *buffer = NULL; -	uint64_t length; - -	if (!filename) -		return 0; - -	buffer_read_from_filename(filename, &buffer, &length); - -	if (!buffer) { -		return 0; -	} - -	if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) { -		plist_from_bin(buffer, length, plist); -	} else { -		plist_from_xml(buffer, length, plist); -	} - -	free(buffer); - -	return 1; -} - -int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format) -{ -	char *buffer = NULL; -	uint32_t length; - -	if (!plist || !filename) -		return 0; - -	if (format == PLIST_FORMAT_XML) -		plist_to_xml(plist, &buffer, &length); -	else if (format == PLIST_FORMAT_BINARY) -		plist_to_bin(plist, &buffer, &length); -	else -		return 0; - -	buffer_write_to_filename(filename, buffer, length); - -	free(buffer); - -	return 1; -} - -static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char base64_pad = '='; - -static char *base64encode(const unsigned char *buf, size_t size) -{ -	if (!buf || !(size > 0)) return NULL; -	int outlen = (size / 3) * 4; -	char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0' -	size_t n = 0; -	size_t m = 0; -	unsigned char input[3]; -	unsigned int output[4]; -	while (n < size) { -		input[0] = buf[n]; -		input[1] = (n+1 < size) ? buf[n+1] : 0; -		input[2] = (n+2 < size) ? buf[n+2] : 0; -		output[0] = input[0] >> 2; -		output[1] = ((input[0] & 3) << 4) + (input[1] >> 4); -		output[2] = ((input[1] & 15) << 2) + (input[2] >> 6); -		output[3] = input[2] & 63; -		outbuf[m++] = base64_str[(int)output[0]]; -		outbuf[m++] = base64_str[(int)output[1]]; -		outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad; -		outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad; -		n+=3; -	} -	outbuf[m] = 0; // 0-termination! -	return outbuf; -} - -static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream); - -static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream) -{ -	/* iterate over items */ -	int i, count; -	plist_t subnode = NULL; - -	count = plist_array_get_size(node); - -	for (i = 0; i < count; i++) { -		subnode = plist_array_get_item(node, i); -		fprintf(stream, "%*s", *indent_level, ""); -		fprintf(stream, "%d: ", i); -		plist_node_print_to_stream(subnode, indent_level, stream); -	} -} - -static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream) -{ -	/* iterate over key/value pairs */ -	plist_dict_iter it = NULL; - -	char* key = NULL; -	plist_t subnode = NULL; -	plist_dict_new_iter(node, &it); -	plist_dict_next_item(node, it, &key, &subnode); -	while (subnode) -	{ -		fprintf(stream, "%*s", *indent_level, ""); -		fprintf(stream, "%s", key); -		if (plist_get_node_type(subnode) == PLIST_ARRAY) -			fprintf(stream, "[%d]: ", plist_array_get_size(subnode)); -		else -			fprintf(stream, ": "); -		free(key); -		key = NULL; -		plist_node_print_to_stream(subnode, indent_level, stream); -		plist_dict_next_item(node, it, &key, &subnode); -	} -	free(it); -} - -static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream) -{ -	char *s = NULL; -	char *data = NULL; -	double d; -	uint8_t b; -	uint64_t u = 0; -	struct timeval tv = { 0, 0 }; - -	plist_type t; - -	if (!node) -		return; - -	t = plist_get_node_type(node); - -	switch (t) { -	case PLIST_BOOLEAN: -		plist_get_bool_val(node, &b); -		fprintf(stream, "%s\n", (b ? "true" : "false")); -		break; - -	case PLIST_UINT: -		plist_get_uint_val(node, &u); -		fprintf(stream, "%"PRIu64"\n", u); -		break; - -	case PLIST_REAL: -		plist_get_real_val(node, &d); -		fprintf(stream, "%f\n", d); -		break; - -	case PLIST_STRING: -		plist_get_string_val(node, &s); -		fprintf(stream, "%s\n", s); -		free(s); -		break; - -	case PLIST_KEY: -		plist_get_key_val(node, &s); -		fprintf(stream, "%s: ", s); -		free(s); -		break; - -	case PLIST_DATA: -		plist_get_data_val(node, &data, &u); -		if (u > 0) { -			s = base64encode((unsigned char*)data, u); -			free(data); -			if (s) { -				fprintf(stream, "%s\n", s); -				free(s); -			} else { -				fprintf(stream, "\n"); -			} -		} else { -			fprintf(stream, "\n"); -		} -		break; - -	case PLIST_DATE: -		plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec); -		{ -			time_t ti = (time_t)tv.tv_sec; -			struct tm *btime = localtime(&ti); -			if (btime) { -				s = (char*)malloc(24); - 				memset(s, 0, 24); -				if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) { -					free (s); -					s = NULL; -				} -			} -		} -		if (s) { -			fprintf(stream, "%s\n", s); -			free(s); -		} else { -			fprintf(stream, "\n"); -		} -		break; - -	case PLIST_ARRAY: -		fprintf(stream, "\n"); -		(*indent_level)++; -		plist_array_print_to_stream(node, indent_level, stream); -		(*indent_level)--; -		break; - -	case PLIST_DICT: -		fprintf(stream, "\n"); -		(*indent_level)++; -		plist_dict_print_to_stream(node, indent_level, stream); -		(*indent_level)--; -		break; - -	default: -		break; -	} -} - -void plist_print_to_stream(plist_t plist, FILE* stream) -{ -	int indent = 0; - -	if (!plist || !stream) -		return; - -	switch (plist_get_node_type(plist)) { -	case PLIST_DICT: -		plist_dict_print_to_stream(plist, &indent, stream); -		break; -	case PLIST_ARRAY: -		plist_array_print_to_stream(plist, &indent, stream); -		break; -	default: -		plist_node_print_to_stream(plist, &indent, stream); -	} -} diff --git a/common/utils.h b/common/utils.h deleted file mode 100644 index 8426bc0..0000000 --- a/common/utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * utils.h - * Miscellaneous utilities for string manipulation - * - * Copyright (c) 2013 Federico Mena Quintero - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - */ - -#ifndef __UTILS_H -#define __UTILS_H - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef WIN32 -#include <windows.h> -#endif - -#include <stdio.h> -#include <plist/plist.h> - -#define MAC_EPOCH 978307200 - -#ifndef HAVE_STPCPY -char *stpcpy(char *s1, const char *s2); -#endif -char *string_concat(const char *str, ...); -char *string_build_path(const char *elem, ...); -char *string_format_size(uint64_t size); -char *string_toupper(char *str); -char *generate_uuid(void); - -void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); -void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length); - -enum plist_format_t { -	PLIST_FORMAT_XML, -	PLIST_FORMAT_BINARY -}; - -int plist_read_from_filename(plist_t *plist, const char *filename); -int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format); - -void plist_print_to_stream(plist_t plist, FILE* stream); - -#endif  | 
