/* < internal > * _g_dbus_method_invocation_new: * @sender: The bus name that invoked the method or %NULL if @connection is not a bus connection. * @object_path: The object path the method was invoked on. * @interface_name: The name of the D-Bus interface the method was invoked on. * @method_name: The name of the method that was invoked. * @method_info: Information about the method call or %NULL. * @connection: The #GDBusConnection the method was invoked on. * @message: The D-Bus message as a #GDBusMessage. * @parameters: The parameters as a #GVariant tuple. * @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object(). * * Creates a new #GDBusMethodInvocation object. * * Returns: A #GDBusMethodInvocation. Free with g_object_unref(). * * Since: 2.26 */ GDBusMethodInvocation * _g_dbus_method_invocation_new (const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, const GDBusMethodInfo *method_info, GDBusConnection *connection, GDBusMessage *message, GVariant *parameters, gpointer user_data) { GDBusMethodInvocation *invocation; g_return_val_if_fail (sender == NULL || g_dbus_is_name (sender), NULL); g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), NULL); g_return_val_if_fail (g_dbus_is_member_name (method_name), NULL); g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); g_return_val_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL); invocation = G_DBUS_METHOD_INVOCATION (g_object_new (G_TYPE_DBUS_METHOD_INVOCATION, NULL)); invocation->sender = g_strdup (sender); invocation->object_path = g_strdup (object_path); invocation->interface_name = g_strdup (interface_name); invocation->method_name = g_strdup (method_name); invocation->method_info = g_dbus_method_info_ref ((GDBusMethodInfo *)method_info); invocation->connection = g_object_ref (connection); invocation->message = g_object_ref (message); invocation->parameters = g_variant_ref (parameters); invocation->user_data = user_data; return invocation; }
static gboolean register_portal (const char *path, GError **error) { g_autoptr(GKeyFile) keyfile = g_key_file_new (); g_autoptr(PortalImplementation) impl = g_new0 (PortalImplementation, 1); int i; g_debug ("loading %s", path); if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, error)) return FALSE; impl->dbus_name = g_key_file_get_string (keyfile, "portal", "DBusName", error); if (impl->dbus_name == NULL) return FALSE; if (!g_dbus_is_name (impl->dbus_name)) { g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, "Not a valid bus name: %s", impl->dbus_name); return FALSE; } impl->interfaces = g_key_file_get_string_list (keyfile, "portal", "Interfaces", NULL, error); if (impl->interfaces == NULL) return FALSE; for (i = 0; impl->interfaces[i]; i++) { if (!g_dbus_is_interface_name (impl->interfaces[i])) { g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, "Not a valid interface name: %s", impl->interfaces[i]); return FALSE; } if (!g_str_has_prefix (impl->interfaces[i], "org.freedesktop.impl.portal.")) { g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, "Not a portal backend interface: %s", impl->interfaces[i]); return FALSE; } } impl->use_in = g_key_file_get_string_list (keyfile, "portal", "UseIn", NULL, error); if (impl->use_in == NULL) return FALSE; if (opt_verbose) { g_autofree char *uses = g_strjoinv (", ", impl->use_in); g_debug ("portal implementation for %s", uses); for (i = 0; impl->interfaces[i]; i++) g_debug ("portal implementation supports %s", impl->interfaces[i]); } implementations = g_list_prepend (implementations, impl); impl = NULL; return TRUE; }
/** * g_bus_own_name: * @bus_type: The type of bus to own a name on. * @name: The well-known name to own. * @flags: A set of flags from the #GBusNameOwnerFlags enumeration. * @bus_acquired_handler: Handler to invoke when connected to the bus of type @bus_type or %NULL. * @name_acquired_handler: Handler to invoke when @name is acquired or %NULL. * @name_lost_handler: Handler to invoke when @name is lost or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: Function for freeing @user_data or %NULL. * * Starts acquiring @name on the bus specified by @bus_type and calls * @name_acquired_handler and @name_lost_handler when the name is * acquired respectively lost. Callbacks will be invoked in the <link * linkend="g-main-context-push-thread-default">thread-default main * loop</link> of the thread you are calling this function from. * * You are guaranteed that one of the @name_acquired_handler and @name_lost_handler * callbacks will be invoked after calling this function - there are three * possible cases: * <itemizedlist> * <listitem><para> * @name_lost_handler with a %NULL connection (if a connection to the bus can't be made). * </para></listitem> * <listitem><para> * @bus_acquired_handler then @name_lost_handler (if the name can't be obtained) * </para></listitem> * <listitem><para> * @bus_acquired_handler then @name_acquired_handler (if the name was obtained). * </para></listitem> * </itemizedlist> * When you are done owning the name, just call g_bus_unown_name() * with the owner id this function returns. * * If the name is acquired or lost (for example another application * could acquire the name if you allow replacement or the application * currently owning the name exits), the handlers are also invoked. If the * #GDBusConnection that is used for attempting to own the name * closes, then @name_lost_handler is invoked since it is no * longer possible for other processes to access the process. * * You cannot use g_bus_own_name() several times for the same name (unless * interleaved with calls to g_bus_unown_name()) - only the first call * will work. * * Another guarantee is that invocations of @name_acquired_handler * and @name_lost_handler are guaranteed to alternate; that * is, if @name_acquired_handler is invoked then you are * guaranteed that the next time one of the handlers is invoked, it * will be @name_lost_handler. The reverse is also true. * * If you plan on exporting objects (using e.g. * g_dbus_connection_register_object()), note that it is generally too late * to export the objects in @name_acquired_handler. Instead, you can do this * in @bus_acquired_handler since you are guaranteed that this will run * before @name is requested from the bus. * * This behavior makes it very simple to write applications that wants * to own names and export objects, see <xref linkend="gdbus-owning-names"/>. * Simply register objects to be exported in @bus_acquired_handler and * unregister the objects (if any) in @name_lost_handler. * * Returns: An identifier (never 0) that an be used with * g_bus_unown_name() to stop owning the name. * * Since: 2.26 */ guint g_bus_own_name (GBusType bus_type, const gchar *name, GBusNameOwnerFlags flags, GBusAcquiredCallback bus_acquired_handler, GBusNameAcquiredCallback name_acquired_handler, GBusNameLostCallback name_lost_handler, gpointer user_data, GDestroyNotify user_data_free_func) { Client *client; g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0); G_LOCK (lock); client = g_new0 (Client, 1); client->ref_count = 1; client->id = next_global_id++; /* TODO: uh oh, handle overflow */ client->name = g_strdup (name); client->flags = flags; client->bus_acquired_handler = bus_acquired_handler; client->name_acquired_handler = name_acquired_handler; client->name_lost_handler = name_lost_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; client->main_context = g_main_context_get_thread_default (); if (client->main_context != NULL) g_main_context_ref (client->main_context); if (map_id_to_client == NULL) { map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); } g_hash_table_insert (map_id_to_client, GUINT_TO_POINTER (client->id), client); g_bus_get (bus_type, NULL, connection_get_cb, client_ref (client)); G_UNLOCK (lock); return client->id; }
static gboolean app_check_name (gchar **args, const gchar *command) { if (args[0] == NULL) { g_printerr (_("%s command requires an application id to directly follow\n\n"), command); return FALSE; } if (!g_dbus_is_name (args[0])) { g_printerr (_("invalid application id: '%s'\n"), args[0]); return FALSE; } return TRUE; }
/** * g_bus_watch_name: * @bus_type: The type of bus to watch a name on. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL. * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL. * * Starts watching @name on the bus specified by @bus_type and calls * @name_appeared_handler and @name_vanished_handler when the name is * known to have a owner respectively known to lose its * owner. Callbacks will be invoked in the * [thread-default main context][g-main-context-push-thread-default] * of the thread you are calling this function from. * * You are guaranteed that one of the handlers will be invoked after * calling this function. When you are done watching the name, just * call g_bus_unwatch_name() with the watcher id this function * returns. * * If the name vanishes or appears (for example the application owning * the name could restart), the handlers are also invoked. If the * #GDBusConnection that is used for watching the name disconnects, then * @name_vanished_handler is invoked since it is no longer * possible to access the name. * * Another guarantee is that invocations of @name_appeared_handler * and @name_vanished_handler are guaranteed to alternate; that * is, if @name_appeared_handler is invoked then you are * guaranteed that the next time one of the handlers is invoked, it * will be @name_vanished_handler. The reverse is also true. * * This behavior makes it very simple to write applications that want * to take action when a certain [name exists][gdbus-watching-names]. * Basically, the application should create object proxies in * @name_appeared_handler and destroy them again (if any) in * @name_vanished_handler. * * Returns: An identifier (never 0) that an be used with * g_bus_unwatch_name() to stop watching the name. * * Since: 2.26 */ guint g_bus_watch_name (GBusType bus_type, const gchar *name, GBusNameWatcherFlags flags, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, gpointer user_data, GDestroyNotify user_data_free_func) { Client *client; g_return_val_if_fail (g_dbus_is_name (name), 0); G_LOCK (lock); client = g_new0 (Client, 1); client->ref_count = 1; client->id = g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */ client->name = g_strdup (name); client->flags = flags; client->name_appeared_handler = name_appeared_handler; client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) { map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); } g_hash_table_insert (map_id_to_client, GUINT_TO_POINTER (client->id), client); g_bus_get (bus_type, NULL, connection_get_cb, client_ref (client)); G_UNLOCK (lock); return client->id; }
/** * g_bus_watch_name_on_connection: * @connection: A #GDBusConnection. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. * @name_appeared_handler: (allow-none): Handler to invoke when @name is known to exist or %NULL. * @name_vanished_handler: (allow-none): Handler to invoke when @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (allow-none): Function for freeing @user_data or %NULL. * * Like g_bus_watch_name() but takes a #GDBusConnection instead of a * #GBusType. * * Returns: An identifier (never 0) that an be used with * g_bus_unwatch_name() to stop watching the name. * * Since: 2.26 */ guint g_bus_watch_name_on_connection (GDBusConnection *connection, const gchar *name, GBusNameWatcherFlags flags, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, gpointer user_data, GDestroyNotify user_data_free_func) { Client *client; g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0); g_return_val_if_fail (g_dbus_is_name (name), 0); G_LOCK (lock); client = g_new0 (Client, 1); client->ref_count = 1; client->id = next_global_id++; /* TODO: uh oh, handle overflow */ client->name = g_strdup (name); client->flags = flags; client->name_appeared_handler = name_appeared_handler; client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (map_id_to_client, GUINT_TO_POINTER (client->id), client); client->connection = g_object_ref (connection); G_UNLOCK (lock); has_connection (client); return client->id; }
/** * g_dbus_method_invocation_return_dbus_error: * @invocation: A #GDBusMethodInvocation. * @error_name: A valid D-Bus error name. * @error_message: A valid D-Bus error message. * * Finishes handling a D-Bus method call by returning an error. * * This method will free @invocation, you cannot use it afterwards. * * Since: 2.26 */ void g_dbus_method_invocation_return_dbus_error (GDBusMethodInvocation *invocation, const gchar *error_name, const gchar *error_message) { GDBusMessage *reply; g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); g_return_if_fail (error_name != NULL && g_dbus_is_name (error_name)); g_return_if_fail (error_message != NULL); if (G_UNLIKELY (_g_dbus_debug_return ())) { _g_dbus_debug_print_lock (); g_print ("========================================================================\n" "GDBus-debug:Return:\n" " >>>> METHOD ERROR %s\n" " message `%s'\n" " in response to %s.%s()\n" " on object %s\n" " to name %s\n" " reply-serial %d\n", error_name, error_message, invocation->interface_name, invocation->method_name, invocation->object_path, invocation->sender, g_dbus_message_get_serial (invocation->message)); _g_dbus_debug_print_unlock (); } reply = g_dbus_message_new_method_error_literal (invocation->message, error_name, error_message); g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL); g_object_unref (reply); g_object_unref (invocation); }
/** * cockpit_fake_manager_new_for_bus: * @bus_type: dbus bus to listen on * @flags: flags for the object manager * @bus_name: name of service to look for objects on * @object_paths: the paths to initially poke * @cancellable: optional cancellation object * @callback: called when operation finishes * @user_data: data for callback * * Create a new CockpitFakeManager. * * The @object_paths are poked and introspected. These are added * as well as anything else discovered along the way, before the * async operation completes. * * If @object_paths is NULL it will default to the root '/' DBus * path. If @object_paths is an empty array, then nothing is * poked during initialization. */ void cockpit_fake_manager_new_for_bus (GBusType bus_type, GDBusObjectManagerClientFlags flags, const gchar *bus_name, const gchar **object_paths, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (g_dbus_is_name (bus_name)); g_async_initable_new_async (COCKPIT_TYPE_FAKE_MANAGER, G_PRIORITY_DEFAULT, cancellable, callback, user_data, "bus-type", bus_type, "flags", flags, "name", bus_name, "object-paths", object_paths, NULL); }
/* ** DBus method call: "InstanceExit" -- Called from an instance */ static gboolean on_handle_instance_exit(WarfacebotMngr *wbm, GDBusMethodInvocation *invocation, const gchar *BusName) { g_print("Instance wants to exit: %s\n", BusName); if (!g_dbus_is_name(BusName)) { g_dbus_method_invocation_return_dbus_error( invocation, "org.freedesktop.DBus.Error.ServiceUnknown", "Invalid BusName"); return FALSE; } delete_service_file(BusName); warfacebot_mngr_complete_instance_exit( wbm, invocation); return TRUE; }
/* ** DBus method call: "InstanceReady" -- Called from an instance ** - Create an instance interface in the manager bus ** - Watch the instance bus */ static gboolean on_handle_instance_ready(WarfacebotMngr *wbm, GDBusMethodInvocation *invocation, const gchar *Nickname, const gchar *Server, const gchar *BusName) { ObjectSkeleton *skeleton = NULL; WarfacebotMngrInstance *wbi = NULL; struct watch_instance *watch = NULL; if (!g_dbus_is_name(BusName)) { g_dbus_method_invocation_return_dbus_error( invocation, "org.freedesktop.DBus.Error.ServiceUnknown", "Invalid BusName"); return FALSE; } g_print("Notification from instance: %s\n", BusName); watch = g_new0(struct watch_instance, 1); watch->name = g_strdup(BusName); watch->path = g_strdup_printf(API_MNGR_PATH "/%03d", ++uniq_id); skeleton = object_skeleton_new(watch->path); wbi = warfacebot_mngr_instance_skeleton_new(); warfacebot_mngr_instance_set_nickname(wbi, Nickname); warfacebot_mngr_instance_set_server(wbi, Server); warfacebot_mngr_instance_set_bus_name(wbi, BusName); warfacebot_mngr_instance_set_starttime(wbi, time(NULL)); object_skeleton_set_warfacebot_mngr_instance(skeleton, wbi); g_dbus_object_manager_server_export( manager, G_DBUS_OBJECT_SKELETON (skeleton)); g_object_unref(skeleton); create_service_file(BusName, Nickname, Server); watch->id = g_bus_watch_name( G_BUS_TYPE_SESSION, BusName, G_BUS_NAME_WATCHER_FLAGS_AUTO_START, on_instance_name_appeared, on_instance_name_vanished, watch, NULL); g_print("Watching instance: %s\n", BusName); warfacebot_mngr_complete_instance_ready( wbm, invocation); return TRUE; }
int main (int argc, char *argv[]) { NMDBusLibreswanHelper *proxy; GVariantBuilder environment; GError *err = NULL; gchar **env; gchar **p; const char *bus_name = NM_DBUS_SERVICE_LIBRESWAN; char *str = NULL; char **i_env; #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif /* support old command line arguments. The only reason for that is to * support update of the plugin while being connected. */ switch (argc) { case 1: break; case 4: gl.log_level = _nm_utils_ascii_str_to_int64 (argv[1], 10, 0, LOG_DEBUG, 0); gl.log_prefix_token = argv[2]; bus_name = argv[3]; break; case 3: if (strcmp (argv[1], "--bus-name") == 0) { bus_name = argv[2]; break; } /* fallthrough */ default: g_printerr ("Usage: %s <LEVEL> <PREFIX_TOKEN> <BUS_NAME>\n", argv[0]); exit (1); } if (!g_dbus_is_name (bus_name)) { g_printerr ("Not a valid bus name: '%s'\n", bus_name); exit (1); } _LOGD ("command line: %s", (str = g_strjoinv (" ", argv))); g_clear_pointer (&str, g_free); for (i_env = environ; i_env && *i_env; i_env++) _LOGD ("environment: %s", *i_env); proxy = nmdbus_libreswan_helper_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, bus_name, NM_DBUS_PATH_LIBRESWAN_HELPER, NULL, &err); if (!proxy) { _LOGW ("Could not create a D-Bus proxy: %s", err->message); g_error_free (err); exit (1); } g_variant_builder_init (&environment, G_VARIANT_TYPE ("a{ss}")); env = g_listenv (); for (p = env; *p; p++) { if (strncmp ("PLUTO_", *p, 6)) continue; g_variant_builder_add (&environment, "{ss}", *p, g_getenv (*p)); } g_strfreev (env); if (!nmdbus_libreswan_helper_call_callback_sync (proxy, g_variant_builder_end (&environment), NULL, &err)) { _LOGW ("Could not call the plugin: %s", err->message); g_error_free (err); g_object_unref (proxy); exit (1); } g_object_unref (proxy); exit (0); }
int main (int argc, char *argv[]) { GDBusProxy *proxy; GVariantBuilder builder, ip4builder, ip6builder; GVariant *ip4config, *ip6config; char *tmp; GVariant *val; int i; GError *err = NULL; GPtrArray *dns4_list, *dns6_list; GPtrArray *nbns_list; GPtrArray *dns_domains; struct in_addr temp_addr; int tapdev = -1; char **iter; int shift = 0; gboolean is_restart; gboolean has_ip4_prefix = FALSE; gboolean has_ip4_address = FALSE; gboolean has_ip6_address = FALSE; gchar *bus_name = NM_DBUS_SERVICE_OPENVPN; #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "--")) { i++; break; } if (nm_streq (argv[i], "--debug")) { if (i + 2 >= argc) { g_printerr ("Missing debug arguments (requires <LEVEL> <PREFIX_TOKEN>)\n"); exit (1); } gl.log_level = _nm_utils_ascii_str_to_int64 (argv[++i], 10, 0, LOG_DEBUG, 0); gl.log_prefix_token = argv[++i]; } else if (!strcmp (argv[i], "--tun")) tapdev = 0; else if (!strcmp (argv[i], "--tap")) tapdev = 1; else if (!strcmp (argv[i], "--bus-name")) { if (++i == argc) { g_printerr ("Missing bus name argument\n"); exit (1); } if (!g_dbus_is_name (argv[i])) { g_printerr ("Invalid bus name\n"); exit (1); } bus_name = argv[i]; } else break; } shift = i - 1; if (_LOGD_enabled ()) { GString *args; args = g_string_new (NULL); for (i = 0; i < argc; i++) { if (i > 0) g_string_append_c (args, ' '); if (shift && 1 + shift == i) g_string_append (args, " "); tmp = g_strescape (argv[i], NULL); g_string_append_printf (args, "\"%s\"", tmp); g_free (tmp); } _LOGD ("command line: %s", args->str); g_string_free (args, TRUE); for (iter = environ; iter && *iter; iter++) _LOGD ("environment: %s", *iter); } /* shift the arguments to the right leaving only those provided by openvpn */ argv[shift] = argv[0]; argv += shift; argc -= shift; is_restart = argc >= 7 && !g_strcmp0 (argv[6], "restart"); proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, bus_name, NM_VPN_DBUS_PLUGIN_PATH, NM_VPN_DBUS_PLUGIN_INTERFACE, NULL, &err); if (!proxy) { _LOGW ("Could not create a D-Bus proxy: %s", err->message); g_error_free (err); exit (1); } g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT); /* External world-visible VPN gateway */ val = trusted_remote_to_gvariant (); if (val) g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, val); else helper_failed (proxy, "VPN Gateway"); /* Internal VPN subnet gateway */ tmp = getenv ("route_vpn_gateway"); val = addr4_to_gvariant (tmp); if (val) g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, val); else { val = addr6_to_gvariant (tmp); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, val); } /* VPN device */ tmp = getenv ("dev"); val = str_to_gvariant (tmp, FALSE); if (val) g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV, val); else helper_failed (proxy, "Tunnel Device"); if (tapdev == -1) tapdev = strncmp (tmp, "tap", 3) == 0; /* IPv4 address */ tmp = getenv ("ifconfig_local"); if (!tmp && is_restart) tmp = argv[4]; if (tmp && strlen (tmp)) { val = addr4_to_gvariant (tmp); if (val) { has_ip4_address = TRUE; g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val); } else helper_failed (proxy, "IP4 Address"); } /* PTP address; for vpnc PTP address == internal IP4 address */ tmp = getenv ("ifconfig_remote"); if (!tmp && is_restart) tmp = argv[5]; val = addr4_to_gvariant (tmp); if (val) { /* Sigh. Openvpn added 'topology' stuff in 2.1 that changes the meaning * of the ifconfig bits without actually telling you what they are * supposed to mean; basically relying on specific 'ifconfig' behavior. */ if (tmp && !strncmp (tmp, "255.", 4)) { guint32 addr; /* probably a netmask, not a PTP address; topology == subnet */ addr = g_variant_get_uint32 (val); g_variant_unref (val); val = g_variant_new_uint32 (nm_utils_ip4_netmask_to_prefix (addr)); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); has_ip4_prefix = TRUE; } else g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PTP, val); } /* Netmask * * Either TAP or TUN modes can have an arbitrary netmask in newer versions * of openvpn, while in older versions only TAP mode would. So accept a * netmask if passed, otherwise default to /32 for TUN devices since they * are usually point-to-point. */ tmp = getenv ("ifconfig_netmask"); if (tmp && inet_pton (AF_INET, tmp, &temp_addr) > 0) { val = g_variant_new_uint32 (nm_utils_ip4_netmask_to_prefix (temp_addr.s_addr)); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); } else if (!tapdev) { if (has_ip4_address && !has_ip4_prefix) { val = g_variant_new_uint32 (32); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); } } else _LOGW ("No IP4 netmask/prefix (missing or invalid 'ifconfig_netmask')"); val = get_ip4_routes (); if (val) g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, val); else if (is_restart) { g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, g_variant_new_boolean (TRUE)); } /* IPv6 address */ tmp = getenv ("ifconfig_ipv6_local"); if (tmp && strlen (tmp)) { val = addr6_to_gvariant (tmp); if (val) { g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, val); has_ip6_address = TRUE; } else helper_failed (proxy, "IP6 Address"); } /* IPv6 remote address */ tmp = getenv ("ifconfig_ipv6_remote"); if (tmp && strlen (tmp)) { val = addr6_to_gvariant (tmp); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PTP, val); else helper_failed (proxy, "IP6 PTP Address"); } /* IPv6 netbits */ tmp = getenv ("ifconfig_ipv6_netbits"); if (tmp && strlen (tmp)) { long int netbits; errno = 0; netbits = strtol (tmp, NULL, 10); if (errno || netbits < 0 || netbits > 128) { _LOGW ("Ignoring invalid prefix '%s'", tmp); } else { val = g_variant_new_uint32 ((guint32) netbits); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, val); } } val = get_ip6_routes (); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, val); else if (is_restart) { g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, g_variant_new_boolean (TRUE)); } /* DNS and WINS servers */ dns_domains = g_ptr_array_sized_new (3); dns4_list = g_ptr_array_new (); dns6_list = g_ptr_array_new (); nbns_list = g_ptr_array_new (); for (i = 1; i < 256; i++) { char *env_name; env_name = g_strdup_printf ("foreign_option_%d", i); tmp = getenv (env_name); g_free (env_name); if (!tmp || strlen (tmp) < 1) break; if (!g_str_has_prefix (tmp, "dhcp-option ")) continue; tmp += 12; /* strlen ("dhcp-option ") */ if (g_str_has_prefix (tmp, "DNS ")) parse_addr_list (dns4_list, dns6_list, tmp + 4); else if (g_str_has_prefix (tmp, "WINS ")) parse_addr_list (nbns_list, NULL, tmp + 5); else if (g_str_has_prefix (tmp, "DOMAIN ") && is_domain_valid (tmp + 7)) g_ptr_array_add (dns_domains, tmp + 7); } if (dns4_list->len) { val = g_variant_new_array (G_VARIANT_TYPE_UINT32, (GVariant **) dns4_list->pdata, dns4_list->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS, val); } if (has_ip6_address && dns6_list->len) { val = g_variant_new_array (G_VARIANT_TYPE ("ay"), (GVariant **) dns6_list->pdata, dns6_list->len); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS, val); } if (nbns_list->len) { val = g_variant_new_array (G_VARIANT_TYPE_UINT32, (GVariant **) nbns_list->pdata, nbns_list->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val); } if (dns_domains->len) { val = g_variant_new_strv ((const gchar **) dns_domains->pdata, dns_domains->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, val); /* Domains apply to both IPv4 and IPv6 configurations */ if (has_ip6_address) { val = g_variant_new_strv ((const gchar **) dns_domains->pdata, dns_domains->len); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, val); } } g_ptr_array_unref (dns4_list); g_ptr_array_unref (dns6_list); g_ptr_array_unref (nbns_list); g_ptr_array_unref (dns_domains); /* Tunnel MTU */ tmp = getenv ("tun_mtu"); if (tmp && strlen (tmp)) { long int mtu; errno = 0; mtu = strtol (tmp, NULL, 10); if (errno || mtu < 0 || mtu > 20000) { _LOGW ("Ignoring invalid tunnel MTU '%s'", tmp); } else { val = g_variant_new_uint32 ((guint32) mtu); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_MTU, val); } } ip4config = g_variant_builder_end (&ip4builder); if (g_variant_n_children (ip4config)) { val = g_variant_new_boolean (TRUE); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4, val); } else { g_variant_unref (ip4config); ip4config = NULL; } ip6config = g_variant_builder_end (&ip6builder); if (g_variant_n_children (ip6config)) { val = g_variant_new_boolean (TRUE); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6, val); } else { g_variant_unref (ip6config); ip6config = NULL; } if (!ip4config && !ip6config) helper_failed (proxy, "IPv4 or IPv6 configuration"); /* Send the config info to nm-openvpn-service */ send_config (proxy, g_variant_builder_end (&builder), ip4config, ip6config); g_object_unref (proxy); return 0; }
int main (int argc, char *argv[]) { GError *error = NULL; GOptionContext *context = NULL; gchar *summary; gchar *app_name; #ifdef G_OS_UNIX gchar *desktop_file_name; gchar *bus_name = NULL; #endif GAppInfo *info = NULL; GAppLaunchContext *launch_context; GList *l; GFile *f; setlocale (LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR); textdomain (GETTEXT_PACKAGE); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif #endif /* Translators: this message will appear immediately after the */ /* usage string - Usage: COMMAND [OPTION...] <THIS_MESSAGE> */ context = g_option_context_new (_("APPLICATION [URI...] — launch an APPLICATION")); /* Translators: this message will appear after the usage string */ /* and before the list of options. */ summary = _("Launch an application (specified by its desktop file name),\n" "optionally passing one or more URIs as arguments."); g_option_context_set_summary (context, summary); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (FALSE)); g_option_context_parse (context, &argc, &argv, &error); g_option_context_free (context); if (error != NULL) { g_printerr (_("Error parsing commandline options: %s\n"), error->message); g_printerr ("\n"); g_printerr (_("Try \"%s --help\" for more information."), g_get_prgname ()); g_printerr ("\n"); g_error_free (error); return 1; } if (show_version) { g_print ("%d.%d.%d\n", gtk_get_major_version (), gtk_get_minor_version (), gtk_get_micro_version ()); return 0; } if (!args) { /* Translators: the %s is the program name. This error message */ /* means the user is calling gtk-launch without any argument. */ g_printerr (_("%s: missing application name"), g_get_prgname ()); g_printerr ("\n"); g_printerr (_("Try \"%s --help\" for more information."), g_get_prgname ()); g_printerr ("\n"); return 1; } gtk_init (&argc, &argv); app_name = *args; #if defined(HAVE_GIO_UNIX) && !defined(__APPLE__) bus_name = g_strdup (app_name); if (g_str_has_suffix (app_name, ".desktop")) { desktop_file_name = g_strdup (app_name); bus_name[strlen (bus_name) - strlen(".desktop")] = '\0'; } else { desktop_file_name = g_strconcat (app_name, ".desktop", NULL); } if (!g_dbus_is_name (bus_name)) g_clear_pointer (&bus_name, g_free); info = G_APP_INFO (g_desktop_app_info_new (desktop_file_name)); g_free (desktop_file_name); #else #warning Please add support for creating AppInfo from id for your OS g_printerr (_("Creating AppInfo from id not supported on non unix operating systems")); #endif args++; if (!info) { /* Translators: the first %s is the program name, the second one */ /* is the application name. */ g_printerr (_("%s: no such application %s"), g_get_prgname (), app_name); g_printerr ("\n"); return 2; } l = NULL; for (; *args; args++) { f = g_file_new_for_commandline_arg (*args); l = g_list_append (l, f); } launch_context = (GAppLaunchContext*) gdk_display_get_app_launch_context (gdk_display_get_default ()); if (!g_app_info_launch (info, l, launch_context, &error)) { /* Translators: the first %s is the program name, the second one */ /* is the error message. */ g_printerr (_("%s: error launching application: %s\n"), g_get_prgname (), error->message); return 3; } g_object_unref (info); g_object_unref (launch_context); #ifdef G_OS_UNIX if (bus_name != NULL) { GDBusConnection *connection; gchar *object_path, *p; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); object_path = g_strdup_printf ("/%s", bus_name); for (p = object_path; *p != '\0'; p++) if (*p == '.') *p = '/'; if (connection) g_dbus_connection_call_sync (connection, bus_name, object_path, "org.freedesktop.DBus.Peer", "Ping", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_clear_pointer (&object_path, g_free); g_clear_object (&connection); g_clear_pointer (&bus_name, g_free); } #endif g_list_free_full (l, g_object_unref); return 0; }