aboutsummaryrefslogtreecommitdiffstats
path: root/src/frontends/osx/strongSwan/Control.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontends/osx/strongSwan/Control.m')
-rw-r--r--src/frontends/osx/strongSwan/Control.m258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/frontends/osx/strongSwan/Control.m b/src/frontends/osx/strongSwan/Control.m
new file mode 100644
index 000000000..6bb0d0fa5
--- /dev/null
+++ b/src/frontends/osx/strongSwan/Control.m
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program 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 General Public License
+ * for more details.
+ */
+
+#import "Control.h"
+#import "Helper.h"
+
+@implementation Control {
+ /* Provides the XPC main connection to the privileged helper */
+ Helper *helper;
+ /* active connection specific XPC channels, indexed by connection name */
+ NSDictionary *active;
+ /* delegate to invoke callbacks on */
+ id<ControlDelegate> del;
+}
+
+- (NSString*)translateAlert:(const char*)alert
+{
+ if (strcmp(alert, "local-auth") == 0)
+ {
+ return @"Client authentication failed";
+ }
+ if (strcmp(alert, "remote-auth") == 0)
+ {
+ return @"Server authentication failed";
+ }
+ if (strcmp(alert, "dns") == 0)
+ {
+ return @"Resolving server hostname failed";
+ }
+ if (strcmp(alert, "unreachable") == 0)
+ {
+ return @"Server is unreachable";
+ }
+ if (strcmp(alert, "timeout") == 0)
+ {
+ return @"Server did not respond";
+ }
+ if (strcmp(alert, "proposal-mismatch") == 0)
+ {
+ return @"No common cryptographic algorithms found";
+ }
+ if (strcmp(alert, "ts-mismatch") == 0)
+ {
+ return @"No common traffic selectors found";
+ }
+ return NULL;
+}
+
+- (void)changeState:(connectionState)state withChannel:(xpc_connection_t)channel
+ andConn:(NSDictionary*)conn
+{
+ NSString *name;
+
+ name = [conn objectForKey:@"name"];
+ switch (state)
+ {
+ case STATE_WORKING:
+ xpc_dictionary_set_value(active, [name UTF8String], channel);
+ break;
+ case STATE_DOWN:
+ xpc_dictionary_set_value(active, [name UTF8String], NULL);
+ break;
+ case STATE_UP:
+ break;
+ }
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [del change:state withConnection:conn];
+ });
+}
+
+- (void)handleEvent:(xpc_object_t)request withChannel:(xpc_connection_t)channel
+ andConn:(NSDictionary*)conn
+{
+ xpc_connection_t client;
+ xpc_object_t reply;
+ const char *type, *rpc, *event;
+ client = xpc_dictionary_get_remote_connection(request);
+ type = xpc_dictionary_get_string(request, "type");
+ if (type)
+ {
+ if (strcmp(type, "rpc") == 0)
+ {
+ reply = xpc_dictionary_create_reply(request);
+ rpc = xpc_dictionary_get_string(request, "rpc");
+ if (rpc)
+ {
+ if (strcmp(rpc, "get_password") == 0)
+ {
+ __block NSString *password;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ password = [del createPasswordWithConnection:conn];
+ });
+ xpc_dictionary_set_string(reply, "password",
+ [password UTF8String]);
+ [password release];
+ }
+ }
+ xpc_connection_send_message(client, reply);
+ xpc_release(reply);
+ }
+ if (strcmp(type, "event") == 0)
+ {
+ event = xpc_dictionary_get_string(request, "event");
+ if (event)
+ {
+ if (strcmp(event, "log") == 0)
+ {
+ NSString *line;
+
+ line = [[NSString alloc] initWithUTF8String:
+ xpc_dictionary_get_string(request, "message")];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [del log:line withConnection:conn];
+ });
+ [line release];
+ }
+ if (strcmp(event, "alert") == 0)
+ {
+ NSString *msg;
+ const char *str;
+
+ str = xpc_dictionary_get_string(request, "alert");
+ if (str)
+ {
+ msg = [self translateAlert:str];
+ if (msg)
+ {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [del raise:msg withConnection:conn];
+ });
+ }
+ }
+ }
+ if (strcmp(event, "connecting") == 0)
+ {
+ [self changeState:STATE_WORKING withChannel:channel andConn:conn];
+ }
+ if (strcmp(event, "up") == 0)
+ {
+ /* IKE_SA up */
+ }
+ if (strcmp(event, "down") == 0)
+ {
+ [self changeState:STATE_DOWN withChannel:channel andConn:conn];
+ }
+ if (strcmp(event, "child_up") == 0)
+ {
+ [self changeState:STATE_UP withChannel:channel andConn:conn];
+ }
+ if (strcmp(event, "child_down") == 0)
+ {
+ [self changeState:STATE_DOWN withChannel:channel andConn:conn];
+ }
+ }
+ }
+ }
+}
+
+- (void)connect:(NSDictionary*)conn
+{
+ xpc_object_t request;
+ xpc_connection_t service, daemon;
+ NSString *name, *server, *username;
+
+ name = [conn objectForKey:@"name"];
+ server = [conn objectForKey:@"server"];
+ username = [conn objectForKey:@"username"];
+
+ daemon = [helper getConnection];
+ if (!daemon)
+ {
+ [del raise:[helper getError] withConnection:conn];
+ }
+
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(request, "type", "rpc");
+ xpc_dictionary_set_string(request, "rpc", "start_connection");
+ xpc_dictionary_set_string(request, "name", [name UTF8String]);
+ xpc_dictionary_set_string(request, "host", [server UTF8String]);
+ xpc_dictionary_set_string(request, "id", [username UTF8String]);
+
+ service = xpc_connection_create(NULL, NULL);
+ xpc_connection_set_event_handler(service, ^(xpc_object_t channel) {
+
+ xpc_connection_set_event_handler(channel, ^(xpc_object_t event) {
+
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED ||
+ event == XPC_ERROR_CONNECTION_INVALID)
+ {
+ xpc_dictionary_set_value(active, [name UTF8String], NULL);
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [del change:STATE_DOWN withConnection:conn];
+ });
+ }
+ else
+ {
+ [self handleEvent:event withChannel:channel andConn:conn];
+ }
+ });
+ xpc_connection_resume(channel);
+ });
+
+ xpc_connection_resume(service);
+ xpc_dictionary_set_connection(request, "channel", xpc_retain(service));
+ xpc_connection_send_message_with_reply(daemon, request,
+ dispatch_get_main_queue(),
+ ^(xpc_object_t reply) {});
+ xpc_release(request);
+}
+
+- (void)disconnect:(NSDictionary*)conn
+{
+ xpc_connection_t tunnel;
+ xpc_object_t request;
+
+ tunnel = xpc_dictionary_get_value(active,
+ [[conn objectForKey:@"name"] UTF8String]);
+ if (tunnel)
+ {
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_string(request, "type", "rpc");
+ xpc_dictionary_set_string(request, "rpc", "stop_connection");
+ xpc_connection_send_message_with_reply(tunnel, request,
+ dispatch_get_main_queue(),
+ ^(xpc_object_t reply) {});
+ xpc_release(request);
+ }
+}
+
+- (void)dealloc
+{
+ xpc_release(active);
+ [super dealloc];
+}
+
+- (id)initWithDelegate:(id<ControlDelegate>)delegate;
+{
+ self = [super init];
+ helper = [[Helper alloc] init];
+ active = xpc_dictionary_create(NULL, NULL, 0);
+ del = delegate;
+ return self;
+}
+
+@end