osx-attr: add plugin installing config attributes using SystemConfiguration
authorMartin Willi <martin@revosec.ch>
Wed, 15 May 2013 13:56:17 +0000 (15:56 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 21 Jun 2013 15:03:22 +0000 (17:03 +0200)
Currently installs DNS servers only, by prepending IP addresses to the
DNS configuration of the primary networking service.

configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/osx_attr/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/osx_attr/osx_attr_handler.c [new file with mode: 0644]
src/libcharon/plugins/osx_attr/osx_attr_handler.h [new file with mode: 0644]
src/libcharon/plugins/osx_attr/osx_attr_plugin.c [new file with mode: 0644]
src/libcharon/plugins/osx_attr/osx_attr_plugin.h [new file with mode: 0644]

index a89edb8..696a179 100644 (file)
@@ -225,6 +225,7 @@ ARG_ENABL_SET([gcm],            [enables the GCM AEAD wrapper crypto plugin.])
 ARG_ENABL_SET([addrblock],      [enables RFC 3779 address block constraint support.])
 ARG_ENABL_SET([unity],          [enables Cisco Unity extension plugin.])
 ARG_ENABL_SET([uci],            [enable OpenWRT UCI configuration plugin.])
+ARG_ENABL_SET([osx-attr],       [enable OS X SystemConfiguration attribute handler.])
 ARG_ENABL_SET([android-dns],    [enable Android specific DNS handler.])
 ARG_ENABL_SET([android-log],    [enable Android specific logger plugin.])
 ARG_ENABL_SET([maemo],          [enable Maemo specific plugin.])
@@ -1066,6 +1067,7 @@ ADD_PLUGIN([tnccs-dynamic],        [c charon])
 ADD_PLUGIN([medsrv],               [c charon])
 ADD_PLUGIN([medcli],               [c charon])
 ADD_PLUGIN([dhcp],                 [c charon])
+ADD_PLUGIN([osx-attr],             [c charon cmd])
 ADD_PLUGIN([android-dns],          [c charon])
 ADD_PLUGIN([android-log],          [c charon])
 ADD_PLUGIN([ha],                   [c charon])
@@ -1158,6 +1160,7 @@ AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue)
 AM_CONDITIONAL(USE_MEDSRV, test x$medsrv = xtrue)
 AM_CONDITIONAL(USE_MEDCLI, test x$medcli = xtrue)
 AM_CONDITIONAL(USE_UCI, test x$uci = xtrue)
+AM_CONDITIONAL(USE_OSX_ATTR, test x$osx_attr = xtrue)
 AM_CONDITIONAL(USE_ANDROID_DNS, test x$android_dns = xtrue)
 AM_CONDITIONAL(USE_ANDROID_LOG, test x$android_log = xtrue)
 AM_CONDITIONAL(USE_MAEMO, test x$maemo = xtrue)
@@ -1435,6 +1438,7 @@ AC_CONFIG_FILES([
        src/libcharon/plugins/duplicheck/Makefile
        src/libcharon/plugins/coupling/Makefile
        src/libcharon/plugins/radattr/Makefile
+       src/libcharon/plugins/osx_attr/Makefile
        src/libcharon/plugins/android_dns/Makefile
        src/libcharon/plugins/android_log/Makefile
        src/libcharon/plugins/maemo/Makefile
index ae7867f..32167e2 100644 (file)
@@ -457,6 +457,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_OSX_ATTR
+  SUBDIRS += plugins/osx_attr
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/osx_attr/libstrongswan-osx-attr.la
+endif
+endif
+
 if USE_ANDROID_DNS
   SUBDIRS += plugins/android_dns
 if MONOLITHIC
diff --git a/src/libcharon/plugins/osx_attr/Makefile.am b/src/libcharon/plugins/osx_attr/Makefile.am
new file mode 100644 (file)
index 0000000..d1ceab4
--- /dev/null
@@ -0,0 +1,18 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-osx-attr.la
+else
+plugin_LTLIBRARIES = libstrongswan-osx-attr.la
+endif
+
+libstrongswan_osx_attr_la_SOURCES = \
+       osx_attr_plugin.c osx_attr_plugin.h \
+       osx_attr_handler.c osx_attr_handler.h
+
+libstrongswan_osx_attr_la_LDFLAGS = -module -avoid-version \
+       -framework SystemConfiguration -framework CoreFoundation
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_handler.c b/src/libcharon/plugins/osx_attr/osx_attr_handler.c
new file mode 100644 (file)
index 0000000..9a3b270
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "osx_attr_handler.h"
+
+#include <networking/host.h>
+#include <utils/debug.h>
+
+#include <SystemConfiguration/SCDynamicStore.h>
+
+typedef struct private_osx_attr_handler_t private_osx_attr_handler_t;
+
+/**
+ * Private data of an osx_attr_handler_t object.
+ */
+struct private_osx_attr_handler_t {
+
+       /**
+        * Public interface
+        */
+       osx_attr_handler_t public;
+};
+
+/**
+ * Create a path to the DNS configuration of the Primary IPv4 Service
+ */
+static CFStringRef create_dns_path(SCDynamicStoreRef store)
+{
+       CFStringRef service, path = NULL;
+       CFDictionaryRef dict;
+
+       /* get primary service */
+       dict = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4"));
+       if (dict)
+       {
+               service = CFDictionaryGetValue(dict, CFSTR("PrimaryService"));
+               if (service)
+               {
+                       path = CFStringCreateWithFormat(NULL, NULL,
+                                                               CFSTR("State:/Network/Service/%@/DNS"), service);
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "SystemConfiguration PrimaryService not known");
+               }
+               CFRelease(dict);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "getting global IPv4 SystemConfiguration failed");
+       }
+       return path;
+}
+
+/**
+ * Create a mutable dictionary from path, a new one if not found
+ */
+static CFMutableDictionaryRef get_dictionary(SCDynamicStoreRef store,
+                                                                                        CFStringRef path)
+{
+       CFDictionaryRef dict;
+       CFMutableDictionaryRef mut = NULL;
+
+       dict = SCDynamicStoreCopyValue(store, path);
+       if (dict)
+       {
+               if (CFGetTypeID(dict) == CFDictionaryGetTypeID())
+               {
+                       mut = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+               }
+               CFRelease(dict);
+       }
+       if (!mut)
+       {
+               mut = CFDictionaryCreateMutable(NULL, 0,
+                                                                               &kCFTypeDictionaryKeyCallBacks,
+                                                                               &kCFTypeDictionaryValueCallBacks);
+       }
+       return mut;
+}
+
+/**
+ * Create a mutable array from dictionary path, a new one if not found
+ */
+static CFMutableArrayRef get_array_from_dict(CFDictionaryRef dict,
+                                                                                        CFStringRef name)
+{
+       CFArrayRef arr;
+
+       arr = CFDictionaryGetValue(dict, name);
+       if (arr && CFGetTypeID(arr) == CFArrayGetTypeID())
+       {
+               return CFArrayCreateMutableCopy(NULL, 0, arr);
+       }
+       return CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+}
+
+/**
+ * Add/Remove a DNS server to the configuration
+ */
+static bool manage_dns(int family, chunk_t data, bool add)
+{
+       SCDynamicStoreRef store;
+       CFStringRef path, dns;
+       CFMutableArrayRef arr;
+       CFMutableDictionaryRef dict;
+       CFIndex i;
+       host_t *server;
+       char buf[64];
+       bool success = FALSE;
+
+       server = host_create_from_chunk(family, data, 0);
+       if (!server)
+       {
+               return FALSE;
+       }
+       snprintf(buf, sizeof(buf), "%H", server);
+       server->destroy(server);
+
+       store = SCDynamicStoreCreate(NULL, CFSTR("osx-attr"), NULL, NULL);
+       path = create_dns_path(store);
+       if (path)
+       {
+               dict = get_dictionary(store, path);
+               arr = get_array_from_dict(dict, CFSTR("ServerAddresses"));
+               dns = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
+               if (add)
+               {
+                       DBG1(DBG_CFG, "installing %s as DNS server", buf);
+                       CFArrayInsertValueAtIndex(arr, 0, dns);
+               }
+               else
+               {
+                       i = CFArrayGetFirstIndexOfValue(arr,
+                                                                       CFRangeMake(0, CFArrayGetCount(arr)), dns);
+                       if (i >= 0)
+                       {
+                               DBG1(DBG_CFG, "removing %s from DNS servers (%d)", buf, i);
+                               CFArrayRemoveValueAtIndex(arr, i);
+                       }
+               }
+               CFRelease(dns);
+               CFDictionarySetValue(dict, CFSTR("ServerAddresses"), arr);
+               CFRelease(arr);
+
+               success = SCDynamicStoreSetValue(store, path, dict);
+               CFRelease(dict);
+               CFRelease(path);
+       }
+       CFRelease(store);
+
+       if (!success)
+       {
+               DBG1(DBG_CFG, "adding DNS server to SystemConfiguration failed");
+       }
+       return success;
+}
+
+METHOD(attribute_handler_t, handle, bool,
+       private_osx_attr_handler_t *this, identification_t *id,
+       configuration_attribute_type_t type, chunk_t data)
+{
+       switch (type)
+       {
+               case INTERNAL_IP4_DNS:
+                       return manage_dns(AF_INET, data, TRUE);
+               default:
+                       return FALSE;
+       }
+}
+
+METHOD(attribute_handler_t, release, void,
+       private_osx_attr_handler_t *this, identification_t *server,
+       configuration_attribute_type_t type, chunk_t data)
+{
+       switch (type)
+       {
+               case INTERNAL_IP4_DNS:
+                       manage_dns(AF_INET, data, FALSE);
+                       break;
+               default:
+                       break;
+       }
+}
+
+METHOD(enumerator_t, enumerate_dns, bool,
+       enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
+{
+       *type = INTERNAL_IP4_DNS;
+       *data = chunk_empty;
+       /* stop enumeration */
+       this->enumerate = (void*)return_false;
+       return TRUE;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
+       private_osx_attr_handler_t *this, identification_t *id,
+       linked_list_t *vips)
+{
+       enumerator_t *enumerator;
+
+       INIT(enumerator,
+               .enumerate = (void*)_enumerate_dns,
+               .destroy = (void*)free,
+       );
+       return enumerator;
+}
+
+METHOD(osx_attr_handler_t, destroy, void,
+       private_osx_attr_handler_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+osx_attr_handler_t *osx_attr_handler_create()
+{
+       private_osx_attr_handler_t *this;
+
+       INIT(this,
+               .public = {
+                       .handler = {
+                               .handle = _handle,
+                               .release = _release,
+                               .create_attribute_enumerator = _create_attribute_enumerator,
+                       },
+                       .destroy = _destroy,
+               },
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_handler.h b/src/libcharon/plugins/osx_attr/osx_attr_handler.h
new file mode 100644 (file)
index 0000000..c1f979b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup osx_attr_handler osx_attr_handler
+ * @{ @ingroup osx_attr
+ */
+
+#ifndef OSX_ATTR_HANDLER_H_
+#define OSX_ATTR_HANDLER_H_
+
+#include <attributes/attribute_handler.h>
+
+typedef struct osx_attr_handler_t osx_attr_handler_t;
+
+/**
+ * OS X specific attribute handler, using SystemConfiguration framework.
+ */
+struct osx_attr_handler_t {
+
+       /**
+        * Implements attribute_handler_t.
+        */
+       attribute_handler_t handler;
+
+       /**
+        * Destroy a osx_attr_handler_t.
+        */
+       void (*destroy)(osx_attr_handler_t *this);
+};
+
+/**
+ * Create an osx_attr_handler_t instance.
+ */
+osx_attr_handler_t *osx_attr_handler_create();
+
+#endif /** OSX_ATTR_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_plugin.c b/src/libcharon/plugins/osx_attr/osx_attr_plugin.c
new file mode 100644 (file)
index 0000000..380483c
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "osx_attr_plugin.h"
+#include "osx_attr_handler.h"
+
+#include <hydra.h>
+#include <daemon.h>
+
+typedef struct private_osx_attr_plugin_t private_osx_attr_plugin_t;
+
+/**
+ * Private data of an osx_attr_plugin_t object.
+ */
+struct private_osx_attr_plugin_t {
+
+       /**
+        * Public interface
+        */
+       osx_attr_plugin_t public;
+
+       /**
+        * Android specific DNS handler
+        */
+       osx_attr_handler_t *handler;
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_osx_attr_plugin_t *this)
+{
+       return "osx-attr";
+}
+
+/**
+ * Register handler
+ */
+static bool plugin_cb(private_osx_attr_plugin_t *this,
+                                         plugin_feature_t *feature, bool reg, void *cb_data)
+{
+       if (reg)
+       {
+               hydra->attributes->add_handler(hydra->attributes,
+                                                                          &this->handler->handler);
+       }
+       else
+       {
+               hydra->attributes->remove_handler(hydra->attributes,
+                                                                                 &this->handler->handler);
+       }
+       return TRUE;
+}
+
+METHOD(plugin_t, get_features, int,
+       private_osx_attr_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+                       PLUGIN_PROVIDE(CUSTOM, "osx-attr"),
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_osx_attr_plugin_t *this)
+{
+       this->handler->destroy(this->handler);
+       free(this);
+}
+
+/**
+ * See header
+ */
+plugin_t *osx_attr_plugin_create()
+{
+       private_osx_attr_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+               .handler = osx_attr_handler_create(),
+       );
+
+       return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_plugin.h b/src/libcharon/plugins/osx_attr/osx_attr_plugin.h
new file mode 100644 (file)
index 0000000..7613793
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup osx_attr osx_attr
+ * @ingroup cplugins
+ *
+ * @defgroup osx_attr_plugin osx_attr_plugin
+ * @{ @ingroup osx_attr
+ */
+
+#ifndef OSX_ATTR_PLUGIN_H_
+#define OSX_ATTR_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct osx_attr_plugin_t osx_attr_plugin_t;
+
+/**
+ * Plugin providing an OS X specific configuration attribute handler.
+ */
+struct osx_attr_plugin_t {
+
+       /**
+        * Implements plugin interface.
+        */
+       plugin_t plugin;
+};
+
+#endif /** OSX_ATTR_PLUGIN_H_ @}*/