summaryrefslogtreecommitdiff
path: root/src/backend/plugins/config-osx/config-osx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/plugins/config-osx/config-osx.c')
-rw-r--r--src/backend/plugins/config-osx/config-osx.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/src/backend/plugins/config-osx/config-osx.c b/src/backend/plugins/config-osx/config-osx.c
new file mode 100644
index 0000000..16813a0
--- /dev/null
+++ b/src/backend/plugins/config-osx/config-osx.c
@@ -0,0 +1,341 @@
+/* config-osx.c
+ *
+ * Copyright 2022-2023 The Libproxy Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <gio/gio.h>
+
+#include "config-osx.h"
+
+#include "px-plugin-config.h"
+#include "px-manager.h"
+
+static void px_config_iface_init (PxConfigInterface *iface);
+
+struct _PxConfigOsX {
+ GObject parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (PxConfigOsX,
+ px_config_osx,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (PX_TYPE_CONFIG, px_config_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CONFIG_OPTION
+};
+
+static void
+px_config_osx_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_CONFIG_OPTION:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_osx_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+px_config_osx_init (PxConfigOsX *self)
+{
+}
+
+static void
+px_config_osx_class_init (PxConfigOsXClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = px_config_osx_set_property;
+ object_class->get_property = px_config_osx_get_property;
+
+ g_object_class_override_property (object_class, PROP_CONFIG_OPTION, "config-option");
+}
+
+static gboolean
+px_config_osx_is_available (PxConfig *self)
+{
+ return TRUE;
+}
+
+static CFNumberRef
+getobj (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFNumberRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFNumberRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static CFStringRef
+getobj_str (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFStringRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFStringRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static CFArrayRef
+getobj_array (CFDictionaryRef settings,
+ char *key)
+{
+ CFStringRef k;
+ CFArrayRef retval;
+
+ if (!settings)
+ return NULL;
+
+ k = CFStringCreateWithCString (NULL, key, kCFStringEncodingMacRoman);
+ if (!k)
+ return NULL;
+
+ retval = (CFArrayRef)CFDictionaryGetValue (settings, k);
+
+ CFRelease (k);
+ return retval;
+}
+
+static char *
+str (CFStringRef ref)
+{
+ CFIndex size = CFStringGetLength (ref) + 1;
+ char *ret = g_malloc0 (size);
+
+ CFStringGetCString (ref, ret, size, kCFStringEncodingUTF8);
+
+ return ret;
+}
+
+static gboolean
+getint (CFDictionaryRef settings,
+ char *key,
+ int64_t *answer)
+{
+ CFNumberRef n = getobj (settings, key);
+
+ if (!n)
+ return FALSE;
+
+ if (!CFNumberGetValue (n, kCFNumberSInt64Type, answer))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+getbool (CFDictionaryRef settings,
+ char *key)
+{
+ int64_t i = 0;
+
+ if (!getint (settings, key, &i))
+ return FALSE;
+
+ return i != 0;
+}
+
+static char *
+str_to_upper (const char *str)
+{
+ char *ret = NULL;
+ int idx;
+
+ if (!str)
+ return NULL;
+
+ ret = g_malloc0 (strlen (str) + 1);
+
+ for (idx = 0; idx < strlen (str); idx++)
+ ret[idx] = g_ascii_toupper (str[idx]);
+
+ return ret;
+}
+
+static char *
+protocol_url (CFDictionaryRef settings,
+ char *protocol)
+{
+ g_autofree char *tmp = NULL;
+ g_autoptr (GString) ret = NULL;
+ g_autofree char *host = NULL;
+ int64_t port;
+ CFStringRef ref;
+
+ /* Check ProtocolEnabled */
+ tmp = g_strconcat (protocol, "Enable", NULL);
+ if (!getbool (settings, tmp)) {
+ g_debug ("%s: %s not set", __FUNCTION__, tmp);
+ return NULL;
+ }
+ g_clear_pointer (&tmp, g_free);
+
+ /* Get ProtocolPort */
+ tmp = g_strconcat (protocol, "Port", NULL);
+ getint (settings, tmp, &port);
+ if (!port) {
+ g_debug ("%s: %s not set", __FUNCTION__, tmp);
+ return NULL;
+ }
+ g_clear_pointer (&tmp, g_free);
+
+ /* Get ProtocolProxy */
+ tmp = g_strconcat (protocol, "Proxy", NULL);
+ ref = getobj_str (settings, tmp);
+ g_clear_pointer (&tmp, g_free);
+
+ host = str (ref);
+ if (!host || strlen (host) == 0)
+ return NULL;
+
+ if (strcmp (protocol, "HTTP") == 0 || strcmp (protocol, "HTTPS") == 0 || strcmp (protocol, "FTP") == 0 || strcmp (protocol, "Gopher") == 0)
+ ret = g_string_new ("http://");
+ else if (strcmp (protocol, "RTSP") == 0)
+ ret = g_string_new ("rtsp://");
+ else if (strcmp (protocol, "SOCKS") == 0)
+ ret = g_string_new ("socks://");
+ else
+ return NULL;
+
+ g_string_append_printf (ret, "%s:%lld", host, port);
+
+ return g_strdup (ret->str);
+}
+
+static GStrv
+get_ignore_list (CFDictionaryRef proxies)
+{
+ CFArrayRef ref = getobj_array (proxies, "ExceptionsList");
+ g_autoptr (GStrvBuilder) ret = g_strv_builder_new ();
+
+ if (!ref)
+ return g_strv_builder_end (ret);
+
+ for (int idx = 0; idx < CFArrayGetCount (ref); idx++) {
+ CFStringRef s = (CFStringRef)CFArrayGetValueAtIndex (ref, idx);
+
+ px_strv_builder_add_proxy (ret, str (s));
+ }
+
+ if (getbool (proxies, "ExcludeSimpleHostnames"))
+ px_strv_builder_add_proxy (ret, "127.0.0.1");
+
+ return g_strv_builder_end (ret);
+}
+
+static void
+px_config_osx_get_config (PxConfig *self,
+ GUri *uri,
+ GStrvBuilder *builder)
+{
+ const char *proxy = NULL;
+ CFDictionaryRef proxies = SCDynamicStoreCopyProxies (NULL);
+ g_auto (GStrv) ignore_list = NULL;
+
+ if (!proxies) {
+ g_warning ("Unable to fetch proxy configuration");
+ return;
+ }
+
+ ignore_list = get_ignore_list (proxies);
+
+ if (px_manager_is_ignore (uri, ignore_list))
+ return;
+
+ if (getbool (proxies, "ProxyAutoDiscoveryEnable")) {
+ CFRelease (proxies);
+ px_strv_builder_add_proxy (builder, "wpad://");
+ return;
+ }
+
+ if (getbool (proxies, "ProxyAutoConfigEnable")) {
+ CFStringRef ref = getobj_str (proxies, "ProxyAutoConfigURLString");
+ g_autofree char *tmp = str (ref);
+ GUri *tmp_uri = g_uri_parse (tmp, G_URI_FLAGS_PARSE_RELAXED, NULL);
+
+ if (tmp_uri) {
+ g_autofree char *ret = g_strdup_printf ("pac+%s", g_uri_to_string (tmp_uri));
+ CFRelease (proxies);
+ px_strv_builder_add_proxy (builder, ret);
+ return;
+ }
+ } else {
+ const char *scheme = g_uri_get_scheme (uri);
+ g_autofree char *capital_scheme = str_to_upper (scheme);
+
+ proxy = protocol_url (proxies, capital_scheme);
+
+ if (!proxy)
+ proxy = protocol_url (proxies, "SOCKS");
+ }
+
+ if (proxy)
+ px_strv_builder_add_proxy (builder, proxy);
+}
+
+static void
+px_config_iface_init (PxConfigInterface *iface)
+{
+ iface->name = "config-osx";
+ iface->priority = PX_CONFIG_PRIORITY_DEFAULT;
+ iface->is_available = px_config_osx_is_available;
+ iface->get_config = px_config_osx_get_config;
+}