259 lines
6.5 KiB
Objective-C
259 lines
6.5 KiB
Objective-C
/*
|
|
* 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
|