From 1c6188a0c2cd25604fdcc9b1843298286fb34dfc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 16 Dec 2014 16:58:17 +0100 Subject: [PATCH 1/5] charon-xpc: Add a work-around to trigger IP address add events after boot --- src/frontends/osx/charon-xpc/charon-xpc.c | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index 2235be12d..057bfbd88 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -122,6 +122,29 @@ static void segv_handler(int signal) abort(); } +/** + * PF_ROUTE for some reason does not send an event for the first address + * installed after a fresh boot. Fix this by installing a fake tun address + * just to remove it afterwards. + */ +static void fixup_pf_route() +{ + tun_device_t *tun; + host_t *host; + + tun = tun_device_create(NULL); + if (tun) + { + if (tun->up(tun)) + { + host = host_create_from_string("127.0.0.99", 0); + tun->set_address(tun, host, 32); + host->destroy(host); + } + tun->destroy(tun); + } +} + /** * Main function, starts the daemon. */ @@ -204,5 +227,6 @@ int main(int argc, char *argv[]) atexit(dispatcher_cleanup); charon->start(charon); + fixup_pf_route(); return run(); } From 6fa203b8d4dfdaad586a3b056cb1ff1318f6e643 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 24 Oct 2014 15:21:11 +0200 Subject: [PATCH 2/5] kernel-pfroute: If a new interface appears, slightly delay address enumeration On OS X 10.10, when installing a virtual IP on a tun device, there is a chance that a RTM_IFANNOUNCE is sent before the IP is ready on that link when calling getifaddrs(). As we don't get an RTM_NEWADDR event either, that race lets us miss the virtual IP install event, failing the add_ip() call. --- src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c index 26fae0d6b..0f7802270 100644 --- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -830,6 +830,15 @@ static void process_link(private_kernel_pfroute_net_t *this, DBG1(DBG_KNL, "interface %s deactivated", iface->ifname); } } +#ifdef __APPLE__ + /* There seems to be a race condition on 10.10, where we get + * the RTM_IFINFO, but getifaddrs() does not return the virtual + * IP installed on a tun device, but we also don't get a + * RTM_NEWADDR. We therefore could miss the new address, letting + * virtual IP installation fail. Delaying getifaddrs() helps, + * but is obviously not a clean fix. */ + usleep(50000); +#endif iface->flags = msg->ifm_flags; repopulate_iface(this, iface); found = TRUE; From 04337fed02e8dde1b184b3c163cc76138037905e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 16 Dec 2014 16:55:29 +0100 Subject: [PATCH 3/5] apple: Redefine some additional clashing Mach types While they usually are not included in a normal strongSwan build, the XPC header indirectly defines these Mach types. To build charon-xpc, which uses both XPC and strongSwan includes, we have to redefine these types. --- src/libcharon/sa/task.h | 2 ++ src/libstrongswan/networking/host.h | 6 +++--- src/libstrongswan/processing/processor.h | 2 ++ src/libstrongswan/utils/compat/apple.h | 6 ++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h index f2c4299cc..8e380851a 100644 --- a/src/libcharon/sa/task.h +++ b/src/libcharon/sa/task.h @@ -22,6 +22,8 @@ #ifndef TASK_H_ #define TASK_H_ +#include + typedef enum task_type_t task_type_t; typedef struct task_t task_t; diff --git a/src/libstrongswan/networking/host.h b/src/libstrongswan/networking/host.h index 26f23bc99..db6f4dd49 100644 --- a/src/libstrongswan/networking/host.h +++ b/src/libstrongswan/networking/host.h @@ -24,6 +24,9 @@ #ifndef HOST_H_ #define HOST_H_ +#include +#include + typedef enum host_diff_t host_diff_t; typedef struct host_t host_t; @@ -31,9 +34,6 @@ typedef struct host_t host_t; #include #include -#include -#include - /** * Representates a Host * diff --git a/src/libstrongswan/processing/processor.h b/src/libstrongswan/processing/processor.h index f96530e54..ee08870fb 100644 --- a/src/libstrongswan/processing/processor.h +++ b/src/libstrongswan/processing/processor.h @@ -23,6 +23,8 @@ #ifndef PROCESSOR_H_ #define PROCESSOR_H_ +#include + typedef struct processor_t processor_t; #include diff --git a/src/libstrongswan/utils/compat/apple.h b/src/libstrongswan/utils/compat/apple.h index 77e072279..61afb9d9e 100644 --- a/src/libstrongswan/utils/compat/apple.h +++ b/src/libstrongswan/utils/compat/apple.h @@ -34,6 +34,12 @@ /* Mach uses a semaphore_create() call, use a different name for ours */ #define semaphore_create(x) strongswan_semaphore_create(x) +/* Since OS X 10.10 XPC includes some additional conflicting Mach types */ +#define host_t strongswan_host_t +#define processor_t strongswan_processor_t +#define task_t strongswan_task_t +#define thread_t strongswan_thread_t + /* forward declaration, see below */ static inline int precancellable_poll(struct pollfd fds[], nfds_t nfds, int timeout); From dacd667c84525cf335e61c8000922ca68686a4b6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 16 Dec 2014 17:13:44 +0100 Subject: [PATCH 4/5] osx: Initial import of the Objective-C App graphical user interface --- .../osx/charon-xpc/charon-xpc-Info.plist | 2 +- .../osx/strongSwan.xcodeproj/project.pbxproj | 293 +++- src/frontends/osx/strongSwan/AppDelegate.h | 36 + src/frontends/osx/strongSwan/AppDelegate.m | 358 ++++ src/frontends/osx/strongSwan/ConnController.h | 74 + src/frontends/osx/strongSwan/ConnController.m | 102 ++ src/frontends/osx/strongSwan/Control.h | 95 ++ src/frontends/osx/strongSwan/Control.m | 258 +++ src/frontends/osx/strongSwan/Helper.h | 41 + src/frontends/osx/strongSwan/Helper.m | 223 +++ src/frontends/osx/strongSwan/LogController.h | 45 + src/frontends/osx/strongSwan/LogController.m | 51 + .../osx/strongSwan/PasswordController.h | 41 + .../osx/strongSwan/PasswordController.m | 56 + .../osx/strongSwan/en.lproj/ConnWindow.xib | 1469 +++++++++++++++++ .../osx/strongSwan/en.lproj/Credits.rtf | 32 + .../osx/strongSwan/en.lproj/InfoPlist.strings | 1 + .../osx/strongSwan/en.lproj/LogWindow.xib | 587 +++++++ .../osx/strongSwan/en.lproj/MainMenu.xib | 277 ++++ .../strongSwan/en.lproj/PasswordWindow.xib | 578 +++++++ src/frontends/osx/strongSwan/icon-active.png | Bin 0 -> 401 bytes src/frontends/osx/strongSwan/icon-alt.png | Bin 0 -> 413 bytes src/frontends/osx/strongSwan/icon-large.icns | Bin 0 -> 77520 bytes src/frontends/osx/strongSwan/icon.png | Bin 0 -> 467 bytes src/frontends/osx/strongSwan/main.m | 21 + .../osx/strongSwan/strongSwan-Info.plist | 43 + .../osx/strongSwan/strongSwan-Prefix.pch | 7 + 27 files changed, 4681 insertions(+), 9 deletions(-) create mode 100644 src/frontends/osx/strongSwan/AppDelegate.h create mode 100644 src/frontends/osx/strongSwan/AppDelegate.m create mode 100644 src/frontends/osx/strongSwan/ConnController.h create mode 100644 src/frontends/osx/strongSwan/ConnController.m create mode 100644 src/frontends/osx/strongSwan/Control.h create mode 100644 src/frontends/osx/strongSwan/Control.m create mode 100644 src/frontends/osx/strongSwan/Helper.h create mode 100644 src/frontends/osx/strongSwan/Helper.m create mode 100644 src/frontends/osx/strongSwan/LogController.h create mode 100644 src/frontends/osx/strongSwan/LogController.m create mode 100644 src/frontends/osx/strongSwan/PasswordController.h create mode 100644 src/frontends/osx/strongSwan/PasswordController.m create mode 100644 src/frontends/osx/strongSwan/en.lproj/ConnWindow.xib create mode 100644 src/frontends/osx/strongSwan/en.lproj/Credits.rtf create mode 100644 src/frontends/osx/strongSwan/en.lproj/InfoPlist.strings create mode 100644 src/frontends/osx/strongSwan/en.lproj/LogWindow.xib create mode 100644 src/frontends/osx/strongSwan/en.lproj/MainMenu.xib create mode 100644 src/frontends/osx/strongSwan/en.lproj/PasswordWindow.xib create mode 100644 src/frontends/osx/strongSwan/icon-active.png create mode 100644 src/frontends/osx/strongSwan/icon-alt.png create mode 100644 src/frontends/osx/strongSwan/icon-large.icns create mode 100644 src/frontends/osx/strongSwan/icon.png create mode 100644 src/frontends/osx/strongSwan/main.m create mode 100644 src/frontends/osx/strongSwan/strongSwan-Info.plist create mode 100644 src/frontends/osx/strongSwan/strongSwan-Prefix.pch diff --git a/src/frontends/osx/charon-xpc/charon-xpc-Info.plist b/src/frontends/osx/charon-xpc/charon-xpc-Info.plist index e8ddd24b0..85e2e4dc2 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc-Info.plist +++ b/src/frontends/osx/charon-xpc/charon-xpc-Info.plist @@ -12,7 +12,7 @@ 1.0 SMAuthorizedClients - identifier org.strongswan.osx and certificate leaf[subject.CN] = "Joe Developer" + identifier org.strongswan.osx and certificate leaf[subject.CN] = "Developer ID Application: revosec AG (SRXT3TB2PY)" diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 3b77d2552..e7840e75a 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -7,22 +7,94 @@ objects = { /* Begin PBXBuildFile section */ + 5B04A712174558F100A13BDC /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 5B04A711174558F100A13BDC /* icon.png */; }; + 5B04A7211747800F00A13BDC /* icon-alt.png in Resources */ = {isa = PBXBuildFile; fileRef = 5B04A7201747800F00A13BDC /* icon-alt.png */; }; + 5B313F9A17A93D590055C86A /* icon-large.icns in Resources */ = {isa = PBXBuildFile; fileRef = 5B313F9917A93D590055C86A /* icon-large.icns */; }; 5B74989217311B200041971E /* xpc_channels.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74989117311B200041971E /* xpc_channels.c */; }; 5B7498B8173275D10041971E /* xpc_logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B7498B7173275D10041971E /* xpc_logger.c */; }; + 5B7FA5A11754D5DB00264BAC /* LogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B7FA59F1754D5DB00264BAC /* LogController.m */; }; + 5B7FA5B01754EBC800264BAC /* ConnController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B7FA5AE1754EBC800264BAC /* ConnController.m */; }; + 5B7FA5B51754F5AF00264BAC /* PasswordController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B7FA5B31754F5AF00264BAC /* PasswordController.m */; }; + 5B8D879B1A40658B008E5702 /* Helper.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B8D879A1A40658B008E5702 /* Helper.m */; }; + 5B8D879C1A409E4D008E5702 /* LogWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B8D879E1A409E4D008E5702 /* LogWindow.xib */; }; + 5B8D879F1A409E5A008E5702 /* ConnWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B8D87A11A409E5A008E5702 /* ConnWindow.xib */; }; + 5B8D87A21A409E6D008E5702 /* PasswordWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B8D87A41A409E6D008E5702 /* PasswordWindow.xib */; }; + 5BAE9E9A17A94A2600858FE2 /* icon-active.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BAE9E9917A94A2500858FE2 /* icon-active.png */; }; + 5BD1CCB11726DB0100587077 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCB01726DB0100587077 /* Cocoa.framework */; }; + 5BD1CCBB1726DB0100587077 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5BD1CCB91726DB0100587077 /* InfoPlist.strings */; }; + 5BD1CCBD1726DB0100587077 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCBC1726DB0100587077 /* main.m */; }; + 5BD1CCC11726DB0100587077 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 5BD1CCBF1726DB0100587077 /* Credits.rtf */; }; + 5BD1CCC41726DB0100587077 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCC31726DB0100587077 /* AppDelegate.m */; }; + 5BD1CCC71726DB0200587077 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BD1CCC51726DB0200587077 /* MainMenu.xib */; }; 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; + 5BD1CCDF1726DC0A00587077 /* org.strongswan.charon-xpc in Copy Files */ = {isa = PBXBuildFile; fileRef = 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */; }; + 5BD1CCEB1727CCA400587077 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 5BD1CCEA1727CCA400587077 /* README.md */; }; + 5BD1CCED1727D7AF00587077 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */; }; + 5BD1CCF31727DE3E00587077 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; + 5BD1CCFB1729365F00587077 /* Control.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCFA1729365F00587077 /* Control.m */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; 5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; 5BF60F631743C57500E5D608 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 5BD1CCE81726E45200587077 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5BD1CCA31726DB0100587077 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5BD1CCD01726DB4000587077; + remoteInfo = "charon-xpc"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5BD1CCDE1726DBF100587077 /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 12; + dstPath = Contents/Library/LaunchServices; + dstSubfolderSpec = 1; + files = ( + 5BD1CCDF1726DC0A00587077 /* org.strongswan.charon-xpc in Copy Files */, + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 5B04A711174558F100A13BDC /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = ""; }; + 5B04A7201747800F00A13BDC /* icon-alt.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-alt.png"; sourceTree = ""; }; + 5B313F9917A93D590055C86A /* icon-large.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "icon-large.icns"; sourceTree = ""; }; 5B74984C172AA3550041971E /* xpc_dispatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_dispatch.c; sourceTree = ""; }; 5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = ""; }; 5B74989017311AFC0041971E /* xpc_channels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_channels.h; sourceTree = ""; }; 5B74989117311B200041971E /* xpc_channels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_channels.c; sourceTree = ""; }; 5B7498B7173275D10041971E /* xpc_logger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_logger.c; sourceTree = ""; }; 5B7498B9173275DD0041971E /* xpc_logger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_logger.h; sourceTree = ""; }; + 5B7FA59E1754D5DB00264BAC /* LogController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogController.h; sourceTree = ""; }; + 5B7FA59F1754D5DB00264BAC /* LogController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogController.m; sourceTree = ""; }; + 5B7FA5AD1754EBC800264BAC /* ConnController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnController.h; sourceTree = ""; }; + 5B7FA5AE1754EBC800264BAC /* ConnController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConnController.m; sourceTree = ""; }; + 5B7FA5B21754F5AF00264BAC /* PasswordController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PasswordController.h; sourceTree = ""; }; + 5B7FA5B31754F5AF00264BAC /* PasswordController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PasswordController.m; sourceTree = ""; }; + 5B8D87991A406572008E5702 /* Helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Helper.h; sourceTree = ""; }; + 5B8D879A1A40658B008E5702 /* Helper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Helper.m; sourceTree = ""; }; + 5B8D879D1A409E4D008E5702 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/LogWindow.xib; sourceTree = ""; }; + 5B8D87A01A409E5A008E5702 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ConnWindow.xib; sourceTree = ""; }; + 5B8D87A31A409E6D008E5702 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/PasswordWindow.xib; sourceTree = ""; }; + 5BAE9E9917A94A2500858FE2 /* icon-active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-active.png"; sourceTree = ""; }; + 5BD1CCAC1726DB0100587077 /* strongSwan.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = strongSwan.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5BD1CCB01726DB0100587077 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5BD1CCB81726DB0100587077 /* strongSwan-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "strongSwan-Info.plist"; sourceTree = ""; }; + 5BD1CCBA1726DB0100587077 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5BD1CCBC1726DB0100587077 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5BD1CCBE1726DB0100587077 /* strongSwan-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "strongSwan-Prefix.pch"; sourceTree = ""; }; + 5BD1CCC01726DB0100587077 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; + 5BD1CCC21726DB0100587077 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5BD1CCC31726DB0100587077 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5BD1CCC61726DB0200587077 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; + 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Launchd.plist"; sourceTree = ""; }; @@ -30,10 +102,22 @@ 5BD1CCEA1727CCA400587077 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 5BD1CCF21727DE3E00587077 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 5BD1CCF91729365F00587077 /* Control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Control.h; sourceTree = ""; }; + 5BD1CCFA1729365F00587077 /* Control.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Control.m; sourceTree = ""; }; 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 5BD1CCA91726DB0100587077 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BD1CCF31727DE3E00587077 /* Security.framework in Frameworks */, + 5BD1CCED1727D7AF00587077 /* ServiceManagement.framework in Frameworks */, + 5BD1CCB11726DB0100587077 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5BD1CCCE1726DB4000587077 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -51,6 +135,7 @@ isa = PBXGroup; children = ( 5BD1CCEA1727CCA400587077 /* README.md */, + 5BD1CCB61726DB0100587077 /* strongSwan */, 5BD1CCD51726DB4000587077 /* charon-xpc */, 5BD1CCAF1726DB0100587077 /* Frameworks */, 5BD1CCAD1726DB0100587077 /* Products */, @@ -60,6 +145,7 @@ 5BD1CCAD1726DB0100587077 /* Products */ = { isa = PBXGroup; children = ( + 5BD1CCAC1726DB0100587077 /* strongSwan.app */, 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */, ); name = Products; @@ -71,11 +157,44 @@ 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */, 5BD1CCF21727DE3E00587077 /* Security.framework */, 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */, + 5BD1CCB01726DB0100587077 /* Cocoa.framework */, 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */, ); name = Frameworks; sourceTree = ""; }; + 5BD1CCB61726DB0100587077 /* strongSwan */ = { + isa = PBXGroup; + children = ( + 5B04A711174558F100A13BDC /* icon.png */, + 5B04A7201747800F00A13BDC /* icon-alt.png */, + 5BAE9E9917A94A2500858FE2 /* icon-active.png */, + 5B313F9917A93D590055C86A /* icon-large.icns */, + 5BD1CCBF1726DB0100587077 /* Credits.rtf */, + 5BD1CCBE1726DB0100587077 /* strongSwan-Prefix.pch */, + 5BD1CCBC1726DB0100587077 /* main.m */, + 5BD1CCB91726DB0100587077 /* InfoPlist.strings */, + 5BD1CCB81726DB0100587077 /* strongSwan-Info.plist */, + 5BD1CCC21726DB0100587077 /* AppDelegate.h */, + 5BD1CCC31726DB0100587077 /* AppDelegate.m */, + 5B7FA59E1754D5DB00264BAC /* LogController.h */, + 5B7FA59F1754D5DB00264BAC /* LogController.m */, + 5B8D879E1A409E4D008E5702 /* LogWindow.xib */, + 5BD1CCC51726DB0200587077 /* MainMenu.xib */, + 5BD1CCF91729365F00587077 /* Control.h */, + 5BD1CCFA1729365F00587077 /* Control.m */, + 5B7FA5AD1754EBC800264BAC /* ConnController.h */, + 5B7FA5AE1754EBC800264BAC /* ConnController.m */, + 5B8D87A11A409E5A008E5702 /* ConnWindow.xib */, + 5B7FA5B21754F5AF00264BAC /* PasswordController.h */, + 5B7FA5B31754F5AF00264BAC /* PasswordController.m */, + 5B8D87A41A409E6D008E5702 /* PasswordWindow.xib */, + 5B8D87991A406572008E5702 /* Helper.h */, + 5B8D879A1A40658B008E5702 /* Helper.m */, + ); + path = strongSwan; + sourceTree = ""; + }; 5BD1CCD51726DB4000587077 /* charon-xpc */ = { isa = PBXGroup; children = ( @@ -95,6 +214,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 5BD1CCAB1726DB0100587077 /* strongSwan */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5BD1CCCA1726DB0200587077 /* Build configuration list for PBXNativeTarget "strongSwan" */; + buildPhases = ( + 5BD1CCA81726DB0100587077 /* Sources */, + 5BD1CCA91726DB0100587077 /* Frameworks */, + 5BD1CCAA1726DB0100587077 /* Resources */, + 5BD1CCDE1726DBF100587077 /* Copy Files */, + ); + buildRules = ( + ); + dependencies = ( + 5BD1CCE91726E45200587077 /* PBXTargetDependency */, + ); + name = strongSwan; + productName = strongSwan; + productReference = 5BD1CCAC1726DB0100587077 /* strongSwan.app */; + productType = "com.apple.product-type.application"; + }; 5BD1CCD01726DB4000587077 /* charon-xpc */ = { isa = PBXNativeTarget; buildConfigurationList = 5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */; @@ -117,7 +255,7 @@ 5BD1CCA31726DB0100587077 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0610; ORGANIZATIONNAME = "revosec AG"; }; buildConfigurationList = 5BD1CCA61726DB0100587077 /* Build configuration list for PBXProject "strongSwan" */; @@ -132,12 +270,48 @@ projectDirPath = ""; projectRoot = ""; targets = ( + 5BD1CCAB1726DB0100587077 /* strongSwan */, 5BD1CCD01726DB4000587077 /* charon-xpc */, ); }; /* End PBXProject section */ +/* Begin PBXResourcesBuildPhase section */ + 5BD1CCAA1726DB0100587077 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BD1CCBB1726DB0100587077 /* InfoPlist.strings in Resources */, + 5BD1CCC11726DB0100587077 /* Credits.rtf in Resources */, + 5BD1CCC71726DB0200587077 /* MainMenu.xib in Resources */, + 5BD1CCEB1727CCA400587077 /* README.md in Resources */, + 5B04A712174558F100A13BDC /* icon.png in Resources */, + 5B04A7211747800F00A13BDC /* icon-alt.png in Resources */, + 5B8D879C1A409E4D008E5702 /* LogWindow.xib in Resources */, + 5B8D879F1A409E5A008E5702 /* ConnWindow.xib in Resources */, + 5B8D87A21A409E6D008E5702 /* PasswordWindow.xib in Resources */, + 5B313F9A17A93D590055C86A /* icon-large.icns in Resources */, + 5BAE9E9A17A94A2600858FE2 /* icon-active.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + 5BD1CCA81726DB0100587077 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BD1CCBD1726DB0100587077 /* main.m in Sources */, + 5BD1CCC41726DB0100587077 /* AppDelegate.m in Sources */, + 5BD1CCFB1729365F00587077 /* Control.m in Sources */, + 5B7FA5A11754D5DB00264BAC /* LogController.m in Sources */, + 5B8D879B1A40658B008E5702 /* Helper.m in Sources */, + 5B7FA5B01754EBC800264BAC /* ConnController.m in Sources */, + 5B7FA5B51754F5AF00264BAC /* PasswordController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5BD1CCCD1726DB4000587077 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -151,12 +325,70 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 5BD1CCE91726E45200587077 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5BD1CCD01726DB4000587077 /* charon-xpc */; + targetProxy = 5BD1CCE81726E45200587077 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5B8D879E1A409E4D008E5702 /* LogWindow.xib */ = { + isa = PBXVariantGroup; + children = ( + 5B8D879D1A409E4D008E5702 /* en */, + ); + name = LogWindow.xib; + sourceTree = ""; + }; + 5B8D87A11A409E5A008E5702 /* ConnWindow.xib */ = { + isa = PBXVariantGroup; + children = ( + 5B8D87A01A409E5A008E5702 /* en */, + ); + name = ConnWindow.xib; + sourceTree = ""; + }; + 5B8D87A41A409E6D008E5702 /* PasswordWindow.xib */ = { + isa = PBXVariantGroup; + children = ( + 5B8D87A31A409E6D008E5702 /* en */, + ); + name = PasswordWindow.xib; + sourceTree = ""; + }; + 5BD1CCB91726DB0100587077 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5BD1CCBA1726DB0100587077 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5BD1CCBF1726DB0100587077 /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 5BD1CCC01726DB0100587077 /* en */, + ); + name = Credits.rtf; + sourceTree = ""; + }; + 5BD1CCC51726DB0200587077 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 5BD1CCC61726DB0200587077 /* en */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 5BD1CCC81726DB0200587077 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_EMPTY_BODY = YES; @@ -175,7 +407,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -185,7 +417,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_EMPTY_BODY = YES; @@ -198,15 +429,48 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; }; name = Release; }; + 5BD1CCCB1726DB0200587077 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application"; + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "strongSwan/strongSwan-Prefix.pch"; + INFOPLIST_FILE = "strongSwan/strongSwan-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = macosx; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5BD1CCCC1726DB0200587077 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "strongSwan/strongSwan-Prefix.pch"; + INFOPLIST_FILE = "strongSwan/strongSwan-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = macosx; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; 5BD1CCDB1726DB4000587077 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "Joe Developer"; + CODE_SIGN_IDENTITY = "Developer ID Application"; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO; @@ -224,6 +488,7 @@ ../../libcharon/.libs, ../../libhydra/.libs, ); + MACOSX_DEPLOYMENT_TARGET = 10.7; OTHER_CFLAGS = ( "-include", ../../../config.h, @@ -249,6 +514,7 @@ ); PRODUCT_NAME = "org.strongswan.charon-xpc"; PROVISIONING_PROFILE = ""; + SDKROOT = macosx; STRIP_STYLE = "non-global"; }; name = Debug; @@ -256,8 +522,8 @@ 5BD1CCDC1726DB4000587077 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "Joe Developer"; - COPY_PHASE_STRIP = YES; + CODE_SIGN_IDENTITY = "Developer ID Application"; + COPY_PHASE_STRIP = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO; @@ -275,6 +541,7 @@ ../../libcharon/.libs, ../../libhydra/.libs, ); + MACOSX_DEPLOYMENT_TARGET = 10.7; OTHER_CFLAGS = ( "-include", ../../../config.h, @@ -300,6 +567,7 @@ ); PRODUCT_NAME = "org.strongswan.charon-xpc"; PROVISIONING_PROFILE = ""; + SDKROOT = macosx; STRIP_STYLE = "non-global"; }; name = Release; @@ -316,6 +584,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5BD1CCCA1726DB0200587077 /* Build configuration list for PBXNativeTarget "strongSwan" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5BD1CCCB1726DB0200587077 /* Debug */, + 5BD1CCCC1726DB0200587077 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/src/frontends/osx/strongSwan/AppDelegate.h b/src/frontends/osx/strongSwan/AppDelegate.h new file mode 100644 index 000000000..062da7d3d --- /dev/null +++ b/src/frontends/osx/strongSwan/AppDelegate.h @@ -0,0 +1,36 @@ +/* + * 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 . + * + * 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 + +#import "Control.h" + +/** + * Main application delegate, controls the status menu + */ +@interface AppDelegate : NSObject { + + /** + * Status menu controlled + */ + IBOutlet NSMenu *statusMenu; +} + +/** + * Action to add a new connection + */ +- (IBAction)addConnection:(id)sender; + +@end diff --git a/src/frontends/osx/strongSwan/AppDelegate.m b/src/frontends/osx/strongSwan/AppDelegate.m new file mode 100644 index 000000000..8fe997e0e --- /dev/null +++ b/src/frontends/osx/strongSwan/AppDelegate.m @@ -0,0 +1,358 @@ +/* + * 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 . + * + * 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 "AppDelegate.h" +#import "Control.h" +#import "LogController.h" +#import "ConnController.h" +#import "PasswordController.h" + +@implementation AppDelegate { + NSStatusItem *statusItem; + NSImage *active; + NSImage *inactive; + NSInteger nonConnectionItemCount; + NSMutableArray *connections; + Control *control; + ConnController *editor; + PasswordController *password; +} + +- (void)change:(connectionState)state withConnection:(NSDictionary*)conn +{ + NSInteger idx; + NSMenuItem *item; + + idx = [statusMenu indexOfItemWithRepresentedObject:conn]; + if (idx != -1) + { + item = [statusMenu itemAtIndex:idx]; + + switch (state) { + case STATE_DOWN: + [item setState:NSOffState]; + [item setAction:@selector(doConnection:)]; + [[[item submenu] itemAtIndex:0] setAction:@selector(doConnection:)]; + [[[item submenu] itemAtIndex:0] setTitle:@"Connect"]; + [[[item submenu] itemAtIndex:1] setAction:@selector(editConnection:)]; + [[[item submenu] itemAtIndex:2] setAction:@selector(removeConnection:)]; + [self updateIcon]; + break; + case STATE_WORKING: + [item setState:NSMixedState]; + [item setAction:@selector(undoConnection:)]; + [[[item submenu] itemAtIndex:0] setAction:@selector(undoConnection:)]; + [[[item submenu] itemAtIndex:0] setTitle:@"Disconnect"]; + [[[item submenu] itemAtIndex:1] setAction:nil]; + [[[item submenu] itemAtIndex:2] setAction:nil]; + [self updateIcon]; + break; + case STATE_UP: + [item setState:NSOnState]; + [self updateIcon]; + break; + } + } +} + +- (NSString*)createPasswordWithConnection:(NSDictionary*)conn +{ + return [password query]; +} + +- (void)raise:(NSString*)alert withConnection:(NSDictionary*)conn +{ + NSAlert *popup; + NSString *text; + + text = [[NSString alloc] + initWithFormat:@"Establishing connection %@ failed:", + [conn objectForKey:@"name"]]; + popup = [[NSAlert alloc] init]; + [popup setMessageText:text]; + [popup setInformativeText:alert]; + [popup runModal]; + [text release]; + [popup release]; +} + +- (void)log:(NSString*)line withConnection:(NSDictionary*)conn +{ + [[self findLog:conn] appendLine:line]; +} + +- (IBAction)undoConnection:(id)sender +{ + NSDictionary *conn; + + conn = [sender representedObject]; + [control disconnect:conn]; +} + +- (IBAction)doConnection:(id)sender +{ + NSDictionary *conn; + + conn = [sender representedObject]; + [[self findLog:conn] clear]; + [control connect:conn]; +} + +- (IBAction)addConnection:(id)sender +{ + NSMutableDictionary *conn; + + conn = [editor createConnection]; + if (conn) + { + [connections insertObject:conn atIndex:[connections count]]; + [self saveConnections]; + } +} + +- (IBAction)editConnection:(id)sender +{ + NSMutableDictionary *conn; + + conn = [sender representedObject]; + if ([editor editConnection:conn]) + { + [self saveConnections]; + } +} + +- (IBAction)removeConnection:(id)sender +{ + NSDictionary *conn; + + conn = [sender representedObject]; + [connections removeObject:conn]; + [self saveConnections]; +} + +- (void)loadConnections +{ + NSUserDefaults *defaults; + NSArray *array; + + defaults = [NSUserDefaults standardUserDefaults]; + array = [defaults arrayForKey:@"connections"]; + if (array) + { + [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[NSDictionary class]]) + { + NSMutableDictionary *dict; + + dict = [obj mutableCopy]; + [connections insertObject:dict atIndex:[connections count]]; + [dict release]; + } + }]; + } + [defaults addObserver:self + forKeyPath:@"connections" + options:NSKeyValueObservingOptionNew + context:NULL]; +} + +- (void)saveConnections +{ + NSUserDefaults *defaults; + + defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:connections forKey:@"connections"]; + [defaults synchronize]; +} + +- (void)viewLog:(id)sender +{ + [[sender representedObject] show]; +} + +- (LogController*)findLog:(NSDictionary *)connection +{ + NSInteger idx; + NSMenuItem *item; + + idx = [statusMenu indexOfItemWithRepresentedObject:connection]; + if (idx != -1) + { + item = [statusMenu itemAtIndex:idx]; + item = [[item submenu] itemAtIndex:3]; + return [item representedObject]; + } + return nil; +} + +- (void)addMenuItem:(NSDictionary *)connection +{ + NSString *name, *title; + NSMenuItem *item; + NSMenu *submenu; + LogController *ctl; + + name = [connection objectForKey:@"name"]; + if (name) { + /* create submenu first */ + submenu = [[NSMenu alloc] initWithTitle:@"submenu"]; + + item = [[NSMenuItem alloc] initWithTitle:@"Connect" + action:@selector(doConnection:) + keyEquivalent:@""]; + [item setTarget:self]; + [item setRepresentedObject:connection]; + [submenu insertItem:item atIndex:0]; + [item release]; + + item = [[NSMenuItem alloc] initWithTitle:@"Edit..." + action:@selector(editConnection:) + keyEquivalent:@""]; + [item setTarget:self]; + [item setRepresentedObject:connection]; + [submenu insertItem:item atIndex:1]; + [item release]; + + item = [[NSMenuItem alloc] initWithTitle:@"Remove" + action:@selector(removeConnection:) + keyEquivalent:@""]; + [item setTarget:self]; + [item setRepresentedObject:connection]; + [submenu insertItem:item atIndex:2]; + [item release]; + + item = [[NSMenuItem alloc] initWithTitle:@"View Log..." + action:@selector(viewLog:) + keyEquivalent:@""]; + [item setTarget:self]; + ctl = [[LogController alloc] initWithWindowNibName:@"LogWindow"]; + title = [NSString stringWithFormat: @"strongSwan Log: %@", name]; + [[ctl window] setTitle:title]; + [item setRepresentedObject:ctl]; + [ctl release]; + [submenu insertItem:item atIndex:3]; + [item release]; + + item = [[NSMenuItem alloc] initWithTitle:name + action:@selector(doConnection:) + keyEquivalent:@""]; + [item setTarget:self]; + [item setRepresentedObject:connection]; + [item setSubmenu:submenu]; + [submenu release]; + [statusMenu insertItem:item atIndex: + [statusMenu numberOfItems] - nonConnectionItemCount]; + [item release]; + } +} + +- (void)repopulateMenu +{ + while ([statusMenu numberOfItems] > nonConnectionItemCount) + { + [statusMenu removeItemAtIndex:0]; + } + [connections enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { + if ([obj isKindOfClass:[NSDictionary class]]) { + [self addMenuItem:obj]; + } + }]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object change:(NSDictionary *)change + context:(void *)context +{ + [self repopulateMenu]; +} + +- (void)updateIcon +{ + NSMenuItem *item; + bool anyactive = FALSE; + int i; + + for (i = 0; i < [statusMenu numberOfItems] - nonConnectionItemCount; i++) + { + item = [statusMenu itemAtIndex:i]; + if ([item state] == NSOnState) + { + anyactive = TRUE; + break; + } + } + [statusItem setImage: anyactive ? active : inactive]; +} + +- (void)initializeMenu +{ + NSImage *icon; + NSString *path; + + statusItem = [[[NSStatusBar systemStatusBar] + statusItemWithLength:NSVariableStatusItemLength] retain]; + [statusItem setMenu:statusMenu]; + [statusItem setHighlightMode:YES]; + + path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"]; + icon = [[NSImage alloc] initWithContentsOfFile:path]; + [statusItem setImage:icon]; + inactive = icon; + + path = [[NSBundle mainBundle] pathForResource:@"icon-active" ofType:@"png"]; + icon = [[NSImage alloc] initWithContentsOfFile:path]; + active = icon; + + path = [[NSBundle mainBundle] pathForResource:@"icon-alt" ofType:@"png"]; + icon = [[NSImage alloc] initWithContentsOfFile:path]; + [statusItem setAlternateImage:icon]; + [icon release]; + + nonConnectionItemCount = [statusMenu numberOfItems]; + + [self repopulateMenu]; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [self loadConnections]; + [self initializeMenu]; +} + +- (id)init +{ + self = [super init]; + control = [[Control alloc] initWithDelegate:self]; + connections = [[NSMutableArray alloc] init]; + editor = [[ConnController alloc] initWithWindowNibName:@"ConnWindow"]; + password = [[PasswordController alloc] initWithWindowNibName:@"PasswordWindow"]; + return self; +} + +- (void)dealloc +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObserver:self forKeyPath:@"connections"]; + [statusItem release]; + [active release]; + [inactive release]; + [connections release]; + [control release]; + [editor release]; + [password release]; + [super dealloc]; +} + +@end diff --git a/src/frontends/osx/strongSwan/ConnController.h b/src/frontends/osx/strongSwan/ConnController.h new file mode 100644 index 000000000..21134fe5a --- /dev/null +++ b/src/frontends/osx/strongSwan/ConnController.h @@ -0,0 +1,74 @@ +/* + * 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 . + * + * 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 + +/** + * Controller for the Connection Editor window + */ +@interface ConnController : NSWindowController { + + /** + * Text field for the connection name + */ + IBOutlet NSTextField *name; + + /** + * Authentication method select control + */ + IBOutlet NSPopUpButton *auth; + + /** + * Server address of connection + */ + IBOutlet NSTextField *server; + + /** + * Username used for client authentication + */ + IBOutlet NSTextField *user; + + /** + * Confirmation button to save/create connection + */ + IBOutlet NSButton *ok; +} + +/** + * Save the currently edited connection + */ +- (IBAction)saveConnEditor:(id)sender; + +/** + * Cancel editing the current connection + */ +- (IBAction)cancelConnEditor:(id)sender; + +/** + * Open a dialog to create a new connection. + * + * @return dictionary with connection settings, retained + */ +- (NSMutableDictionary*)createConnection; + +/** + * Open a dialog to edit a connection + * + * @param conn dictionary with connection settings, gets updated + * @return TRUE if connection has been updated, FALSE if aborted + */ +- (bool)editConnection:(NSMutableDictionary*)conn; + +@end diff --git a/src/frontends/osx/strongSwan/ConnController.m b/src/frontends/osx/strongSwan/ConnController.m new file mode 100644 index 000000000..cd7b9f1dc --- /dev/null +++ b/src/frontends/osx/strongSwan/ConnController.m @@ -0,0 +1,102 @@ +/* + * 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 . + * + * 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 "ConnController.h" + +@interface ConnController () + +@end + +@implementation ConnController + +- (void)moveWindowToActiveSpace +{ + NSInteger behavior, old; + + /* seems that NSWindowCollectionBehaviorMoveToActiveSpace does not work + * when a window is opened a second time. Fix that by changing the + * behavior forth and back. */ + old = behavior = [[self window] collectionBehavior]; + behavior &= ~NSWindowCollectionBehaviorMoveToActiveSpace; + behavior |= NSWindowCollectionBehaviorCanJoinAllSpaces; + + [[self window] setCollectionBehavior: behavior]; + [[self window] setCollectionBehavior: old]; + + [NSApp activateIgnoringOtherApps:YES]; +} + +- (IBAction)saveConnEditor:(id)sender +{ + [NSApp stopModal]; +} + +- (IBAction)cancelConnEditor:(id)sender +{ + [NSApp abortModal]; +} + +- (NSMutableDictionary*)createConnection +{ + NSMutableDictionary *conn = nil; + + [[self window] setTitle:@"Add new connection"]; + [name setStringValue:@""]; + [server setStringValue:@""]; + [user setStringValue:@""]; + [ok setEnabled:FALSE]; + [self moveWindowToActiveSpace]; + if ([NSApp runModalForWindow: [self window]] == NSRunStoppedResponse) + { + conn = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [name stringValue], @"name", + [server stringValue], @"server", + [user stringValue], @"username", + nil]; + } + [[self window] orderOut: self]; + return conn; +} + +- (bool)editConnection:(NSMutableDictionary*)conn +{ + bool edited = NO; + + [[self window] setTitle:@"Edit connection"]; + [name setStringValue:[conn objectForKey:@"name"]]; + [server setStringValue:[conn objectForKey:@"server"]]; + [user setStringValue:[conn objectForKey:@"username"]]; + [ok setEnabled:TRUE]; + [self moveWindowToActiveSpace]; + if ([NSApp runModalForWindow: [self window]] == NSRunStoppedResponse) + { + [conn setObject:[name stringValue] forKey:@"name"]; + [conn setObject:[server stringValue] forKey:@"server"]; + [conn setObject:[user stringValue] forKey:@"username"]; + edited = YES; + } + [[self window] orderOut: self]; + return edited; +} + +- (void)controlTextDidChange:(NSNotification *)notification +{ + [ok setEnabled: + [[name stringValue] length] && + [[server stringValue] length] && + [[user stringValue] length]]; +} + +@end diff --git a/src/frontends/osx/strongSwan/Control.h b/src/frontends/osx/strongSwan/Control.h new file mode 100644 index 000000000..4bcfb5583 --- /dev/null +++ b/src/frontends/osx/strongSwan/Control.h @@ -0,0 +1,95 @@ +/* + * 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 . + * + * 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 + +/** + * State of a connection during connect. + */ +typedef enum { + /** The connection is currently down */ + STATE_DOWN, + /** The connection is getting established, the daemon is working */ + STATE_WORKING, + /** The connection has been established successfully */ + STATE_UP, +} connectionState; + +/** + * This protocol defines callback functions to invoke during connect. + */ +@protocol ControlDelegate + +/** + * The connection has changed its state + * + * @param state new connection state + * @param conn connection that changed its state + */ +- (void)change:(connectionState)state withConnection:(NSDictionary*)conn; + +/** + * A password is required for authentication + * + * @param conn connection a password is required for + * @return a retained password string + */ +- (NSString*)createPasswordWithConnection:(NSDictionary*)conn; + +/** + * Show an alert message to the user + * + * @param alert alert message string + * @param conn connection an error has occurred + */ +- (void)raise:(NSString*)alert withConnection:(NSDictionary*)conn; + +/** + * Log a line for a specific connection + * + * @param line log line string + * @param conn connection the line is logged for + */ +- (void)log:(NSString*)line withConnection:(NSDictionary*)conn; +@end + +/** + * Implements connection connect/disconnect operations using a GUI delegate. + */ +@interface Control : NSObject + +/** + * Try to establish a connection + * + * @param conn connection configuration to initiate + */ +- (void)connect:(NSDictionary*)conn; + +/** + * Disconnect a previously established connection + * + * @param conn connection configuration to terminate + */ +- (void)disconnect:(NSDictionary*)conn; + +/** + * Initiate the Control class using a delegate for GUI operations + * + * @param delegate delegate to invoke callbacks on during connect operation + * @return class instance + */ +- (id)initWithDelegate:(id)delegate; + +@end 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 . + * + * 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 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)delegate; +{ + self = [super init]; + helper = [[Helper alloc] init]; + active = xpc_dictionary_create(NULL, NULL, 0); + del = delegate; + return self; +} + +@end diff --git a/src/frontends/osx/strongSwan/Helper.h b/src/frontends/osx/strongSwan/Helper.h new file mode 100644 index 000000000..0fa7da8bd --- /dev/null +++ b/src/frontends/osx/strongSwan/Helper.h @@ -0,0 +1,41 @@ +/* + * 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 . + * + * 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 + +/** + * Privileged Helper abstraction. + * + * Manages the installation of the privileged helper charon-xpc binary + * using authorization, SMJobBless() installation using XPC and also + * checks the installed helper version. + */ +@interface Helper : NSObject + +/** + * Get the XPC connection singleton, installing helper if requried + * + * @return XPC service connection, as a singleton + */ +- (xpc_connection_t)getConnection; + +/** + * Return an errror string if if getConnection fails + * + * @return error string, unretained + */ +- (NSString*)getError; + +@end \ No newline at end of file diff --git a/src/frontends/osx/strongSwan/Helper.m b/src/frontends/osx/strongSwan/Helper.m new file mode 100644 index 000000000..df4b4c248 --- /dev/null +++ b/src/frontends/osx/strongSwan/Helper.m @@ -0,0 +1,223 @@ +/* + * 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 . + * + * 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 "Helper.h" + +#include +#include + +/* to check strongSwan version */ +#include "../../../../config.h" + +@implementation Helper { + /* XPC connection to the helper */ + xpc_connection_t helper; + /* authorization instance, if authorized */ + AuthorizationRef auth; + /* string of last error occurred */ + NSString* errmsg; +} + +- (void)setError:(NSString*)error +{ + if (errmsg) + { + [errmsg release]; + } + errmsg = error; +} + +- (bool)authorize +{ + AuthorizationItem item = { kSMRightBlessPrivilegedHelper, 0, NULL, 0 }; + AuthorizationRights rights = { 1, &item }; + OSStatus status; + + if (auth) + { + return TRUE; + } + status = AuthorizationCreate(&rights, kAuthorizationEmptyEnvironment, + kAuthorizationFlagDefaults | + kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagExtendRights, &auth); + if (status == errAuthorizationSuccess) + { + return TRUE; + } + if (errmsg) + { + [errmsg release]; + } + [self setError:[NSString stringWithFormat:@"Authorization failed: %@", + SecCopyErrorMessageString(status, NULL)]]; + return FALSE; +} + +- (bool)manage:(CFStringRef)label bless:(bool)bless +{ + bool done; + CFErrorRef error; + + if (![self authorize]) + { + return FALSE; + } + if (bless) + { + done = SMJobBless(kSMDomainSystemLaunchd, label, auth, &error); + } + else + { + done = SMJobRemove(kSMDomainSystemLaunchd, label, auth, TRUE, &error); + } + if (!done) + { + [self setError: + [NSString stringWithFormat:@"Installing privileged helper failed: %@", + CFErrorCopyDescription(error)]]; + CFRelease(error); + } + return done; +} + +- (bool)make:(CFStringRef)label +{ + char str[128]; + + if (!CFStringGetCString(label, str, sizeof(str), kCFStringEncodingUTF8)) + { + [self setError:@"converting XPC service name failed"]; + return FALSE; + } + helper = xpc_connection_create_mach_service(str, NULL, + XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); + if (!helper) + { + [self setError:@"creating XPC mach service failed"]; + return FALSE; + } + + xpc_connection_set_event_handler(helper, ^(xpc_object_t event) { + if (xpc_get_type(event) == XPC_TYPE_ERROR) + { + if (event == XPC_ERROR_CONNECTION_INTERRUPTED || + event == XPC_ERROR_CONNECTION_INVALID) + { + if (helper) + { + xpc_connection_cancel(helper); + helper = NULL; + } + } + } + }); + xpc_connection_resume(helper); + + return TRUE; +} + +- (bool)checkVersion +{ + xpc_object_t request, response; + bool match = FALSE; + + request = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(request, "type", "rpc"); + xpc_dictionary_set_string(request, "rpc", "get_version"); + + response = xpc_connection_send_message_with_reply_sync(helper, request); + xpc_release(request); + if (xpc_get_type(response) == XPC_TYPE_DICTIONARY) + { + match = strcmp(xpc_dictionary_get_string(response, "version"), + PACKAGE_VERSION) == 0; + } + xpc_release(response); + return match; +} + +- (bool)makeAndCheck:(CFStringRef)label +{ + if (![self make:label]) + { + return FALSE; + } + if ([self checkVersion]) + { + return TRUE; + } + xpc_connection_cancel(helper); + helper = NULL; + /* version outdated, uninstall old helper */ + [self manage:label bless:FALSE]; + return FALSE; +} + +- (bool)blessAndMake:(CFStringRef)label +{ +#ifdef DEBUG + /* always update helper when debugging */ + [self manage:label bless:FALSE]; + [self manage:label bless:TRUE]; +#endif + + if (![self makeAndCheck:label]) + { + if ([self manage:label bless:TRUE]) + { + [self makeAndCheck:label]; + } + } + return helper; +} + +- (xpc_connection_t)getConnection +{ + if (!helper) + { + [self blessAndMake:CFSTR("org.strongswan.charon-xpc")]; + } + return helper; +} + +- (NSString*)getError +{ + return errmsg; +} + +- (id)init +{ + self = [super init]; + return self; +} + +- (void)dealloc +{ + if (helper) + { + xpc_connection_cancel(helper); + } + if (auth) + { + AuthorizationFree(auth, kAuthorizationFlagDefaults); + } + if (errmsg) + { + [errmsg release]; + } + [super dealloc]; +} +@end diff --git a/src/frontends/osx/strongSwan/LogController.h b/src/frontends/osx/strongSwan/LogController.h new file mode 100644 index 000000000..239dd5b05 --- /dev/null +++ b/src/frontends/osx/strongSwan/LogController.h @@ -0,0 +1,45 @@ +/* + * 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 . + * + * 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 + +/** + * Controller for a connection specific log Window + */ +@interface LogController : NSWindowController { + /** + * Text field for the log entries + */ + IBOutlet NSTextView *textView; +} + +/** + * Show the log window on the active Desktop + */ +- (void)show; + +/** + * Append a new log line to the log + * + * @param line log line to append + */ +- (void)appendLine:(NSString*)line; + +/** + * Clear the log window + */ +- (void)clear; + +@end diff --git a/src/frontends/osx/strongSwan/LogController.m b/src/frontends/osx/strongSwan/LogController.m new file mode 100644 index 000000000..56be8c893 --- /dev/null +++ b/src/frontends/osx/strongSwan/LogController.m @@ -0,0 +1,51 @@ +/* + * 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 . + * + * 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 "LogController.h" + +@interface LogController () + +@end + +@implementation LogController + +- (void)appendLine:(NSString*)line +{ + NSAttributedString* attr; + + attr = [[NSAttributedString alloc] initWithString:line]; + [[textView textStorage] appendAttributedString:attr]; + [attr release]; + + attr = [[NSAttributedString alloc] initWithString:@"\n"]; + [[textView textStorage] appendAttributedString:attr]; + [attr release]; + + [textView scrollRangeToVisible:NSMakeRange([[textView string] length], 0)]; +} + +- (void)clear +{ + [textView setString:@""]; +} + +- (void)show +{ + [self showWindow:self]; + [[self window] makeKeyAndOrderFront:self]; + [[self window] orderFrontRegardless]; +} + +@end diff --git a/src/frontends/osx/strongSwan/PasswordController.h b/src/frontends/osx/strongSwan/PasswordController.h new file mode 100644 index 000000000..eeaed0d35 --- /dev/null +++ b/src/frontends/osx/strongSwan/PasswordController.h @@ -0,0 +1,41 @@ +/* + * 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 . + * + * 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 + +/** + * Controller for the EAP password dialog. + */ +@interface PasswordController : NSWindowController { + + /** + * Text field the user enters the password + */ + IBOutlet NSTextField *password; +} + +/** + * Action invoked when the user confirms the password entry + */ +- (IBAction)confirm: (id)sender; + +/** + * Query the user for a password by invoking the modal dialog. + * + * @return password string, retained + */ +- (NSString*)query; + +@end diff --git a/src/frontends/osx/strongSwan/PasswordController.m b/src/frontends/osx/strongSwan/PasswordController.m new file mode 100644 index 000000000..2e0ce556a --- /dev/null +++ b/src/frontends/osx/strongSwan/PasswordController.m @@ -0,0 +1,56 @@ +/* + * 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 . + * + * 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 "PasswordController.h" + +@interface PasswordController () + +@end + +@implementation PasswordController + +- (void)moveWindowToActiveSpace +{ + NSInteger behavior, old; + + /* seems that NSWindowCollectionBehaviorMoveToActiveSpace does not work + * when a window is opened a second time. Fix that by changing the + * behavior forth and back. */ + old = behavior = [[self window] collectionBehavior]; + behavior &= ~NSWindowCollectionBehaviorMoveToActiveSpace; + behavior |= NSWindowCollectionBehaviorCanJoinAllSpaces; + + [[self window] setCollectionBehavior: behavior]; + [[self window] setCollectionBehavior: old]; + + [NSApp activateIgnoringOtherApps:YES]; +} + +- (IBAction)confirm:(id)sender +{ + [NSApp stopModal]; +} + +- (NSString *)query +{ + [password setStringValue:@""]; + [self moveWindowToActiveSpace]; + [NSApp runModalForWindow: [self window]]; + [[self window] orderOut: self]; + + return [[password stringValue] retain]; +} + +@end diff --git a/src/frontends/osx/strongSwan/en.lproj/ConnWindow.xib b/src/frontends/osx/strongSwan/en.lproj/ConnWindow.xib new file mode 100644 index 000000000..37c74b4aa --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/ConnWindow.xib @@ -0,0 +1,1469 @@ + + + + 1080 + 12D78 + 2840 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2840 + + + IBNSLayoutConstraint + NSButton + NSButtonCell + NSCustomObject + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + ConnController + + + FirstResponder + + + NSApplication + + + 1 + 2 + {{121, 123}, {319, 191}} + 611845120 + Window + NSWindow + + + + + 256 + + + + 268 + {{223, 13}, {82, 32}} + + + _NS:9 + YES + + 67108864 + 134217728 + OK + + LucidaGrande + 13 + 1044 + + _NS:9 + + -2038284288 + 129 + + DQ + 200 + 25 + + NO + + + + 268 + {{141, 13}, {82, 32}} + + + + _NS:9 + YES + + 67108864 + 134217728 + Cancel + + _NS:9 + + -2038284288 + 129 + + Gw + 200 + 25 + + NO + + + + 268 + {{20, 154}, {162, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Connection name: + + _NS:1535 + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + NO + + + + 268 + {{147, 151}, {152, 22}} + + + + _NS:9 + YES + + -1804599231 + 272630784 + + + _NS:9 + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + textColor + + + + NO + + + + 268 + {{20, 124}, {162, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Authentication: + + _NS:1535 + + + + + NO + + + + 268 + {{145, 118}, {157, 26}} + + + + _NS:9 + YES + + -2076180416 + 2048 + + _NS:9 + + 109199360 + 129 + + + 400 + 75 + + + IKEv2 EAP + + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + OtherViews + + + + + + 1 + YES + YES + 2 + + NO + + + + 268 + {{20, 94}, {162, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Server address: + + _NS:1535 + + + + + NO + + + + 268 + {{147, 91}, {152, 22}} + + + + _NS:9 + YES + + -1804599231 + 272630784 + + + _NS:9 + + YES + + + + NO + + + + 268 + {{20, 64}, {162, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Username: + + _NS:1535 + + + + + NO + + + + 268 + {{147, 61}, {152, 22}} + + + + _NS:9 + YES + + -1804599231 + 272630784 + + + _NS:9 + + YES + + + + NO + + + {319, 191} + + + + _NS:20 + + {{0, 0}, {1366, 746}} + {10000000000000, 10000000000000} + 3 + 2 + YES + + + + + + + auth + + + + 58 + + + + name + + + + 60 + + + + ok + + + + 61 + + + + server + + + + 62 + + + + user + + + + 63 + + + + window + + + + 64 + + + + saveConnEditor: + + + + 65 + + + + cancelConnEditor: + + + + 66 + + + + delegate + + + + 69 + + + + delegate + + + + 68 + + + + delegate + + + + 67 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 5 + + + + + + connEditor + + + 6 + + + + + + + + + + + + + + + 3 + 0 + + 3 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 23 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 3 + 0 + + 3 + 1 + + 49 + + 1000 + + 3 + 9 + 3 + + + + 11 + 0 + + 11 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 3 + 0 + + 3 + 1 + + 78 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 3 + 0 + + 3 + 1 + + 108 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 6 + 1 + + 12 + + 1000 + + 6 + 24 + 3 + + + + + + 7 + + + + + 7 + 0 + + 0 + 1 + + 70 + + 1000 + + 3 + 9 + 1 + + + + + okButton + + + 8 + + + + + + cancelButton + + + 9 + + + + + + typePopup + + + 10 + + + + + + userText + + + 11 + + + + + + userLabel + + + 12 + + + + + + serverText + + + 13 + + + + + + serverLabel + + + 14 + + + + + + typeLabel + + + 15 + + + + + + nameText + + + 16 + + + + + 7 + 0 + + 0 + 1 + + 156 + + 1000 + + 3 + 9 + 1 + + + + + nameLabel + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + 31 + + + + + 32 + + + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + + + 38 + + + + + 39 + + + + + 40 + + + + + 41 + + + + + 42 + + + + + 43 + + + + + 44 + + + + + 45 + + + + + 46 + + + + + 47 + + + + + 48 + + + + + 49 + + + + + 50 + + + + + 51 + + + + + 52 + + + + + + + + 53 + + + + + + + + 54 + + + + + 55 + + + + + 56 + + + + + 57 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 69 + + + + + ConnController + NSWindowController + + id + id + + + + cancelConnEditor: + id + + + saveConnEditor: + id + + + + NSPopUpButton + NSTextField + NSButton + NSTextField + NSTextField + + + + auth + NSPopUpButton + + + name + NSTextField + + + ok + NSButton + + + server + NSTextField + + + user + NSTextField + + + + IBProjectSource + ./Classes/ConnController.h + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + + YES + + diff --git a/src/frontends/osx/strongSwan/en.lproj/Credits.rtf b/src/frontends/osx/strongSwan/en.lproj/Credits.rtf new file mode 100644 index 000000000..5684d78b9 --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/Credits.rtf @@ -0,0 +1,32 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1265 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red0\green0\blue255;} +\paperw11900\paperh16840\viewkind1\viewscale96 +\deftab720 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720\ri0 + +\f0\fs24 \cf0 Based on the strongSwan Open Source project:\ +\ + {\field{\*\fldinst{HYPERLINK "http://www.strongswan.org"}}{\fldrslt \cf2 \ul \ulc2 http://www.strongswan.org}}\ +\ +The App and the +\i charon-xpc +\i0 privileged helper tool are licensed under the {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt"}}{\fldrslt \cf2 \ul \ulc2 General Public License Version 2}}. The strongSwan source code is available for download at:\ +\ + {\field{\*\fldinst{HYPERLINK "http://download.strongswan.org/"}}{\fldrslt \cf2 \ul \ulc2 http://download.strongswan.org/}}\ +\ +The App and the +\i charon-xpc +\i0 helper sources are not part of the main strongSwan distribution, but available separately under:\ +\ + {\field{\*\fldinst{HYPERLINK "http://download.strongswan.org/osx/"}}{\fldrslt \cf2 \ul \ulc2 http://download.strongswan.org/osx/}}\ +\ +The +\i osx-sources +\i0 tarball should get extracted into the strongSwan sources root directory. The +\i README.md +\i0 in +\i src/frontends/osx +\i0 has more information about building +\i charon-xpc +\i0 and the App.} \ No newline at end of file diff --git a/src/frontends/osx/strongSwan/en.lproj/InfoPlist.strings b/src/frontends/osx/strongSwan/en.lproj/InfoPlist.strings new file mode 100644 index 000000000..b92732c79 --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/InfoPlist.strings @@ -0,0 +1 @@ +/* Localized versions of Info.plist keys */ diff --git a/src/frontends/osx/strongSwan/en.lproj/LogWindow.xib b/src/frontends/osx/strongSwan/en.lproj/LogWindow.xib new file mode 100644 index 000000000..4c326185d --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/LogWindow.xib @@ -0,0 +1,587 @@ + + + + 1080 + 12D78 + 2840 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2840 + + + IBNSLayoutConstraint + NSCustomObject + NSScrollView + NSScroller + NSTextView + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + LogController + + + FirstResponder + + + NSApplication + + + 15 + 2 + {{121, 123}, {547, 312}} + 611845120 + Window + NSWindow + + + + + 256 + + + + 256 + + + + 2304 + + + + 2322 + {525, 286} + + + + _NS:13 + + + + + + + + + + + + 166 + + + + 525 + 1 + + + 10593 + 0 + + + 3 + MQA + + + + 6 + System + selectedTextBackgroundColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + selectedTextColor + + 3 + MAA + + + + + + + 1 + MCAwIDEAA + + + {8, -8} + 13 + + + + + 4 + + 1 + + + 1 + + 6 + {548, 10000000} + + + + {{1, 1}, {525, 286}} + + + + _NS:11 + + + + {4, 5} + + 12582912 + + + + + + TU0AKgAAEAj///8A////qwAAAP8AAAD/AwMD/BYWFtIFBQVuAAAABv///wD///8E6+vrTGhoaLYtLS3p +BAQE/QAAAP8AAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///+rAAAA/wAAAP8AAAD/AAAA/wAAAP8EBATSX19fK9HR0ZciIiLv +AAAA/wAAAP8AAAD/AAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////CsPDw0CRkZG1FxcX9AAAAP8bGxvr +ICAg8AAAAP8ICAjlFRUVVQAAAA////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wrm5uab +FxcX9AAAAP8AAAD/AQEB3wAAAA////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///zaXl5fGAAAA/wAAAP8AAABR////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////CO7u7q8AAAD/AAAA/wAAAAz///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///+rAAAA/wAAAP////8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6sAAAD/AAAA/////wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/ +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+r +AAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///6sAAAD/AAAA/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////qwAAAP8AAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///+rAAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///6sAAAD/AAAA/////wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/AAAA/wAAAP8AAAD/ +AAAA/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+rAAAA/wAAAP8AAAD/ +AAAA/wAAAP8AAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////qwAAAP8AAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///+rAAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///6sAAAD/AAAA/////wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///+rAAAA/wAAAP////8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6sAAAD/AAAA/////wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qwAAAP8AAAD/ +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+r +AAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////CO7u7q8AAAD/AAAA/wAAAAz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///80mpqaxQAAAP8AAAD/AAAATv///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////CuXl5ZYeHh7xAAAA/wAAAP8CAgLXAAAAD////wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////EKurq0mOjo63FxcX9AAAAP8bGxvrICAg8AAAAP8ICAjlHh4eXAAAABj///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////qwAAAP8AAAD/AAAA/wAAAP8AAAD/BAQE1V9fXyvS0tKZICAg8AAAAP8AAAD/ +AAAA/wAAAP8AAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///+rAAAA/wAAAP8AAAD/FBQU1AUFBXEAAAAG////AP///wTr6+tO +ZWVluC4uLuoAAAD/AAAA/wAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8AABABAAADAAAAAQAgAAABAQADAAAAAQAgAAABAgADAAAABAAA +EM4BAwADAAAAAQABAAABBgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAE +AAABFgADAAAAAQAgAAABFwAEAAAAAQAAEAABGgAFAAAAAQAAENYBGwAFAAAAAQAAEN4BHAADAAAAAQAB +AAABKAADAAAAAQACAAABUgADAAAAAQACAAABUwADAAAABAAAEOYAAAAAAAgACAAIAAgSAAAAACAAABIA +AAAAIAAAAAEAAQABAAE + + + + + + + + TU0AKgAABAj///9VQ0ND/wAAAP////8A////AP///6pDQ0P/AAAA/////wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///+qAAAA/////6oAAAD/////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///6oAAAD/////AP///wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///+qAAAA/////wD///8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////qgAAAP////8A////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6oAAAD/////AP///wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+qAAAA/////wD///8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qgAAAP////8A +////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qgAAAP8AAAD/ +AAAA/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+q +AAAA/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////qgAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///6oAAAD/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///+qAAAA/////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////qgAAAP////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///8A////qgAAAP////+qAAAA/////wD///8A////AP///wD///8A////AP///wD///8A +////AP///wD///9VQ0ND/wAAAP////8A////AP///6pDQ0P/AAAA/////wD///8A////AP///wD///8A +////AP///wD///8AAA4BAAADAAAAAQAQAAABAQADAAAAAQAQAAABAgADAAAABAAABLYBAwADAAAAAQAB +AAABBgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAEAAABFgADAAAAAQAQ +AAABFwAEAAAAAQAABAABHAADAAAAAQABAAABUgADAAAAAQACAAABUwADAAAABAAABL6HcwAHAAAHqAAA +BMYAAAAAAAgACAAIAAgAAQABAAEAAQAAB6hhcHBsAiAAAG1udHJSR0IgWFlaIAfZAAIAGQALABoAC2Fj +c3BBUFBMAAAAAGFwcGwAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2Rlc2MAAAEIAAAAb2RzY20AAAF4AAAFbGNw +cnQAAAbkAAAAOHd0cHQAAAccAAAAFHJYWVoAAAcwAAAAFGdYWVoAAAdEAAAAFGJYWVoAAAdYAAAAFHJU +UkMAAAdsAAAADmNoYWQAAAd8AAAALGJUUkMAAAdsAAAADmdUUkMAAAdsAAAADmRlc2MAAAAAAAAAFEdl +bmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAABRHZW5lcmljIFJHQiBQcm9maWxlAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAB4AAAAMc2tTSwAA +ACgAAAF4aHJIUgAAACgAAAGgY2FFUwAAACQAAAHIcHRCUgAAACYAAAHsdWtVQQAAACoAAAISZnJGVQAA +ACgAAAI8emhUVwAAABYAAAJkaXRJVAAAACgAAAJ6bmJOTwAAACYAAAKia29LUgAAABYAAALIY3NDWgAA +ACIAAALeaGVJTAAAAB4AAAMAZGVERQAAACwAAAMeaHVIVQAAACgAAANKc3ZTRQAAACYAAAKiemhDTgAA +ABYAAANyamFKUAAAABoAAAOIcm9STwAAACQAAAOiZWxHUgAAACIAAAPGcHRQTwAAACYAAAPobmxOTAAA +ACgAAAQOZXNFUwAAACYAAAPodGhUSAAAACQAAAQ2dHJUUgAAACIAAARaZmlGSQAAACgAAAR8cGxQTAAA +ACwAAASkcnVSVQAAACIAAATQYXJFRwAAACYAAATyZW5VUwAAACYAAAUYZGFESwAAAC4AAAU+AFYBYQBl +AG8AYgBlAGMAbgD9ACAAUgBHAEIAIABwAHIAbwBmAGkAbABHAGUAbgBlAHIAaQENAGsAaQAgAFIARwBC +ACAAcAByAG8AZgBpAGwAUABlAHIAZgBpAGwAIABSAEcAQgAgAGcAZQBuAOgAcgBpAGMAUABlAHIAZgBp +AGwAIABSAEcAQgAgAEcAZQBuAOkAcgBpAGMAbwQXBDAEMwQwBDsETAQ9BDgEOQAgBD8EQAQ+BEQEMAQ5 +BDsAIABSAEcAQgBQAHIAbwBmAGkAbAAgAGcA6QBuAOkAcgBpAHEAdQBlACAAUgBWAEKQGnUoACAAUgBH +AEIAIIJyX2ljz4/wAFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAGcAZQBuAGUAcgBpAGMAbwBHAGUAbgBl +AHIAaQBzAGsAIABSAEcAQgAtAHAAcgBvAGYAaQBsx3y8GAAgAFIARwBCACDVBLhc0wzHfABPAGIAZQBj +AG4A/QAgAFIARwBCACAAcAByAG8AZgBpAGwF5AXoBdUF5AXZBdwAIABSAEcAQgAgBdsF3AXcBdkAQQBs +AGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbADBAGwAdABhAGwA4QBuAG8AcwAg +AFIARwBCACAAcAByAG8AZgBpAGxmbpAaACAAUgBHAEIAIGPPj/Blh072TgCCLAAgAFIARwBCACAw1zDt +MNUwoTCkMOsAUAByAG8AZgBpAGwAIABSAEcAQgAgAGcAZQBuAGUAcgBpAGMDkwO1A70DuQO6A8wAIAPA +A8EDvwPGA68DuwAgAFIARwBCAFAAZQByAGYAaQBsACAAUgBHAEIAIABnAGUAbgDpAHIAaQBjAG8AQQBs +AGcAZQBtAGUAZQBuACAAUgBHAEIALQBwAHIAbwBmAGkAZQBsDkIOGw4jDkQOHw4lDkwAIABSAEcAQgAg +DhcOMQ5IDicORA4bAEcAZQBuAGUAbAAgAFIARwBCACAAUAByAG8AZgBpAGwAaQBZAGwAZQBpAG4AZQBu +ACAAUgBHAEIALQBwAHIAbwBmAGkAaQBsAGkAVQBuAGkAdwBlAHIAcwBhAGwAbgB5ACAAcAByAG8AZgBp +AGwAIABSAEcAQgQeBDEESQQ4BDkAIAQ/BEAEPgREBDgEOwRMACAAUgBHAEIGRQZEBkEAIAYqBjkGMQZK +BkEAIABSAEcAQgAgBicGRAY5BicGRQBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABl +AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZXRleHQAAAAAQ29weXJp +Z2h0IDIwMDcgQXBwbGUgSW5jLiwgYWxsIHJpZ2h0cyByZXNlcnZlZC4AWFlaIAAAAAAAAPNSAAEAAAAB +Fs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAACgaAAAVnwAA +uDZjdXJ2AAAAAAAAAAEBzQAAc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeSAAD9kf//+6L///2jAAAD3AAA +wGw + + + + + + 3 + MCAwAA + + + + 4 + + + + 256 + {{510, 1}, {16, 286}} + + + _NS:83 + NO + + _doScroller: + 1 + 0.85256409645080566 + + + + 256 + {{1, 271}, {525, 16}} + + + + _NS:33 + NO + 1 + + _doScroller: + 1 + 0.94565218687057495 + + + {{10, 10}, {527, 288}} + + + + _NS:9 + 133170 + + + + 0.25 + 4 + 1 + + + {547, 312} + + + + _NS:20 + + {{0, 0}, {1366, 746}} + {10000000000000, 10000000000000} + YES + + + + + + + textView + + + + 15 + + + + window + + + + 16 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 5 + + + + + + logWindow + + + 6 + + + + + + 9 + 0 + + 9 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 3 + 0 + + 3 + 1 + + 14 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 10 + + 1000 + + 9 + 40 + 3 + + + + + + 7 + + + + + + + + logView + + + 12 + + + + + 13 + + + + + 14 + + + + + 45 + + + + + 47 + + + + + 48 + + + + + 49 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 49 + + + + + LogController + NSWindowController + + textView + NSTextView + + + textView + + textView + NSTextView + + + + IBProjectSource + ./Classes/LogController.h + + + + + 0 + IBCocoaFramework + YES + 3 + YES + + diff --git a/src/frontends/osx/strongSwan/en.lproj/MainMenu.xib b/src/frontends/osx/strongSwan/en.lproj/MainMenu.xib new file mode 100644 index 000000000..c7cce11e6 --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/MainMenu.xib @@ -0,0 +1,277 @@ + + + + 1080 + 12D78 + 2840 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2840 + + + NSCustomObject + NSMenu + NSMenuItem + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + + + + + YES + YES + + + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + + + + Add connection... + + 2147483647 + + + + + + About + + 2147483647 + + + + + + Quit + + 2147483647 + + + + + + + AppDelegate + + + NSFontManager + + + + + + + terminate: + + + + 559 + + + + orderFrontStandardAboutPanel: + + + + 560 + + + + delegate + + + + 495 + + + + statusMenu + + + + 550 + + + + addConnection: + + + + 561 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 420 + + + + + 494 + + + + + 536 + + + + + + + + + statusMenu + + + 538 + + + quitItem + + + 547 + + + aboutItem + + + 557 + + + connSeparator + + + 558 + + + addItem + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 780 + + + + + AppDelegate + NSObject + + id + id + + + + addConnection: + id + + + confirmPassword: + id + + + + NSTextField + NSWindow + NSMenu + + + + password + NSTextField + + + passwordDialog + NSWindow + + + statusMenu + NSMenu + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + + YES + + diff --git a/src/frontends/osx/strongSwan/en.lproj/PasswordWindow.xib b/src/frontends/osx/strongSwan/en.lproj/PasswordWindow.xib new file mode 100644 index 000000000..1f4434348 --- /dev/null +++ b/src/frontends/osx/strongSwan/en.lproj/PasswordWindow.xib @@ -0,0 +1,578 @@ + + + + 1070 + 14B25 + 6254 + 1343.16 + 755.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 6254 + + + IBNSLayoutConstraint + NSButton + NSButtonCell + NSCustomObject + NSSecureTextField + NSSecureTextFieldCell + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + PasswordController + + + FirstResponder + + + NSApplication + + + 1 + 2 + {{121, 123}, {246, 91}} + 611845120 + Password required + NSWindow + + + + + 256 + + + + 268 + {{98, 51}, {128, 22}} + + + + _NS:9 + YES + + 342884416 + 272630848 + + + YES + 13 + 1044 + + _NS:9 + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + textColor + + 3 + MAA + + + + NSAllRomanInputSourcesLocaleIdentifier + + + NO + 1 + + + + 268 + {{21, 54}, {69, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Password: + + _NS:1535 + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + NO + 1 + + + + 268 + {{144, 13}, {88, 32}} + + + _NS:9 + YES + + 67108864 + 134217728 + OK + + _NS:9 + + -2038284288 + 129 + + DQ + 200 + 25 + + NO + + + {246, 91} + + + + _NS:20 + + {{0, 0}, {1366, 745}} + {10000000000000, 10000000000000} + 2 + YES + + + + + + + password + + + + 21 + + + + window + + + + 22 + + + + confirm: + + + + 23 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 5 + + + + + + passwordDialog + + + 6 + + + + + + + + 5 + 0 + + 5 + 1 + 1 + + 23 + + 1000 + + 3 + 9 + 3 + NO + + + + 3 + 0 + + 3 + 1 + 1 + + 20 + + 1000 + + 0 + 29 + 3 + NO + + + + 10 + 0 + + 10 + 1 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + NO + + + + 6 + 0 + + 6 + 1 + 1 + + 20 + + 1000 + + 0 + 29 + 3 + NO + + + + 6 + 0 + + 6 + 1 + 1 + + 20 + + 1000 + + 0 + 29 + 3 + NO + + + + 4 + 0 + + 4 + 1 + 1 + + 20 + + 1000 + + 0 + 29 + 3 + NO + + + + + + 7 + + + + + 7 + 0 + + 0 + 1 + 1 + + 76 + + 1000 + + 3 + 9 + 1 + NO + + + + + + + 8 + + + + + 7 + 0 + + 0 + 1 + 1 + + 128 + + 1000 + + 3 + 9 + 1 + NO + + + + + + + 9 + + + + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 23 + + + + + PasswordController + NSWindowController + + confirm: + id + + + confirm: + + confirm: + id + + + + password + NSTextField + + + password + + password + NSTextField + + + + IBProjectSource + ../strongSwan/PasswordController.h + + + + PasswordController + + confirm: + id + + + confirm: + + confirm: + id + + + + IBProjectSource + ../strongSwan/PasswordController.m + + + + + 0 + IBCocoaFramework + NO + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + YES + + diff --git a/src/frontends/osx/strongSwan/icon-active.png b/src/frontends/osx/strongSwan/icon-active.png new file mode 100644 index 0000000000000000000000000000000000000000..e470b083ba9d618df06f0deeb4ff2a7287b6a778 GIT binary patch literal 401 zcmV;C0dD?@P)X`!u%l?WDE zXrTx}6d_>5SI*`F;n>?;#DQVi*_r>&%nr*xOR0d*ILdg(!(V}8s9+YuZNPgRW2>92 zE2!fKNkBjGh~*-%CA{T;vigjPETAW|U&Ua-O1{vWHMSduFj@eVr0WZ=W5Cz6jG_-Y ziCt9Dhk1Nwo!8Ll(7PWr^UgzKvz@+lp4{OG1L#j}4b*U&7qk({u#U}GPZo3RD-mcD z`=OvRZgGRF%-LlcxDXhx5~lGHDzkO#9;O199!4^)VI~il;35E=!&3yh69Xpc2auI& vhfx}d0TY}Dpl1=_dM99lgD!e`(sKF*J3@^t&IZwz00000NkvXXu0mjfaa^HG literal 0 HcmV?d00001 diff --git a/src/frontends/osx/strongSwan/icon-alt.png b/src/frontends/osx/strongSwan/icon-alt.png new file mode 100644 index 0000000000000000000000000000000000000000..997652a162ff555ebbd9b4a7418bad858b22281c GIT binary patch literal 413 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 literal 0 HcmV?d00001 diff --git a/src/frontends/osx/strongSwan/icon.png b/src/frontends/osx/strongSwan/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..07be18ecf74277f1a31b3c1a6093c8421a1a4448 GIT binary patch literal 467 zcmV;^0WAKBP)<^U#4?^%)vbwvN#<}Bn=#dK<~u&(TvaU&0+Y;Q0h=axu20xsRd2_GZ3m|(gpHg| zw}aDT?zUpb1fbs|hgJ1@wUi&>$b=5R;Q{8c9tZHFZTT?{VdDVkS7T%yPBmljmv1*E z)2DY>YA)T-#J*q!&-&`{JZ|&=KjThSUF=$%N^-Crtg4&sRK~Og7n0oX1ma1O6CKdI zxP+fQ4RJil{9g-6MrCjhm#gYcEB!?r?s5A8vsLw~tFTYvVaK6sO{;Zj24{ylWlxgj zR_f1jec;#6B-!2vgq=xVwxCz=VgPz<2nc(dt{K. + * + * 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 + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **)argv); +} diff --git a/src/frontends/osx/strongSwan/strongSwan-Info.plist b/src/frontends/osx/strongSwan/strongSwan-Info.plist new file mode 100644 index 000000000..56ab217ef --- /dev/null +++ b/src/frontends/osx/strongSwan/strongSwan-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + icon-large.icns + CFBundleIdentifier + org.strongswan.osx + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + strongSwan OS X App + CFBundlePackageType + APPL + CFBundleShortVersionString + 5.2.2 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSApplicationCategoryType + public.app-category.utilities + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSUIElement + + NSHumanReadableCopyright + Copyright © 2013 revosec AG. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + SMPrivilegedExecutables + + org.strongswan.charon-xpc + identifier "org.strongswan.charon-xpc" and certificate leaf[subject.CN] = "Developer ID Application: revosec AG (SRXT3TB2PY)" + + + diff --git a/src/frontends/osx/strongSwan/strongSwan-Prefix.pch b/src/frontends/osx/strongSwan/strongSwan-Prefix.pch new file mode 100644 index 000000000..93e0dd127 --- /dev/null +++ b/src/frontends/osx/strongSwan/strongSwan-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'strongSwan' target in the 'strongSwan' project +// + +#ifdef __OBJC__ + #import +#endif From 7f82a8f34b4eecf8011716a3e57dee30227293fb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 16 Dec 2014 17:14:38 +0100 Subject: [PATCH 5/5] osx: Update the README with App related bits --- src/frontends/osx/README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index 8ad7e439f..9dfdeb224 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -4,8 +4,8 @@ The strongSwan OS X App consists of two components: -* A frontend to configure and control connections -* A privileged helper daemon, controlled using XPC, called charon-xpc +* A frontend App to configure and control connections (under strongSwan) +* A privileged helper daemon, controlled using XPC (under charon-xpc) The privileged helper daemon gets installed automatically using SMJobBless functionality on its first use, and gets started automatically by Launchd when @@ -13,10 +13,10 @@ needed. charon-xpc is a special build linking statically against strongSwan components. -charon-xpc sources are not part of the official strongSwan distribution. Build -the charon-xpc tarball with: +charon-xpc and the App sources are currently not part of the official strongSwan +distribution. Build the charon-xpc tarball with: - git archive -o charon-xpc-$(grep AC_INIT configure.ac | \ + git archive -o osx-sources-$(grep AC_INIT configure.ac | \ cut -d '[' -f3 | cut -d ']' -f1).tar.bz2 \ HEAD src/frontends/osx @@ -25,7 +25,7 @@ the charon-xpc tarball with: Before building the Xcode project, the strongSwan base tree must be built using a monolithic and static build. This can be achieved on OS X by using: - CFLAGS="-O2 -Wall -Wno-format -Wno-pointer-sign -Wno-deprecated-declarations" \ + CFLAGS="-O2 -g -Wall -Wno-format -Wno-pointer-sign -Wno-deprecated-declarations" \ ./configure --enable-monolithic --disable-shared --enable-static \ --disable-defaults \ --enable-openssl --enable-kernel-libipsec --enable-kernel-pfroute \ @@ -38,11 +38,17 @@ a monolithic and static build. This can be achieved on OS X by using: followed by calling make (no need to make install). Building charon-xpc using the Xcode project yields a single binary without -any non OS X dependencies. +any non OS X dependencies. The strongSwan target in the same project builds +the App and integrates charon-xpc for the deployment. Both charon-xpc and the App must be code-signed to allow the installation of -the privileged helper. git-grep for "Joe Developer" to change the signing -identity. +the privileged helper. By default both targets use the _Developer ID: *_ +wildcard to use the first usable code signing identity. Both the App and +charon-xpc require a hardcoded certificate subject under +_strongSwan/strongSwan-Info.plist_ respectively +_charon-xpc/charon-xpc-Info.plist_. Update the _org.strongswan.charon-xpc_ +_SMPrivilegedExecutables_ in the App and _SMAuthorizedClients_ in charon-xpc +with your code signing certificate identity. ## XPC application protocol ##