xpc: add Xcode project for a charon controlled through XPC
[strongswan.git] / src / frontends / osx / charon-xpc / charon-xpc.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <xpc/xpc.h>
21
22 #include <library.h>
23 #include <hydra.h>
24 #include <daemon.h>
25
26 /**
27 * Loglevel configuration
28 */
29 static level_t levels[DBG_MAX];
30
31 /**
32 * hook in library for debugging messages
33 */
34 extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
35
36 /**
37 * Logging hook for library logs, using stderr output
38 */
39 static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
40 {
41 va_list args;
42
43 if (level <= 1)
44 {
45 va_start(args, fmt);
46 fprintf(stderr, "00[%N] ", debug_names, group);
47 vfprintf(stderr, fmt, args);
48 fprintf(stderr, "\n");
49 va_end(args);
50 }
51 }
52
53 /**
54 * Return version of this helper
55 */
56 xpc_object_t get_version(xpc_object_t request, xpc_connection_t client)
57 {
58 xpc_object_t reply;
59
60 reply = xpc_dictionary_create_reply(request);
61 xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION);
62
63 return reply;
64 }
65
66 /**
67 * XPC command dispatch table
68 */
69 struct {
70 char *name;
71 xpc_object_t (*handler)(xpc_object_t request, xpc_connection_t client);
72 } commands[] = {
73 { "get_version", get_version },
74 };
75
76 /**
77 * Handle a received XPC request message
78 */
79 static void handle(xpc_object_t request)
80 {
81 xpc_connection_t client;
82 xpc_object_t reply;
83 const char *command;
84 int i;
85
86 client = xpc_dictionary_get_remote_connection(request);
87 command = xpc_dictionary_get_string(request, "command");
88 if (command)
89 {
90 for (i = 0; i < countof(commands); i++)
91 {
92 if (streq(commands[i].name, command))
93 {
94 reply = commands[i].handler(request, client);
95 if (reply)
96 {
97 xpc_connection_send_message(client, reply);
98 xpc_release(reply);
99 }
100 break;
101 }
102 }
103 }
104 }
105
106 /**
107 * Dispatch XPC commands
108 */
109 static int dispatch()
110 {
111 xpc_connection_t service;
112
113 service = xpc_connection_create_mach_service("org.strongswan.charon-xpc",
114 NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
115 if (!service)
116 {
117 return EXIT_FAILURE;
118 }
119
120 xpc_connection_set_event_handler(service, ^(xpc_object_t conn) {
121
122 xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
123
124 if (xpc_get_type(event) == XPC_TYPE_ERROR)
125 {
126 if (event == XPC_ERROR_CONNECTION_INVALID ||
127 event == XPC_ERROR_TERMINATION_IMMINENT)
128 {
129 xpc_connection_cancel(conn);
130 }
131 }
132 else
133 {
134 handle(event);
135 }
136 });
137 xpc_connection_resume(conn);
138 });
139
140 xpc_connection_resume(service);
141
142 dispatch_main();
143
144 xpc_release(service);
145 }
146
147 /**
148 * Main function, starts the daemon.
149 */
150 int main(int argc, char *argv[])
151 {
152 struct utsname utsname;
153 int group;
154
155 dbg = dbg_stderr;
156 atexit(library_deinit);
157 if (!library_init(NULL))
158 {
159 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
160 }
161 if (lib->integrity)
162 {
163 if (!lib->integrity->check_file(lib->integrity, "charon-xpc", argv[0]))
164 {
165 exit(SS_RC_DAEMON_INTEGRITY);
166 }
167 }
168 atexit(libhydra_deinit);
169 if (!libhydra_init("charon-xpc"))
170 {
171 exit(SS_RC_INITIALIZATION_FAILED);
172 }
173 atexit(libcharon_deinit);
174 if (!libcharon_init("charon-xpc"))
175 {
176 exit(SS_RC_INITIALIZATION_FAILED);
177 }
178 for (group = 0; group < DBG_MAX; group++)
179 {
180 levels[group] = LEVEL_CTRL;
181 }
182 charon->load_loggers(charon, levels, TRUE);
183
184 lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
185 lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
186 if (!charon->initialize(charon,
187 lib->settings->get_str(lib->settings, "charon-xpc.load",
188 "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute "
189 "socket-default eap-identity eap-mschapv2")))
190 {
191 exit(SS_RC_INITIALIZATION_FAILED);
192 }
193
194 if (uname(&utsname) != 0)
195 {
196 memset(&utsname, 0, sizeof(utsname));
197 }
198 DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)",
199 VERSION, utsname.sysname, utsname.release, utsname.machine);
200
201 charon->start(charon);
202 return dispatch();
203 }