gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gportalsupport.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright 2016 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "config.h"
22
23 #include "glib-private.h"
24 #include "gportalsupport.h"
25 #include "gsandbox.h"
26
27 static GSandboxType sandbox_type = G_SANDBOX_TYPE_UNKNOWN;
28 static gboolean use_portal;
29 static gboolean network_available;
30 static gboolean dconf_access;
31
32 #ifdef G_PORTAL_SUPPORT_TEST
33 static const char *snapctl = "snapctl";
34 #else
35 static const char *snapctl = "/usr/bin/snapctl";
36 #endif
37
38 static gboolean
39 snap_plug_is_connected (const gchar *plug_name)
40 {
41   gint wait_status;
42   const gchar *argv[] = { snapctl, "is-connected", plug_name, NULL };
43
44   /* Bail out if our process is privileged - we don't want to pass those
45    * privileges to snapctl. It could be overridden and this would
46    * allow arbitrary code execution.
47    */
48   if (GLIB_PRIVATE_CALL (g_check_setuid) ())
49     return FALSE;
50
51   if (!g_spawn_sync (NULL, (gchar **) argv, NULL,
52 #ifdef G_PORTAL_SUPPORT_TEST
53                      G_SPAWN_SEARCH_PATH |
54 #endif
55                          G_SPAWN_STDOUT_TO_DEV_NULL |
56                          G_SPAWN_STDERR_TO_DEV_NULL,
57                      NULL, NULL, NULL, NULL, &wait_status,
58                      NULL))
59     return FALSE;
60
61   return g_spawn_check_wait_status (wait_status, NULL);
62 }
63
64 static void
65 sandbox_info_read (void)
66 {
67   static gsize sandbox_info_is_read = 0;
68
69   /* Sandbox type and Flatpak info is static, so only read once */
70   if (!g_once_init_enter (&sandbox_info_is_read))
71     return;
72
73   sandbox_type = glib_get_sandbox_type ();
74
75   switch (sandbox_type)
76     {
77     case G_SANDBOX_TYPE_FLATPAK:
78       {
79         GKeyFile *keyfile;
80         const char *keyfile_path = "/.flatpak-info";
81
82         use_portal = TRUE;
83         network_available = FALSE;
84         dconf_access = FALSE;
85
86         keyfile = g_key_file_new ();
87
88 #ifdef G_PORTAL_SUPPORT_TEST
89         char *test_key_file =
90           g_build_filename (g_get_user_runtime_dir (), keyfile_path, NULL);
91         keyfile_path = test_key_file;
92 #endif
93
94         if (g_key_file_load_from_file (keyfile, keyfile_path, G_KEY_FILE_NONE, NULL))
95           {
96             char **shared = NULL;
97             char *dconf_policy = NULL;
98
99             shared = g_key_file_get_string_list (keyfile, "Context", "shared", NULL, NULL);
100             if (shared)
101               {
102                 network_available = g_strv_contains ((const char *const *) shared, "network");
103                 g_strfreev (shared);
104               }
105
106             dconf_policy = g_key_file_get_string (keyfile, "Session Bus Policy", "ca.desrt.dconf", NULL);
107             if (dconf_policy)
108               {
109                 if (strcmp (dconf_policy, "talk") == 0)
110                   dconf_access = TRUE;
111                 g_free (dconf_policy);
112               }
113           }
114
115 #ifdef G_PORTAL_SUPPORT_TEST
116         g_clear_pointer (&test_key_file, g_free);
117 #endif
118
119         g_key_file_unref (keyfile);
120       }
121       break;
122     case G_SANDBOX_TYPE_SNAP:
123       break;
124     case G_SANDBOX_TYPE_UNKNOWN:
125       {
126         const char *var;
127
128         var = g_getenv ("GTK_USE_PORTAL");
129         if (var && var[0] == '1')
130           use_portal = TRUE;
131         network_available = TRUE;
132         dconf_access = TRUE;
133       }
134       break;
135     }
136
137   g_once_init_leave (&sandbox_info_is_read, 1);
138 }
139
140 gboolean
141 glib_should_use_portal (void)
142 {
143   sandbox_info_read ();
144
145   if (sandbox_type == G_SANDBOX_TYPE_SNAP)
146     return snap_plug_is_connected ("desktop");
147
148   return use_portal;
149 }
150
151 gboolean
152 glib_network_available_in_sandbox (void)
153 {
154   sandbox_info_read ();
155
156   if (sandbox_type == G_SANDBOX_TYPE_SNAP)
157     {
158       /* FIXME: This is inefficient doing multiple calls to check connections.
159        * See https://github.com/snapcore/snapd/pull/12301 for a proposed
160        * improvement to snapd for this.
161        */
162       return snap_plug_is_connected ("desktop") ||
163         snap_plug_is_connected ("network-status");
164     }
165
166   return network_available;
167 }
168
169 gboolean
170 glib_has_dconf_access_in_sandbox (void)
171 {
172   sandbox_info_read ();
173
174   if (sandbox_type == G_SANDBOX_TYPE_SNAP)
175     return snap_plug_is_connected ("gsettings");
176
177   return dconf_access;
178 }