2015-03-23 11:17:58 +00:00
/*
* Copyright © 2014 Red Hat , Inc
*
* This program 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
2016-07-29 18:27:49 +00:00
* version 2.1 of the License , or ( at your option ) any later version .
2015-03-23 11:17:58 +00:00
*
* 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 , see < http : //www.gnu.org/licenses/>.
*
* Authors :
* Alexander Larsson < alexl @ redhat . com >
*/
2015-02-13 09:29:41 +00:00
# include "config.h"
# include <string.h>
# include <fcntl.h>
# include <stdio.h>
2015-03-04 13:40:17 +00:00
# include <unistd.h>
2015-10-01 19:23:23 +00:00
# include <sys/utsname.h>
2016-04-29 09:39:39 +00:00
# include <sys/socket.h>
2017-01-17 15:36:56 +00:00
# include <sys/ioctl.h>
2016-04-29 09:39:39 +00:00
# include <grp.h>
# ifdef ENABLE_SECCOMP
# include <seccomp.h>
# endif
2015-10-01 19:23:23 +00:00
2016-01-28 13:34:22 +00:00
# ifdef ENABLE_XAUTH
2015-10-01 19:23:23 +00:00
# include <X11/Xauth.h>
2016-01-28 13:34:22 +00:00
# endif
2015-02-13 09:29:41 +00:00
2016-07-23 15:01:50 +00:00
# include <glib/gi18n.h>
2015-02-13 09:29:41 +00:00
# include <gio/gio.h>
2015-03-20 15:21:19 +00:00
# include "libglnx/libglnx.h"
2015-02-13 09:29:41 +00:00
2016-05-06 16:03:47 +00:00
# include "flatpak-run.h"
# include "flatpak-proxy.h"
# include "flatpak-utils.h"
2016-10-14 09:20:53 +00:00
# include "flatpak-dir.h"
2016-05-06 16:03:47 +00:00
# include "flatpak-systemd-dbus.h"
2015-02-13 09:29:41 +00:00
2016-04-29 09:39:39 +00:00
# define DEFAULT_SHELL " / bin / sh"
2015-10-01 19:23:23 +00:00
2015-05-22 13:36:52 +00:00
typedef enum {
2016-05-06 14:37:47 +00:00
FLATPAK_CONTEXT_SHARED_NETWORK = 1 < < 0 ,
FLATPAK_CONTEXT_SHARED_IPC = 1 < < 1 ,
} FlatpakContextShares ;
2015-05-22 13:36:52 +00:00
2016-04-29 09:39:39 +00:00
/* In numerical order of more privs */
2015-11-26 16:22:37 +00:00
typedef enum {
2016-05-06 14:37:47 +00:00
FLATPAK_FILESYSTEM_MODE_READ_ONLY = 1 ,
FLATPAK_FILESYSTEM_MODE_READ_WRITE = 2 ,
2016-11-14 09:58:39 +00:00
FLATPAK_FILESYSTEM_MODE_CREATE = 3 ,
2016-05-06 14:37:47 +00:00
} FlatpakFilesystemMode ;
2015-11-26 16:22:37 +00:00
2015-09-09 12:11:05 +00:00
/* Same order as enum */
2016-05-27 14:30:13 +00:00
const char * flatpak_context_shares [ ] = {
2015-09-09 12:11:05 +00:00
" network " ,
" ipc " ,
NULL
} ;
2015-05-22 13:36:52 +00:00
typedef enum {
2016-05-06 14:37:47 +00:00
FLATPAK_CONTEXT_SOCKET_X11 = 1 < < 0 ,
FLATPAK_CONTEXT_SOCKET_WAYLAND = 1 < < 1 ,
FLATPAK_CONTEXT_SOCKET_PULSEAUDIO = 1 < < 2 ,
FLATPAK_CONTEXT_SOCKET_SESSION_BUS = 1 < < 3 ,
FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS = 1 < < 4 ,
} FlatpakContextSockets ;
2015-05-22 13:36:52 +00:00
2015-09-09 12:11:05 +00:00
/* Same order as enum */
2016-05-27 14:30:13 +00:00
const char * flatpak_context_sockets [ ] = {
2015-09-09 12:11:05 +00:00
" x11 " ,
" wayland " ,
" pulseaudio " ,
" session-bus " ,
" system-bus " ,
NULL
} ;
2016-04-29 09:39:39 +00:00
const char * dont_mount_in_root [ ] = {
" . " , " .. " , " lib " , " lib32 " , " lib64 " , " bin " , " sbin " , " usr " , " boot " , " root " ,
" tmp " , " etc " , " app " , " run " , " proc " , " sys " , " dev " , " var " , NULL
} ;
2017-01-19 09:43:17 +00:00
/* We don't want to export paths pointing into these, because they are readonly
( so we can ' t create mountpoints there ) and don ' t match whats on the host anyway */
const char * dont_export_in [ ] = {
" /lib/ " , " /lib32/ " , " /lib64/ " , " /bin/ " , " /sbin/ " , " /usr/ " , " /etc/ " , " /app/ " , NULL
} ;
2015-05-22 13:36:52 +00:00
typedef enum {
2016-05-06 14:37:47 +00:00
FLATPAK_CONTEXT_DEVICE_DRI = 1 < < 0 ,
2016-06-14 20:33:14 +00:00
FLATPAK_CONTEXT_DEVICE_ALL = 1 < < 1 ,
2016-09-30 14:44:17 +00:00
FLATPAK_CONTEXT_DEVICE_KVM = 1 < < 2 ,
2016-05-06 14:37:47 +00:00
} FlatpakContextDevices ;
2015-05-22 13:36:52 +00:00
2016-05-27 14:30:13 +00:00
const char * flatpak_context_devices [ ] = {
2015-09-09 12:11:05 +00:00
" dri " ,
2016-06-14 20:33:14 +00:00
" all " ,
2016-09-30 14:44:17 +00:00
" kvm " ,
2015-09-09 12:11:05 +00:00
NULL
} ;
2016-09-05 19:22:20 +00:00
typedef enum {
FLATPAK_CONTEXT_FEATURE_DEVEL = 1 < < 0 ,
2016-09-29 15:17:37 +00:00
FLATPAK_CONTEXT_FEATURE_MULTIARCH = 1 < < 1 ,
2016-09-05 19:22:20 +00:00
} FlatpakContextFeatures ;
const char * flatpak_context_features [ ] = {
" devel " ,
2016-09-29 15:17:37 +00:00
" multiarch " ,
2016-09-05 19:22:20 +00:00
NULL
} ;
2017-03-14 15:20:33 +00:00
static gboolean
add_dbus_proxy_args ( GPtrArray * argv_array ,
GPtrArray * dbus_proxy_argv ,
gboolean enable_logging ,
int sync_fds [ 2 ] ,
const char * app_info_path ,
GError * * error ) ;
2016-05-06 14:37:47 +00:00
struct FlatpakContext
{
FlatpakContextShares shares ;
FlatpakContextShares shares_valid ;
FlatpakContextSockets sockets ;
FlatpakContextSockets sockets_valid ;
FlatpakContextDevices devices ;
FlatpakContextDevices devices_valid ;
2016-09-05 19:22:20 +00:00
FlatpakContextFeatures features ;
FlatpakContextFeatures features_valid ;
2016-05-06 14:37:47 +00:00
GHashTable * env_vars ;
GHashTable * persistent ;
GHashTable * filesystems ;
GHashTable * session_bus_policy ;
GHashTable * system_bus_policy ;
2016-10-19 18:39:17 +00:00
GHashTable * generic_policy ;
2015-05-22 13:36:52 +00:00
} ;
2016-05-06 14:37:47 +00:00
FlatpakContext *
flatpak_context_new ( void )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
context = g_slice_new0 ( FlatpakContext ) ;
2015-05-22 13:36:52 +00:00
context - > env_vars = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_free ) ;
context - > persistent = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
context - > filesystems = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
2016-01-29 07:50:11 +00:00
context - > session_bus_policy = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
context - > system_bus_policy = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
2016-10-19 18:39:17 +00:00
context - > generic_policy = g_hash_table_new_full ( g_str_hash , g_str_equal ,
g_free , ( GDestroyNotify ) g_strfreev ) ;
2015-05-22 13:36:52 +00:00
return context ;
}
void
2016-05-06 14:37:47 +00:00
flatpak_context_free ( FlatpakContext * context )
2015-05-22 13:36:52 +00:00
{
g_hash_table_destroy ( context - > env_vars ) ;
g_hash_table_destroy ( context - > persistent ) ;
g_hash_table_destroy ( context - > filesystems ) ;
2016-01-29 07:50:11 +00:00
g_hash_table_destroy ( context - > session_bus_policy ) ;
g_hash_table_destroy ( context - > system_bus_policy ) ;
2016-10-19 18:39:17 +00:00
g_hash_table_destroy ( context - > generic_policy ) ;
2016-05-06 14:37:47 +00:00
g_slice_free ( FlatpakContext , context ) ;
2015-05-22 13:36:52 +00:00
}
2015-09-09 12:11:05 +00:00
static guint32
2016-05-06 14:37:47 +00:00
flatpak_context_bitmask_from_string ( const char * name , const char * * names )
2015-05-22 13:36:52 +00:00
{
2015-09-09 12:11:05 +00:00
guint32 i ;
for ( i = 0 ; names [ i ] ! = NULL ; i + + )
{
if ( strcmp ( names [ i ] , name ) = = 0 )
return 1 < < i ;
}
2015-05-22 13:36:52 +00:00
return 0 ;
}
static char * *
2016-05-06 14:37:47 +00:00
flatpak_context_bitmask_to_string ( guint32 enabled , guint32 valid , const char * * names )
2015-05-22 13:36:52 +00:00
{
2015-09-09 12:11:05 +00:00
guint32 i ;
2015-05-22 13:36:52 +00:00
GPtrArray * array ;
array = g_ptr_array_new ( ) ;
2015-09-09 12:11:05 +00:00
for ( i = 0 ; names [ i ] ! = NULL ; i + + )
{
guint32 bitmask = 1 < < i ;
if ( valid & bitmask )
{
if ( enabled & bitmask )
g_ptr_array_add ( array , g_strdup ( names [ i ] ) ) ;
else
g_ptr_array_add ( array , g_strdup_printf ( " !%s " , names [ i ] ) ) ;
}
}
2015-05-22 13:36:52 +00:00
g_ptr_array_add ( array , NULL ) ;
2016-05-06 14:03:27 +00:00
return ( char * * ) g_ptr_array_free ( array , FALSE ) ;
2015-05-22 13:36:52 +00:00
}
2016-05-26 10:23:48 +00:00
static void
flatpak_context_bitmask_to_args ( guint32 enabled , guint32 valid , const char * * names ,
const char * enable_arg , const char * disable_arg ,
GPtrArray * args )
{
guint32 i ;
for ( i = 0 ; names [ i ] ! = NULL ; i + + )
{
guint32 bitmask = 1 < < i ;
if ( valid & bitmask )
{
if ( enabled & bitmask )
g_ptr_array_add ( args , g_strdup_printf ( " %s=%s " , enable_arg , names [ i ] ) ) ;
else
g_ptr_array_add ( args , g_strdup_printf ( " %s=%s " , disable_arg , names [ i ] ) ) ;
}
}
}
2016-05-06 14:37:47 +00:00
static FlatpakContextShares
flatpak_context_share_from_string ( const char * string , GError * * error )
2015-09-09 12:11:05 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContextShares shares = flatpak_context_bitmask_from_string ( string , flatpak_context_shares ) ;
2015-09-09 12:11:05 +00:00
if ( shares = = 0 )
2016-07-23 19:02:01 +00:00
{
g_autofree char * values = g_strjoinv ( " , " , ( char * * ) flatpak_context_shares ) ;
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Unknown share type %s, valid types are: %s " ) , string , values ) ;
}
2015-09-09 12:11:05 +00:00
return shares ;
}
static char * *
2016-05-06 14:37:47 +00:00
flatpak_context_shared_to_string ( FlatpakContextShares shares , FlatpakContextShares valid )
2015-09-09 12:11:05 +00:00
{
2016-05-06 14:37:47 +00:00
return flatpak_context_bitmask_to_string ( shares , valid , flatpak_context_shares ) ;
2015-09-09 12:11:05 +00:00
}
2016-05-26 10:23:48 +00:00
static void
flatpak_context_shared_to_args ( FlatpakContextShares shares ,
FlatpakContextShares valid ,
GPtrArray * args )
{
return flatpak_context_bitmask_to_args ( shares , valid , flatpak_context_shares , " --share " , " --unshare " , args ) ;
}
2016-05-06 14:37:47 +00:00
static FlatpakPolicy
flatpak_policy_from_string ( const char * string , GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-07-23 19:02:01 +00:00
const char * policies [ ] = { " none " , " see " , " talk " , " own " , NULL } ;
int i ;
g_autofree char * values = NULL ;
for ( i = 0 ; policies [ i ] ; i + + )
{
if ( strcmp ( string , policies [ i ] ) = = 0 )
return i ;
}
2015-05-22 13:36:52 +00:00
2016-07-23 19:02:01 +00:00
values = g_strjoinv ( " , " , ( char * * ) policies ) ;
2015-05-22 13:36:52 +00:00
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
2016-07-23 19:02:01 +00:00
_ ( " Unknown policy type %s, valid types are: %s " ) , string , values ) ;
2015-05-22 13:36:52 +00:00
return - 1 ;
}
static const char *
2016-05-06 14:37:47 +00:00
flatpak_policy_to_string ( FlatpakPolicy policy )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
if ( policy = = FLATPAK_POLICY_SEE )
2015-05-22 13:36:52 +00:00
return " see " ;
2016-05-06 14:37:47 +00:00
if ( policy = = FLATPAK_POLICY_TALK )
2015-05-22 13:36:52 +00:00
return " talk " ;
2016-05-06 14:37:47 +00:00
if ( policy = = FLATPAK_POLICY_OWN )
2015-05-22 13:36:52 +00:00
return " own " ;
return " none " ;
}
static gboolean
2016-05-06 14:37:47 +00:00
flatpak_verify_dbus_name ( const char * name , GError * * error )
2015-05-22 13:36:52 +00:00
{
const char * name_part ;
g_autofree char * tmp = NULL ;
if ( g_str_has_suffix ( name , " .* " ) )
{
tmp = g_strndup ( name , strlen ( name ) - 2 ) ;
name_part = tmp ;
}
else
2016-05-06 14:03:27 +00:00
{
name_part = name ;
}
2015-05-22 13:36:52 +00:00
if ( g_dbus_is_name ( name_part ) & & ! g_dbus_is_unique_name ( name_part ) )
return TRUE ;
2016-07-23 17:59:45 +00:00
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Invalid dbus name %s \n " ) , name ) ;
2015-05-22 13:36:52 +00:00
return FALSE ;
}
2016-05-06 14:37:47 +00:00
static FlatpakContextSockets
flatpak_context_socket_from_string ( const char * string , GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContextSockets sockets = flatpak_context_bitmask_from_string ( string , flatpak_context_sockets ) ;
2015-05-22 13:36:52 +00:00
2015-09-09 12:11:05 +00:00
if ( sockets = = 0 )
2016-07-23 19:02:01 +00:00
{
g_autofree char * values = g_strjoinv ( " , " , ( char * * ) flatpak_context_sockets ) ;
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Unknown socket type %s, valid types are: %s " ) , string , values ) ;
}
2015-09-09 12:11:05 +00:00
return sockets ;
2015-05-22 13:36:52 +00:00
}
static char * *
2016-05-06 14:37:47 +00:00
flatpak_context_sockets_to_string ( FlatpakContextSockets sockets , FlatpakContextSockets valid )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
return flatpak_context_bitmask_to_string ( sockets , valid , flatpak_context_sockets ) ;
2015-05-22 13:36:52 +00:00
}
2016-05-26 10:23:48 +00:00
static void
flatpak_context_sockets_to_args ( FlatpakContextSockets sockets ,
FlatpakContextSockets valid ,
GPtrArray * args )
{
return flatpak_context_bitmask_to_args ( sockets , valid , flatpak_context_sockets , " --socket " , " --nosocket " , args ) ;
}
2016-05-06 14:37:47 +00:00
static FlatpakContextDevices
flatpak_context_device_from_string ( const char * string , GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContextDevices devices = flatpak_context_bitmask_from_string ( string , flatpak_context_devices ) ;
2015-05-22 13:36:52 +00:00
2015-09-09 12:11:05 +00:00
if ( devices = = 0 )
2016-07-23 19:02:01 +00:00
{
g_autofree char * values = g_strjoinv ( " , " , ( char * * ) flatpak_context_devices ) ;
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Unknown device type %s, valid types are: %s " ) , string , values ) ;
}
2015-09-09 12:11:05 +00:00
return devices ;
2015-05-22 13:36:52 +00:00
}
static char * *
2016-05-06 14:37:47 +00:00
flatpak_context_devices_to_string ( FlatpakContextDevices devices , FlatpakContextDevices valid )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
return flatpak_context_bitmask_to_string ( devices , valid , flatpak_context_devices ) ;
2015-05-22 13:36:52 +00:00
}
2016-05-26 10:23:48 +00:00
static void
flatpak_context_devices_to_args ( FlatpakContextDevices devices ,
FlatpakContextDevices valid ,
GPtrArray * args )
{
return flatpak_context_bitmask_to_args ( devices , valid , flatpak_context_devices , " --device " , " --nodevice " , args ) ;
}
2016-09-05 19:22:20 +00:00
static FlatpakContextFeatures
flatpak_context_feature_from_string ( const char * string , GError * * error )
{
FlatpakContextFeatures feature = flatpak_context_bitmask_from_string ( string , flatpak_context_features ) ;
if ( feature = = 0 )
{
g_autofree char * values = g_strjoinv ( " , " , ( char * * ) flatpak_context_features ) ;
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Unknown feature type %s, valid types are: %s " ) , string , values ) ;
}
return feature ;
}
static char * *
flatpak_context_features_to_string ( FlatpakContextFeatures features , FlatpakContextFeatures valid )
{
return flatpak_context_bitmask_to_string ( features , valid , flatpak_context_features ) ;
}
static void
flatpak_context_features_to_args ( FlatpakContextFeatures features ,
FlatpakContextFeatures valid ,
GPtrArray * args )
{
return flatpak_context_bitmask_to_args ( features , valid , flatpak_context_features , " --allow " , " --disallow " , args ) ;
}
2015-05-22 13:36:52 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_context_add_shares ( FlatpakContext * context ,
FlatpakContextShares shares )
2015-05-22 13:36:52 +00:00
{
context - > shares_valid | = shares ;
context - > shares | = shares ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_remove_shares ( FlatpakContext * context ,
FlatpakContextShares shares )
2015-05-22 13:36:52 +00:00
{
context - > shares_valid | = shares ;
context - > shares & = ~ shares ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_add_sockets ( FlatpakContext * context ,
FlatpakContextSockets sockets )
2015-05-22 13:36:52 +00:00
{
context - > sockets_valid | = sockets ;
context - > sockets | = sockets ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_remove_sockets ( FlatpakContext * context ,
FlatpakContextSockets sockets )
2015-05-22 13:36:52 +00:00
{
context - > sockets_valid | = sockets ;
context - > sockets & = ~ sockets ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_add_devices ( FlatpakContext * context ,
FlatpakContextDevices devices )
2015-05-22 13:36:52 +00:00
{
context - > devices_valid | = devices ;
context - > devices | = devices ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_remove_devices ( FlatpakContext * context ,
FlatpakContextDevices devices )
2015-05-22 13:36:52 +00:00
{
context - > devices_valid | = devices ;
context - > devices & = ~ devices ;
}
2016-09-05 19:22:20 +00:00
static void
flatpak_context_add_features ( FlatpakContext * context ,
FlatpakContextFeatures features )
{
context - > features_valid | = features ;
context - > features | = features ;
}
static void
flatpak_context_remove_features ( FlatpakContext * context ,
FlatpakContextFeatures features )
{
context - > features_valid | = features ;
context - > features & = ~ features ;
}
2015-05-22 13:36:52 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_context_set_env_var ( FlatpakContext * context ,
const char * name ,
const char * value )
2015-05-22 13:36:52 +00:00
{
g_hash_table_insert ( context - > env_vars , g_strdup ( name ) , g_strdup ( value ) ) ;
}
2015-10-21 10:18:13 +00:00
void
2016-05-06 14:37:47 +00:00
flatpak_context_set_session_bus_policy ( FlatpakContext * context ,
const char * name ,
FlatpakPolicy policy )
2015-05-22 13:36:52 +00:00
{
2016-01-29 07:50:11 +00:00
g_hash_table_insert ( context - > session_bus_policy , g_strdup ( name ) , GINT_TO_POINTER ( policy ) ) ;
}
void
2016-05-06 14:37:47 +00:00
flatpak_context_set_system_bus_policy ( FlatpakContext * context ,
const char * name ,
FlatpakPolicy policy )
2016-01-29 07:50:11 +00:00
{
g_hash_table_insert ( context - > system_bus_policy , g_strdup ( name ) , GINT_TO_POINTER ( policy ) ) ;
2015-05-22 13:36:52 +00:00
}
2017-03-22 18:50:48 +00:00
static void
2016-10-19 18:39:17 +00:00
flatpak_context_apply_generic_policy ( FlatpakContext * context ,
const char * key ,
const char * value )
{
GPtrArray * new = g_ptr_array_new ( ) ;
const char * * old_v ;
int i ;
g_assert ( strchr ( key , ' . ' ) ! = NULL ) ;
old_v = g_hash_table_lookup ( context - > generic_policy , key ) ;
for ( i = 0 ; old_v ! = NULL & & old_v [ i ] ! = NULL ; i + + )
{
const char * old = old_v [ i ] ;
const char * cmp1 = old ;
const char * cmp2 = value ;
if ( * cmp1 = = ' ! ' )
cmp1 + + ;
if ( * cmp2 = = ' ! ' )
cmp2 + + ;
if ( strcmp ( cmp1 , cmp2 ) ! = 0 )
g_ptr_array_add ( new , g_strdup ( old ) ) ;
}
g_ptr_array_add ( new , g_strdup ( value ) ) ;
g_ptr_array_add ( new , NULL ) ;
g_hash_table_insert ( context - > generic_policy , g_strdup ( key ) ,
g_ptr_array_free ( new , FALSE ) ) ;
}
2015-05-22 13:36:52 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_context_set_persistent ( FlatpakContext * context ,
const char * path )
2015-05-22 13:36:52 +00:00
{
g_hash_table_insert ( context - > persistent , g_strdup ( path ) , GINT_TO_POINTER ( 1 ) ) ;
}
2016-04-20 12:26:03 +00:00
static gboolean
2016-11-14 10:04:38 +00:00
get_xdg_dir_from_prefix ( const char * prefix ,
2016-11-14 17:50:49 +00:00
const char * * where ,
2016-11-14 10:04:38 +00:00
const char * * dir )
{
if ( strcmp ( prefix , " xdg-data " ) = = 0 )
{
2016-11-14 17:50:49 +00:00
if ( where )
* where = " data " ;
2016-11-14 10:04:38 +00:00
if ( dir )
* dir = g_get_user_data_dir ( ) ;
return TRUE ;
}
if ( strcmp ( prefix , " xdg-cache " ) = = 0 )
{
2016-11-14 17:50:49 +00:00
if ( where )
* where = " cache " ;
2016-11-14 10:04:38 +00:00
if ( dir )
* dir = g_get_user_cache_dir ( ) ;
return TRUE ;
}
if ( strcmp ( prefix , " xdg-config " ) = = 0 )
{
2016-11-14 17:50:49 +00:00
if ( where )
* where = " config " ;
2016-11-14 10:04:38 +00:00
if ( dir )
* dir = g_get_user_config_dir ( ) ;
return TRUE ;
}
return FALSE ;
}
2016-11-14 17:50:49 +00:00
/* This looks only in the xdg dirs (config, cache, data), not the user
definable ones */
static char *
get_xdg_dir_from_string ( const char * filesystem ,
const char * * suffix ,
const char * * where )
{
char * slash ;
const char * rest ;
2017-01-18 22:46:55 +00:00
g_autofree char * prefix = NULL ;
2016-11-14 17:50:49 +00:00
const char * dir = NULL ;
gsize len ;
slash = strchr ( filesystem , ' / ' ) ;
if ( slash )
len = slash - filesystem ;
else
len = strlen ( filesystem ) ;
rest = filesystem + len ;
while ( * rest = = ' / ' )
rest + + ;
if ( suffix ! = NULL )
* suffix = rest ;
prefix = g_strndup ( filesystem , len ) ;
if ( get_xdg_dir_from_prefix ( prefix , where , & dir ) )
return g_build_filename ( dir , rest , NULL ) ;
return NULL ;
}
2016-11-14 10:04:38 +00:00
static gboolean
get_xdg_user_dir_from_string ( const char * filesystem ,
const char * * config_key ,
const char * * suffix ,
const char * * dir )
2015-05-25 13:28:29 +00:00
{
2016-02-25 15:51:45 +00:00
char * slash ;
2016-02-25 16:11:37 +00:00
const char * rest ;
2017-01-18 22:46:55 +00:00
g_autofree char * prefix = NULL ;
2016-02-25 15:51:45 +00:00
gsize len ;
slash = strchr ( filesystem , ' / ' ) ;
if ( slash )
len = slash - filesystem ;
else
len = strlen ( filesystem ) ;
2016-02-25 16:11:37 +00:00
rest = filesystem + len ;
while ( * rest = = ' / ' )
2016-05-06 14:03:27 +00:00
rest + + ;
2016-02-25 16:11:37 +00:00
2016-02-25 15:51:45 +00:00
if ( suffix )
2016-02-25 16:11:37 +00:00
* suffix = rest ;
2016-02-25 15:51:45 +00:00
prefix = g_strndup ( filesystem , len ) ;
if ( strcmp ( prefix , " xdg-desktop " ) = = 0 )
2016-02-25 16:11:37 +00:00
{
if ( config_key )
* config_key = " XDG_DESKTOP_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_DESKTOP ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
2016-02-25 15:51:45 +00:00
if ( strcmp ( prefix , " xdg-documents " ) = = 0 )
2016-02-25 16:11:37 +00:00
{
if ( config_key )
* config_key = " XDG_DOCUMENTS_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_DOCUMENTS ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
2016-02-25 15:51:45 +00:00
if ( strcmp ( prefix , " xdg-download " ) = = 0 )
2016-02-25 16:11:37 +00:00
{
if ( config_key )
* config_key = " XDG_DOWNLOAD_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_DOWNLOAD ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
if ( strcmp ( prefix , " xdg-music " ) = = 0 )
{
if ( config_key )
* config_key = " XDG_MUSIC_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_MUSIC ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
if ( strcmp ( prefix , " xdg-pictures " ) = = 0 )
{
if ( config_key )
* config_key = " XDG_PICTURES_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_PICTURES ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
if ( strcmp ( prefix , " xdg-public-share " ) = = 0 )
{
if ( config_key )
* config_key = " XDG_PUBLICSHARE_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_PUBLIC_SHARE ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
if ( strcmp ( prefix , " xdg-templates " ) = = 0 )
{
if ( config_key )
* config_key = " XDG_TEMPLATES_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_TEMPLATES ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
if ( strcmp ( prefix , " xdg-videos " ) = = 0 )
{
if ( config_key )
* config_key = " XDG_VIDEOS_DIR " ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_special_dir ( G_USER_DIRECTORY_VIDEOS ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
2016-11-14 17:50:49 +00:00
if ( get_xdg_dir_from_prefix ( prefix , NULL , dir ) )
2016-11-14 10:04:38 +00:00
{
if ( config_key )
* config_key = NULL ;
return TRUE ;
}
2016-02-25 16:11:37 +00:00
/* Don't support xdg-run without suffix, because that doesn't work */
if ( strcmp ( prefix , " xdg-run " ) = = 0 & &
* rest ! = 0 )
{
if ( config_key )
* config_key = NULL ;
2016-04-20 12:26:03 +00:00
if ( dir )
* dir = g_get_user_runtime_dir ( ) ;
return TRUE ;
2016-02-25 16:11:37 +00:00
}
2015-05-25 13:28:29 +00:00
2016-04-21 07:39:55 +00:00
return FALSE ;
2015-05-25 13:28:29 +00:00
}
2015-11-26 16:22:37 +00:00
static char *
2016-05-06 14:37:47 +00:00
parse_filesystem_flags ( const char * filesystem , FlatpakFilesystemMode * mode )
2015-11-26 16:22:37 +00:00
{
gsize len = strlen ( filesystem ) ;
if ( mode )
2016-05-06 14:37:47 +00:00
* mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE ;
2015-11-26 16:22:37 +00:00
if ( g_str_has_suffix ( filesystem , " :ro " ) )
{
len - = 3 ;
if ( mode )
2016-05-06 14:37:47 +00:00
* mode = FLATPAK_FILESYSTEM_MODE_READ_ONLY ;
2015-11-26 16:22:37 +00:00
}
else if ( g_str_has_suffix ( filesystem , " :rw " ) )
{
len - = 3 ;
if ( mode )
2016-05-06 14:37:47 +00:00
* mode = FLATPAK_FILESYSTEM_MODE_READ_WRITE ;
2015-11-26 16:22:37 +00:00
}
2016-11-14 09:58:39 +00:00
else if ( g_str_has_suffix ( filesystem , " :create " ) )
{
len - = 7 ;
if ( mode )
* mode = FLATPAK_FILESYSTEM_MODE_CREATE ;
}
2015-11-26 16:22:37 +00:00
return g_strndup ( filesystem , len ) ;
}
2015-05-22 13:36:52 +00:00
static gboolean
2016-05-06 14:37:47 +00:00
flatpak_context_verify_filesystem ( const char * filesystem_and_mode ,
2016-05-06 14:03:27 +00:00
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-02-25 15:51:45 +00:00
g_autofree char * filesystem = parse_filesystem_flags ( filesystem_and_mode , NULL ) ;
2015-11-26 16:22:37 +00:00
2015-05-22 13:36:52 +00:00
if ( strcmp ( filesystem , " host " ) = = 0 )
return TRUE ;
if ( strcmp ( filesystem , " home " ) = = 0 )
return TRUE ;
2016-11-14 10:04:38 +00:00
if ( get_xdg_user_dir_from_string ( filesystem , NULL , NULL , NULL ) )
2015-05-22 13:36:52 +00:00
return TRUE ;
if ( g_str_has_prefix ( filesystem , " ~/ " ) )
return TRUE ;
if ( g_str_has_prefix ( filesystem , " / " ) )
return TRUE ;
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
2016-07-23 19:02:01 +00:00
_ ( " Unknown filesystem location %s, valid types are: host, home, xdg-*[/...], ~/dir, /dir " ) , filesystem ) ;
2015-05-22 13:36:52 +00:00
return FALSE ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_context_add_filesystem ( FlatpakContext * context ,
const char * what )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakFilesystemMode mode ;
2015-11-26 16:22:37 +00:00
char * fs = parse_filesystem_flags ( what , & mode ) ;
g_hash_table_insert ( context - > filesystems , fs , GINT_TO_POINTER ( mode ) ) ;
2015-05-22 13:36:52 +00:00
}
2015-09-09 12:11:05 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_context_remove_filesystem ( FlatpakContext * context ,
const char * what )
2015-09-09 12:11:05 +00:00
{
2015-11-26 16:22:37 +00:00
g_hash_table_insert ( context - > filesystems ,
parse_filesystem_flags ( what , NULL ) ,
NULL ) ;
2015-09-09 12:11:05 +00:00
}
2015-05-22 13:36:52 +00:00
void
2016-05-06 14:37:47 +00:00
flatpak_context_merge ( FlatpakContext * context ,
FlatpakContext * other )
2015-05-22 13:36:52 +00:00
{
GHashTableIter iter ;
gpointer key , value ;
context - > shares & = ~ other - > shares_valid ;
context - > shares | = other - > shares ;
2015-09-09 12:11:05 +00:00
context - > shares_valid | = other - > shares_valid ;
2015-05-22 13:36:52 +00:00
context - > sockets & = ~ other - > sockets_valid ;
context - > sockets | = other - > sockets ;
2015-09-09 12:11:05 +00:00
context - > sockets_valid | = other - > sockets_valid ;
2015-05-22 13:36:52 +00:00
context - > devices & = ~ other - > devices_valid ;
context - > devices | = other - > devices ;
2015-09-09 12:11:05 +00:00
context - > devices_valid | = other - > devices_valid ;
2016-09-05 19:22:20 +00:00
context - > features & = ~ other - > features_valid ;
context - > features | = other - > features ;
context - > features_valid | = other - > features_valid ;
2015-05-22 13:36:52 +00:00
g_hash_table_iter_init ( & iter , other - > env_vars ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_hash_table_insert ( context - > env_vars , g_strdup ( key ) , g_strdup ( value ) ) ;
g_hash_table_iter_init ( & iter , other - > persistent ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_hash_table_insert ( context - > persistent , g_strdup ( key ) , value ) ;
g_hash_table_iter_init ( & iter , other - > filesystems ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_hash_table_insert ( context - > filesystems , g_strdup ( key ) , value ) ;
2016-01-29 07:50:11 +00:00
g_hash_table_iter_init ( & iter , other - > session_bus_policy ) ;
2015-05-22 13:36:52 +00:00
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
2016-01-29 07:50:11 +00:00
g_hash_table_insert ( context - > session_bus_policy , g_strdup ( key ) , value ) ;
g_hash_table_iter_init ( & iter , other - > system_bus_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_hash_table_insert ( context - > system_bus_policy , g_strdup ( key ) , value ) ;
2016-10-19 18:39:17 +00:00
g_hash_table_iter_init ( & iter , other - > system_bus_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_hash_table_insert ( context - > system_bus_policy , g_strdup ( key ) , value ) ;
g_hash_table_iter_init ( & iter , other - > generic_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
const char * * policy_values = ( const char * * ) value ;
int i ;
for ( i = 0 ; policy_values [ i ] ! = NULL ; i + + )
flatpak_context_apply_generic_policy ( context , ( char * ) key , policy_values [ i ] ) ;
}
2015-05-22 13:36:52 +00:00
}
static gboolean
2016-05-06 14:03:27 +00:00
option_share_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextShares share ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
share = flatpak_context_share_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( share = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_add_shares ( context , share ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_unshare_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextShares share ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
share = flatpak_context_share_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( share = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_remove_shares ( context , share ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_socket_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextSockets socket ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
socket = flatpak_context_socket_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( socket = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_add_sockets ( context , socket ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_nosocket_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextSockets socket ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
socket = flatpak_context_socket_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( socket = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_remove_sockets ( context , socket ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_device_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextDevices device ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
device = flatpak_context_device_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( device = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_add_devices ( context , device ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_nodevice_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
FlatpakContextDevices device ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
device = flatpak_context_device_from_string ( value , error ) ;
2015-05-22 13:36:52 +00:00
if ( device = = 0 )
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_remove_devices ( context , device ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
2016-09-05 19:22:20 +00:00
static gboolean
option_allow_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
{
FlatpakContext * context = data ;
FlatpakContextFeatures feature ;
feature = flatpak_context_feature_from_string ( value , error ) ;
if ( feature = = 0 )
return FALSE ;
flatpak_context_add_features ( context , feature ) ;
return TRUE ;
}
static gboolean
option_disallow_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
{
FlatpakContext * context = data ;
FlatpakContextFeatures feature ;
feature = flatpak_context_feature_from_string ( value , error ) ;
if ( feature = = 0 )
return FALSE ;
flatpak_context_remove_features ( context , feature ) ;
return TRUE ;
}
2015-05-22 13:36:52 +00:00
static gboolean
2016-05-06 14:03:27 +00:00
option_filesystem_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_context_verify_filesystem ( value , error ) )
2015-05-22 13:36:52 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_add_filesystem ( context , value ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
2015-09-25 15:04:50 +00:00
static gboolean
2016-05-06 14:03:27 +00:00
option_nofilesystem_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-09-25 15:04:50 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2015-09-25 15:04:50 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_context_verify_filesystem ( value , error ) )
2015-09-25 15:04:50 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_remove_filesystem ( context , value ) ;
2015-09-25 15:04:50 +00:00
return TRUE ;
}
2015-05-22 13:36:52 +00:00
static gboolean
2016-05-06 14:03:27 +00:00
option_env_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2016-05-06 14:03:27 +00:00
2015-08-31 07:51:48 +00:00
g_auto ( GStrv ) split = g_strsplit ( value , " = " , 2 ) ;
2015-05-22 13:36:52 +00:00
if ( split = = NULL | | split [ 0 ] = = NULL | | split [ 0 ] [ 0 ] = = 0 | | split [ 1 ] = = NULL )
{
2016-07-23 17:59:45 +00:00
g_set_error ( error , G_OPTION_ERROR , G_OPTION_ERROR_FAILED ,
_ ( " Invalid env format %s " ) , value ) ;
2015-05-22 13:36:52 +00:00
return FALSE ;
}
2016-05-06 14:37:47 +00:00
flatpak_context_set_env_var ( context , split [ 0 ] , split [ 1 ] ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_own_name_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( value , error ) )
2015-05-22 13:36:52 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_session_bus_policy ( context , value , FLATPAK_POLICY_OWN ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_talk_name_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( value , error ) )
2015-05-22 13:36:52 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_session_bus_policy ( context , value , FLATPAK_POLICY_TALK ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
2016-01-29 07:50:11 +00:00
static gboolean
2016-05-06 14:03:27 +00:00
option_system_own_name_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2016-01-29 07:50:11 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2016-01-29 07:50:11 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( value , error ) )
2016-01-29 07:50:11 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_system_bus_policy ( context , value , FLATPAK_POLICY_OWN ) ;
2016-01-29 07:50:11 +00:00
return TRUE ;
}
static gboolean
2016-05-06 14:03:27 +00:00
option_system_talk_name_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2016-01-29 07:50:11 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2016-01-29 07:50:11 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( value , error ) )
2016-01-29 07:50:11 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_system_bus_policy ( context , value , FLATPAK_POLICY_TALK ) ;
2016-01-29 07:50:11 +00:00
return TRUE ;
}
2016-10-19 18:39:17 +00:00
static gboolean
option_add_generic_policy_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
{
FlatpakContext * context = data ;
char * t ;
g_autofree char * key = NULL ;
const char * policy_value ;
t = strchr ( value , ' = ' ) ;
if ( t = = NULL )
return flatpak_fail ( error , " --policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE " ) ;
policy_value = t + 1 ;
key = g_strndup ( value , t - value ) ;
if ( strchr ( key , ' . ' ) = = NULL )
return flatpak_fail ( error , " --policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE " ) ;
if ( policy_value [ 0 ] = = ' ! ' )
return flatpak_fail ( error , " --policy values can't start with \" ! \" " ) ;
flatpak_context_apply_generic_policy ( context , key , policy_value ) ;
return TRUE ;
}
static gboolean
option_remove_generic_policy_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
{
FlatpakContext * context = data ;
char * t ;
g_autofree char * key = NULL ;
const char * policy_value ;
g_autofree char * extended_value = NULL ;
t = strchr ( value , ' = ' ) ;
if ( t = = NULL )
return flatpak_fail ( error , " --policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE " ) ;
policy_value = t + 1 ;
key = g_strndup ( value , t - value ) ;
if ( strchr ( key , ' . ' ) = = NULL )
return flatpak_fail ( error , " --policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE " ) ;
if ( policy_value [ 0 ] = = ' ! ' )
return flatpak_fail ( error , " --policy values can't start with \" ! \" " ) ;
extended_value = g_strconcat ( " ! " , policy_value , NULL ) ;
flatpak_context_apply_generic_policy ( context , key , extended_value ) ;
return TRUE ;
}
2015-05-22 13:36:52 +00:00
static gboolean
2016-05-06 14:03:27 +00:00
option_persist_cb ( const gchar * option_name ,
const gchar * value ,
gpointer data ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakContext * context = data ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
flatpak_context_set_persistent ( context , value ) ;
2015-05-22 13:36:52 +00:00
return TRUE ;
}
2016-09-08 09:38:05 +00:00
static gboolean option_no_desktop_deprecated ;
2016-07-01 17:33:53 +00:00
2015-05-22 13:36:52 +00:00
static GOptionEntry context_options [ ] = {
2016-07-23 15:01:50 +00:00
{ " share " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_share_cb , N_ ( " Share with host " ) , N_ ( " SHARE " ) } ,
{ " unshare " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_unshare_cb , N_ ( " Unshare with host " ) , N_ ( " SHARE " ) } ,
{ " socket " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_socket_cb , N_ ( " Expose socket to app " ) , N_ ( " SOCKET " ) } ,
{ " nosocket " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_nosocket_cb , N_ ( " Don't expose socket to app " ) , N_ ( " SOCKET " ) } ,
{ " device " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_device_cb , N_ ( " Expose device to app " ) , N_ ( " DEVICE " ) } ,
{ " nodevice " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_nodevice_cb , N_ ( " Don't expose device to app " ) , N_ ( " DEVICE " ) } ,
2016-09-05 19:22:20 +00:00
{ " allow " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_allow_cb , N_ ( " Allow feature " ) , N_ ( " FEATURE " ) } ,
{ " disallow " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_disallow_cb , N_ ( " Don't allow feature " ) , N_ ( " FEATURE " ) } ,
2016-07-23 15:01:50 +00:00
{ " filesystem " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_filesystem_cb , N_ ( " Expose filesystem to app (:ro for read-only) " ) , N_ ( " FILESYSTEM[:ro] " ) } ,
{ " nofilesystem " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_nofilesystem_cb , N_ ( " Don't expose filesystem to app " ) , N_ ( " FILESYSTEM " ) } ,
{ " env " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_env_cb , N_ ( " Set environment variable " ) , N_ ( " VAR=VALUE " ) } ,
{ " own-name " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_own_name_cb , N_ ( " Allow app to own name on the session bus " ) , N_ ( " DBUS_NAME " ) } ,
{ " talk-name " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_talk_name_cb , N_ ( " Allow app to talk to name on the session bus " ) , N_ ( " DBUS_NAME " ) } ,
{ " system-own-name " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_system_own_name_cb , N_ ( " Allow app to own name on the system bus " ) , N_ ( " DBUS_NAME " ) } ,
{ " system-talk-name " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_system_talk_name_cb , N_ ( " Allow app to talk to name on the system bus " ) , N_ ( " DBUS_NAME " ) } ,
2016-10-19 18:39:17 +00:00
{ " add-policy " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_add_generic_policy_cb , N_ ( " Add generic policy option " ) , N_ ( " SUBSYSTEM.KEY=VALUE " ) } ,
{ " remove-policy " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_remove_generic_policy_cb , N_ ( " Remove generic policy option " ) , N_ ( " SUBSYSTEM.KEY=VALUE " ) } ,
2016-07-23 15:01:50 +00:00
{ " persist " , 0 , G_OPTION_FLAG_IN_MAIN , G_OPTION_ARG_CALLBACK , & option_persist_cb , N_ ( " Persist home directory " ) , N_ ( " FILENAME " ) } ,
2016-09-08 09:38:05 +00:00
/* This is not needed/used anymore, so hidden, but we accept it for backwards compat */
{ " no-desktop " , 0 , G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_HIDDEN , G_OPTION_ARG_NONE , & option_no_desktop_deprecated , N_ ( " Don't require a running session (no cgroups creation) " ) , NULL } ,
2015-05-22 13:36:52 +00:00
{ NULL }
} ;
2016-05-27 14:30:13 +00:00
void
flatpak_context_complete ( FlatpakContext * context , FlatpakCompletion * completion )
{
flatpak_complete_options ( completion , context_options ) ;
}
2015-05-22 13:36:52 +00:00
GOptionGroup *
2016-05-06 14:37:47 +00:00
flatpak_context_get_options ( FlatpakContext * context )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:03:27 +00:00
GOptionGroup * group ;
2015-05-22 13:36:52 +00:00
group = g_option_group_new ( " environment " ,
" Runtime Environment " ,
" Runtime Environment " ,
context ,
NULL ) ;
2016-07-23 15:01:50 +00:00
g_option_group_set_translation_domain ( group , GETTEXT_PACKAGE ) ;
2015-05-22 13:36:52 +00:00
g_option_group_add_entries ( group , context_options ) ;
return group ;
}
2015-09-09 12:11:05 +00:00
static const char *
parse_negated ( const char * option , gboolean * negated )
{
if ( option [ 0 ] = = ' ! ' )
{
option + + ;
* negated = TRUE ;
}
else
2016-05-06 14:03:27 +00:00
{
* negated = FALSE ;
}
2015-09-09 12:11:05 +00:00
return option ;
}
2015-05-22 13:36:52 +00:00
/* This is a merge, not a replace */
gboolean
2016-05-06 14:37:47 +00:00
flatpak_context_load_metadata ( FlatpakContext * context ,
GKeyFile * metakey ,
GError * * error )
2015-05-22 13:36:52 +00:00
{
2015-09-09 12:11:05 +00:00
gboolean remove ;
2016-10-19 18:39:17 +00:00
g_auto ( GStrv ) groups = NULL ;
2015-05-22 13:36:52 +00:00
int i ;
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_SHARED , NULL ) )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
g_auto ( GStrv ) shares = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SHARED , NULL , error ) ;
2015-05-22 13:36:52 +00:00
if ( shares = = NULL )
return FALSE ;
for ( i = 0 ; shares [ i ] ! = NULL ; i + + )
{
2016-05-06 14:37:47 +00:00
FlatpakContextShares share ;
2015-09-09 12:11:05 +00:00
2016-05-06 14:37:47 +00:00
share = flatpak_context_share_from_string ( parse_negated ( shares [ i ] , & remove ) , error ) ;
2015-05-22 13:36:52 +00:00
if ( share = = 0 )
return FALSE ;
2015-09-09 12:11:05 +00:00
if ( remove )
2016-05-06 14:37:47 +00:00
flatpak_context_remove_shares ( context , share ) ;
2015-09-09 12:11:05 +00:00
else
2016-05-06 14:37:47 +00:00
flatpak_context_add_shares ( context , share ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_SOCKETS , NULL ) )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
g_auto ( GStrv ) sockets = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SOCKETS , NULL , error ) ;
2015-05-22 13:36:52 +00:00
if ( sockets = = NULL )
return FALSE ;
for ( i = 0 ; sockets [ i ] ! = NULL ; i + + )
{
2016-05-06 14:37:47 +00:00
FlatpakContextSockets socket = flatpak_context_socket_from_string ( parse_negated ( sockets [ i ] , & remove ) , error ) ;
2015-05-22 13:36:52 +00:00
if ( socket = = 0 )
return FALSE ;
2015-09-09 12:11:05 +00:00
if ( remove )
2016-05-06 14:37:47 +00:00
flatpak_context_remove_sockets ( context , socket ) ;
2015-09-09 12:11:05 +00:00
else
2016-05-06 14:37:47 +00:00
flatpak_context_add_sockets ( context , socket ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_DEVICES , NULL ) )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
g_auto ( GStrv ) devices = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_DEVICES , NULL , error ) ;
2015-05-22 13:36:52 +00:00
if ( devices = = NULL )
return FALSE ;
for ( i = 0 ; devices [ i ] ! = NULL ; i + + )
{
2016-05-06 14:37:47 +00:00
FlatpakContextDevices device = flatpak_context_device_from_string ( parse_negated ( devices [ i ] , & remove ) , error ) ;
2015-05-22 13:36:52 +00:00
if ( device = = 0 )
return FALSE ;
2015-09-09 12:11:05 +00:00
if ( remove )
2016-05-06 14:37:47 +00:00
flatpak_context_remove_devices ( context , device ) ;
2015-09-09 12:11:05 +00:00
else
2016-05-06 14:37:47 +00:00
flatpak_context_add_devices ( context , device ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-09-05 19:22:20 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_FEATURES , NULL ) )
{
g_auto ( GStrv ) features = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FEATURES , NULL , error ) ;
if ( features = = NULL )
return FALSE ;
for ( i = 0 ; features [ i ] ! = NULL ; i + + )
{
FlatpakContextFeatures feature = flatpak_context_feature_from_string ( parse_negated ( features [ i ] , & remove ) , error ) ;
if ( feature = = 0 )
return FALSE ;
if ( remove )
flatpak_context_remove_features ( context , feature ) ;
else
flatpak_context_add_features ( context , feature ) ;
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_FILESYSTEMS , NULL ) )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
g_auto ( GStrv ) filesystems = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FILESYSTEMS , NULL , error ) ;
2015-05-22 13:36:52 +00:00
if ( filesystems = = NULL )
return FALSE ;
for ( i = 0 ; filesystems [ i ] ! = NULL ; i + + )
{
2015-09-09 12:11:05 +00:00
const char * fs = parse_negated ( filesystems [ i ] , & remove ) ;
2016-05-06 14:37:47 +00:00
if ( ! flatpak_context_verify_filesystem ( fs , error ) )
2015-05-22 13:36:52 +00:00
return FALSE ;
2015-09-09 12:11:05 +00:00
if ( remove )
2016-05-06 14:37:47 +00:00
flatpak_context_remove_filesystem ( context , fs ) ;
2015-09-23 11:53:04 +00:00
else
2016-05-06 14:37:47 +00:00
flatpak_context_add_filesystem ( context , fs ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_key ( metakey , FLATPAK_METADATA_GROUP_CONTEXT , FLATPAK_METADATA_KEY_PERSISTENT , NULL ) )
2015-05-22 13:36:52 +00:00
{
2016-05-06 14:37:47 +00:00
g_auto ( GStrv ) persistent = g_key_file_get_string_list ( metakey , FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_PERSISTENT , NULL , error ) ;
2015-05-22 13:36:52 +00:00
if ( persistent = = NULL )
return FALSE ;
for ( i = 0 ; persistent [ i ] ! = NULL ; i + + )
2016-05-06 14:37:47 +00:00
flatpak_context_set_persistent ( context , persistent [ i ] ) ;
2015-05-22 13:36:52 +00:00
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_group ( metakey , FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY ) )
2015-05-22 13:36:52 +00:00
{
2015-08-31 07:51:48 +00:00
g_auto ( GStrv ) keys = NULL ;
2015-05-22 13:36:52 +00:00
gsize i , keys_count ;
2016-05-06 14:37:47 +00:00
keys = g_key_file_get_keys ( metakey , FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY , & keys_count , NULL ) ;
2015-05-22 13:36:52 +00:00
for ( i = 0 ; i < keys_count ; i + + )
{
const char * key = keys [ i ] ;
2016-05-06 14:37:47 +00:00
g_autofree char * value = g_key_file_get_string ( metakey , FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY , key , NULL ) ;
FlatpakPolicy policy ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( key , error ) )
2015-05-22 13:36:52 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
policy = flatpak_policy_from_string ( value , error ) ;
2016-05-06 14:03:27 +00:00
if ( ( int ) policy = = - 1 )
2015-05-22 13:36:52 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_session_bus_policy ( context , key , policy ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_group ( metakey , FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY ) )
2016-01-29 07:50:11 +00:00
{
g_auto ( GStrv ) keys = NULL ;
gsize i , keys_count ;
2016-05-06 14:37:47 +00:00
keys = g_key_file_get_keys ( metakey , FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY , & keys_count , NULL ) ;
2016-01-29 07:50:11 +00:00
for ( i = 0 ; i < keys_count ; i + + )
{
const char * key = keys [ i ] ;
2016-05-06 14:37:47 +00:00
g_autofree char * value = g_key_file_get_string ( metakey , FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY , key , NULL ) ;
FlatpakPolicy policy ;
2016-01-29 07:50:11 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_verify_dbus_name ( key , error ) )
2016-01-29 07:50:11 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
policy = flatpak_policy_from_string ( value , error ) ;
2016-05-06 14:03:27 +00:00
if ( ( int ) policy = = - 1 )
2016-01-29 07:50:11 +00:00
return FALSE ;
2016-05-06 14:37:47 +00:00
flatpak_context_set_system_bus_policy ( context , key , policy ) ;
2016-01-29 07:50:11 +00:00
}
}
2016-05-06 14:37:47 +00:00
if ( g_key_file_has_group ( metakey , FLATPAK_METADATA_GROUP_ENVIRONMENT ) )
2015-05-22 13:36:52 +00:00
{
2015-08-31 07:51:48 +00:00
g_auto ( GStrv ) keys = NULL ;
2015-05-22 13:36:52 +00:00
gsize i , keys_count ;
2016-05-06 14:37:47 +00:00
keys = g_key_file_get_keys ( metakey , FLATPAK_METADATA_GROUP_ENVIRONMENT , & keys_count , NULL ) ;
2015-05-22 13:36:52 +00:00
for ( i = 0 ; i < keys_count ; i + + )
{
const char * key = keys [ i ] ;
2016-05-06 14:37:47 +00:00
g_autofree char * value = g_key_file_get_string ( metakey , FLATPAK_METADATA_GROUP_ENVIRONMENT , key , NULL ) ;
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
flatpak_context_set_env_var ( context , key , value ) ;
2015-05-22 13:36:52 +00:00
}
}
2016-10-19 18:39:17 +00:00
groups = g_key_file_get_groups ( metakey , NULL ) ;
for ( i = 0 ; groups [ i ] ! = NULL ; i + + )
{
const char * group = groups [ i ] ;
const char * subsystem ;
int j ;
if ( g_str_has_prefix ( group , FLATPAK_METADATA_GROUP_PREFIX_POLICY ) )
{
g_auto ( GStrv ) keys = NULL ;
subsystem = group + strlen ( FLATPAK_METADATA_GROUP_PREFIX_POLICY ) ;
keys = g_key_file_get_keys ( metakey , group , NULL , NULL ) ;
for ( j = 0 ; keys ! = NULL & & keys [ j ] ! = NULL ; j + + )
{
const char * key = keys [ j ] ;
g_autofree char * policy_key = g_strdup_printf ( " %s.%s " , subsystem , key ) ;
g_auto ( GStrv ) values = NULL ;
int k ;
values = g_key_file_get_string_list ( metakey , group , key , NULL , NULL ) ;
for ( k = 0 ; values ! = NULL & & values [ k ] ! = NULL ; k + + )
flatpak_context_apply_generic_policy ( context , policy_key ,
values [ k ] ) ;
}
}
}
2015-05-22 13:36:52 +00:00
return TRUE ;
}
void
2016-05-06 14:37:47 +00:00
flatpak_context_save_metadata ( FlatpakContext * context ,
2016-09-07 12:32:10 +00:00
gboolean flatten ,
2016-05-06 14:37:47 +00:00
GKeyFile * metakey )
2015-05-22 13:36:52 +00:00
{
2016-09-07 12:32:10 +00:00
g_auto ( GStrv ) shared = NULL ;
g_auto ( GStrv ) sockets = NULL ;
g_auto ( GStrv ) devices = NULL ;
g_auto ( GStrv ) features = NULL ;
2015-05-22 13:36:52 +00:00
GHashTableIter iter ;
gpointer key , value ;
2016-09-07 12:32:10 +00:00
FlatpakContextShares shares_mask = context - > shares ;
FlatpakContextShares shares_valid = context - > shares_valid ;
FlatpakContextSockets sockets_mask = context - > sockets ;
FlatpakContextSockets sockets_valid = context - > sockets_valid ;
FlatpakContextDevices devices_mask = context - > devices ;
FlatpakContextDevices devices_valid = context - > devices_valid ;
FlatpakContextFeatures features_mask = context - > features ;
FlatpakContextFeatures features_valid = context - > features ;
2016-10-19 18:39:17 +00:00
g_auto ( GStrv ) groups = NULL ;
int i ;
2016-09-07 12:32:10 +00:00
if ( flatten )
{
/* A flattened format means we don't expect this to be merged on top of
another context . In that case we never need to negate any flags .
We calculate this by removing the zero parts of the mask from the valid set .
*/
/* First we make sure only the valid parts of the mask are set, in case we
got some leftover */
shares_mask & = shares_valid ;
sockets_mask & = sockets_valid ;
devices_mask & = devices_valid ;
2016-09-12 09:11:50 +00:00
features_mask & = features_valid ;
2016-09-07 12:32:10 +00:00
/* Then just set the valid set to be the mask set */
shares_valid = shares_mask ;
sockets_valid = sockets_mask ;
devices_valid = devices_mask ;
2016-09-12 09:11:50 +00:00
features_valid = features_mask ;
2016-09-07 12:32:10 +00:00
}
shared = flatpak_context_shared_to_string ( shares_mask , shares_valid ) ;
sockets = flatpak_context_sockets_to_string ( sockets_mask , sockets_valid ) ;
devices = flatpak_context_devices_to_string ( devices_mask , devices_valid ) ;
features = flatpak_context_features_to_string ( features_mask , features_valid ) ;
2015-05-22 13:36:52 +00:00
if ( shared [ 0 ] ! = NULL )
2016-05-06 14:03:27 +00:00
{
g_key_file_set_string_list ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SHARED ,
2016-05-06 14:03:27 +00:00
( const char * const * ) shared , g_strv_length ( shared ) ) ;
}
2015-05-22 13:36:52 +00:00
else
2016-05-06 14:03:27 +00:00
{
g_key_file_remove_key ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SHARED ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2015-05-22 13:36:52 +00:00
if ( sockets [ 0 ] ! = NULL )
2016-05-06 14:03:27 +00:00
{
g_key_file_set_string_list ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SOCKETS ,
2016-05-06 14:03:27 +00:00
( const char * const * ) sockets , g_strv_length ( sockets ) ) ;
}
2015-05-22 13:36:52 +00:00
else
2016-05-06 14:03:27 +00:00
{
g_key_file_remove_key ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_SOCKETS ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2015-05-22 13:36:52 +00:00
if ( devices [ 0 ] ! = NULL )
2016-05-06 14:03:27 +00:00
{
g_key_file_set_string_list ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_DEVICES ,
2016-05-06 14:03:27 +00:00
( const char * const * ) devices , g_strv_length ( devices ) ) ;
}
2015-05-22 13:36:52 +00:00
else
2016-05-06 14:03:27 +00:00
{
g_key_file_remove_key ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_DEVICES ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2015-05-22 13:36:52 +00:00
2016-09-05 19:22:20 +00:00
if ( features [ 0 ] ! = NULL )
{
g_key_file_set_string_list ( metakey ,
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FEATURES ,
( const char * const * ) features , g_strv_length ( features ) ) ;
}
else
{
g_key_file_remove_key ( metakey ,
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FEATURES ,
NULL ) ;
}
2015-05-22 13:36:52 +00:00
if ( g_hash_table_size ( context - > filesystems ) > 0 )
{
2015-11-26 16:22:37 +00:00
g_autoptr ( GPtrArray ) array = g_ptr_array_new_with_free_func ( g_free ) ;
2015-09-09 12:11:05 +00:00
g_hash_table_iter_init ( & iter , context - > filesystems ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
2016-05-06 14:37:47 +00:00
FlatpakFilesystemMode mode = GPOINTER_TO_INT ( value ) ;
2015-11-26 16:22:37 +00:00
2016-05-06 14:37:47 +00:00
if ( mode = = FLATPAK_FILESYSTEM_MODE_READ_ONLY )
2015-11-26 16:22:37 +00:00
g_ptr_array_add ( array , g_strconcat ( key , " :ro " , NULL ) ) ;
2016-11-14 09:58:39 +00:00
else if ( mode = = FLATPAK_FILESYSTEM_MODE_CREATE )
g_ptr_array_add ( array , g_strconcat ( key , " :create " , NULL ) ) ;
2015-11-26 16:22:37 +00:00
else if ( value ! = NULL )
g_ptr_array_add ( array , g_strdup ( key ) ) ;
2015-09-09 12:11:05 +00:00
}
2015-05-22 13:36:52 +00:00
g_key_file_set_string_list ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FILESYSTEMS ,
2016-05-06 14:03:27 +00:00
( const char * const * ) array - > pdata , array - > len ) ;
2015-05-22 13:36:52 +00:00
}
else
2016-05-06 14:03:27 +00:00
{
g_key_file_remove_key ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_FILESYSTEMS ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2015-05-22 13:36:52 +00:00
if ( g_hash_table_size ( context - > persistent ) > 0 )
{
2016-05-06 14:03:27 +00:00
g_autofree char * * keys = ( char * * ) g_hash_table_get_keys_as_array ( context - > persistent , NULL ) ;
2015-05-22 13:36:52 +00:00
g_key_file_set_string_list ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_PERSISTENT ,
2016-05-06 14:03:27 +00:00
( const char * const * ) keys , g_strv_length ( keys ) ) ;
2015-05-22 13:36:52 +00:00
}
else
2016-05-06 14:03:27 +00:00
{
g_key_file_remove_key ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_CONTEXT ,
FLATPAK_METADATA_KEY_PERSISTENT ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2015-05-22 13:36:52 +00:00
2016-05-06 14:37:47 +00:00
g_key_file_remove_group ( metakey , FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY , NULL ) ;
2016-01-29 07:50:11 +00:00
g_hash_table_iter_init ( & iter , context - > session_bus_policy ) ;
2015-05-22 13:36:52 +00:00
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
2016-05-06 14:37:47 +00:00
FlatpakPolicy policy = GPOINTER_TO_INT ( value ) ;
2015-05-22 13:36:52 +00:00
if ( policy > 0 )
g_key_file_set_string ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY ,
( char * ) key , flatpak_policy_to_string ( policy ) ) ;
2015-05-22 13:36:52 +00:00
}
2016-05-06 14:37:47 +00:00
g_key_file_remove_group ( metakey , FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY , NULL ) ;
2016-01-29 07:50:11 +00:00
g_hash_table_iter_init ( & iter , context - > system_bus_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
2016-05-06 14:37:47 +00:00
FlatpakPolicy policy = GPOINTER_TO_INT ( value ) ;
2016-01-29 07:50:11 +00:00
if ( policy > 0 )
g_key_file_set_string ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY ,
( char * ) key , flatpak_policy_to_string ( policy ) ) ;
2016-01-29 07:50:11 +00:00
}
2016-05-06 14:37:47 +00:00
g_key_file_remove_group ( metakey , FLATPAK_METADATA_GROUP_ENVIRONMENT , NULL ) ;
2015-05-22 13:36:52 +00:00
g_hash_table_iter_init ( & iter , context - > env_vars ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
g_key_file_set_string ( metakey ,
2016-05-06 14:37:47 +00:00
FLATPAK_METADATA_GROUP_ENVIRONMENT ,
2016-05-06 14:03:27 +00:00
( char * ) key , ( char * ) value ) ;
2015-05-22 13:36:52 +00:00
}
2016-10-19 18:39:17 +00:00
groups = g_key_file_get_groups ( metakey , NULL ) ;
for ( i = 0 ; groups [ i ] ! = NULL ; i + + )
{
const char * group = groups [ i ] ;
if ( g_str_has_prefix ( group , FLATPAK_METADATA_GROUP_PREFIX_POLICY ) )
g_key_file_remove_group ( metakey , group , NULL ) ;
}
g_hash_table_iter_init ( & iter , context - > generic_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
g_auto ( GStrv ) parts = g_strsplit ( ( const char * ) key , " . " , 2 ) ;
g_autofree char * group = NULL ;
g_assert ( parts [ 1 ] ! = NULL ) ;
const char * * policy_values = ( const char * * ) value ;
g_autoptr ( GPtrArray ) new = g_ptr_array_new ( ) ;
for ( i = 0 ; policy_values [ i ] ! = NULL ; i + + )
{
const char * policy_value = policy_values [ i ] ;
if ( ! flatten | | policy_value [ 0 ] ! = ' ! ' )
g_ptr_array_add ( new , ( char * ) policy_value ) ;
}
if ( new - > len > 0 )
{
group = g_strconcat ( FLATPAK_METADATA_GROUP_PREFIX_POLICY ,
parts [ 0 ] , NULL ) ;
g_key_file_set_string_list ( metakey , group , parts [ 1 ] ,
( const char * const * ) new - > pdata ,
new - > len ) ;
}
}
2015-05-22 13:36:52 +00:00
}
2015-05-25 19:36:36 +00:00
void
2016-05-06 14:37:47 +00:00
flatpak_context_allow_host_fs ( FlatpakContext * context )
2015-05-25 19:36:36 +00:00
{
2016-05-06 14:37:47 +00:00
flatpak_context_add_filesystem ( context , " host " ) ;
2015-05-25 19:36:36 +00:00
}
2017-03-14 15:20:33 +00:00
gboolean
flatpak_context_get_needs_session_bus_proxy ( FlatpakContext * context )
{
return g_hash_table_size ( context - > session_bus_policy ) > 0 ;
}
gboolean
flatpak_context_get_needs_system_bus_proxy ( FlatpakContext * context )
{
return g_hash_table_size ( context - > system_bus_policy ) > 0 ;
}
2016-05-26 10:23:48 +00:00
void
flatpak_context_to_args ( FlatpakContext * context ,
GPtrArray * args )
{
GHashTableIter iter ;
gpointer key , value ;
flatpak_context_shared_to_args ( context - > shares , context - > shares_valid , args ) ;
flatpak_context_sockets_to_args ( context - > sockets , context - > sockets_valid , args ) ;
flatpak_context_devices_to_args ( context - > devices , context - > devices_valid , args ) ;
2016-09-05 19:22:20 +00:00
flatpak_context_features_to_args ( context - > features , context - > features_valid , args ) ;
2016-05-26 10:23:48 +00:00
g_hash_table_iter_init ( & iter , context - > env_vars ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_ptr_array_add ( args , g_strdup_printf ( " --env=%s=%s " , ( char * ) key , ( char * ) value ) ) ;
g_hash_table_iter_init ( & iter , context - > persistent ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
g_ptr_array_add ( args , g_strdup_printf ( " --persist=%s " , ( char * ) key ) ) ;
g_hash_table_iter_init ( & iter , context - > session_bus_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
const char * name = key ;
FlatpakPolicy policy = GPOINTER_TO_INT ( value ) ;
g_ptr_array_add ( args , g_strdup_printf ( " --%s-name=%s " , flatpak_policy_to_string ( policy ) , name ) ) ;
}
g_hash_table_iter_init ( & iter , context - > system_bus_policy ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
const char * name = key ;
FlatpakPolicy policy = GPOINTER_TO_INT ( value ) ;
g_ptr_array_add ( args , g_strdup_printf ( " --system-%s-name=%s " , flatpak_policy_to_string ( policy ) , name ) ) ;
}
g_hash_table_iter_init ( & iter , context - > filesystems ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
FlatpakFilesystemMode mode = GPOINTER_TO_INT ( value ) ;
if ( mode = = FLATPAK_FILESYSTEM_MODE_READ_ONLY )
g_ptr_array_add ( args , g_strdup_printf ( " --filesystem=%s:ro " , ( char * ) key ) ) ;
else if ( mode = = FLATPAK_FILESYSTEM_MODE_READ_WRITE )
g_ptr_array_add ( args , g_strdup_printf ( " --filesystem=%s " , ( char * ) key ) ) ;
2016-11-14 09:58:39 +00:00
else if ( mode = = FLATPAK_FILESYSTEM_MODE_CREATE )
g_ptr_array_add ( args , g_strdup_printf ( " --filesystem=%s:create " , ( char * ) key ) ) ;
2016-05-26 10:23:48 +00:00
else
g_ptr_array_add ( args , g_strdup_printf ( " --nofilesystem=%s " , ( char * ) key ) ) ;
}
}
2015-02-13 09:29:41 +00:00
static char *
extract_unix_path_from_dbus_address ( const char * address )
{
const char * path , * path_end ;
if ( address = = NULL )
return NULL ;
if ( ! g_str_has_prefix ( address , " unix: " ) )
return NULL ;
path = strstr ( address , " path= " ) ;
if ( path = = NULL )
return NULL ;
path + = strlen ( " path= " ) ;
path_end = path ;
while ( * path_end ! = 0 & & * path_end ! = ' , ' )
path_end + + ;
return g_strndup ( path , path_end - path ) ;
}
2016-01-28 11:01:08 +00:00
# ifdef ENABLE_XAUTH
2016-05-06 14:03:27 +00:00
static gboolean
auth_streq ( char * str ,
char * au_str ,
int au_len )
2015-10-01 19:23:23 +00:00
{
return au_len = = strlen ( str ) & & memcmp ( str , au_str , au_len ) = = 0 ;
}
2017-02-15 15:10:29 +00:00
static gboolean
xauth_entry_should_propagate ( Xauth * xa ,
char * hostname ,
char * number )
{
/* ensure entry isn't for remote access */
if ( xa - > family ! = FamilyLocal & & xa - > family ! = FamilyWild )
return FALSE ;
/* ensure entry is for this machine */
if ( xa - > family = = FamilyLocal & & ! auth_streq ( hostname , xa - > address , xa - > address_length ) )
return FALSE ;
/* ensure entry is for this session */
if ( xa - > number ! = NULL & & ! auth_streq ( number , xa - > number , xa - > number_length ) )
return FALSE ;
return TRUE ;
}
2015-10-01 19:23:23 +00:00
static void
write_xauth ( char * number , FILE * output )
{
Xauth * xa , local_xa ;
char * filename ;
FILE * f ;
struct utsname unames ;
if ( uname ( & unames ) )
{
g_warning ( " uname failed " ) ;
return ;
}
filename = XauFileName ( ) ;
f = fopen ( filename , " rb " ) ;
if ( f = = NULL )
return ;
while ( TRUE )
{
xa = XauReadAuth ( f ) ;
if ( xa = = NULL )
break ;
2017-02-15 15:10:29 +00:00
if ( xauth_entry_should_propagate ( xa , unames . nodename , number ) )
2015-10-01 19:23:23 +00:00
{
local_xa = * xa ;
if ( local_xa . number )
{
local_xa . number = " 99 " ;
local_xa . number_length = 2 ;
}
2016-05-06 14:03:27 +00:00
if ( ! XauWriteAuth ( output , & local_xa ) )
2015-10-01 19:23:23 +00:00
g_warning ( " xauth write error " ) ;
}
2016-05-06 14:03:27 +00:00
XauDisposeAuth ( xa ) ;
2015-10-01 19:23:23 +00:00
}
fclose ( f ) ;
}
2016-01-28 11:01:08 +00:00
# endif /* ENABLE_XAUTH */
2015-10-01 19:23:23 +00:00
2015-05-12 12:44:08 +00:00
static void
2016-04-29 09:39:39 +00:00
add_args ( GPtrArray * argv_array , . . . )
{
va_list args ;
const gchar * arg ;
va_start ( args , argv_array ) ;
while ( ( arg = va_arg ( args , const gchar * ) ) )
g_ptr_array_add ( argv_array , g_strdup ( arg ) ) ;
va_end ( args ) ;
}
static int
create_tmp_fd ( const char * contents ,
2016-05-06 14:03:27 +00:00
gssize length ,
GError * * error )
2016-04-29 09:39:39 +00:00
{
char template [ ] = " /tmp/tmp_fd_XXXXXX " ;
int fd ;
if ( length < 0 )
length = strlen ( contents ) ;
fd = g_mkstemp ( template ) ;
if ( fd < 0 )
{
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( errno ) ,
_ ( " Failed to create temporary file " ) ) ;
2016-04-29 09:39:39 +00:00
return - 1 ;
}
if ( unlink ( template ) ! = 0 )
{
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( errno ) ,
_ ( " Failed to unlink temporary file " ) ) ;
2016-04-29 09:39:39 +00:00
close ( fd ) ;
return - 1 ;
}
while ( length > 0 )
{
gssize s ;
s = write ( fd , contents , length ) ;
if ( s < 0 )
{
int saved_errno = errno ;
if ( saved_errno = = EINTR )
continue ;
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( saved_errno ) ,
_ ( " Failed to write to temporary file " ) ) ;
2016-04-29 09:39:39 +00:00
close ( fd ) ;
return - 1 ;
}
g_assert ( s < = length ) ;
contents + = s ;
length - = s ;
}
lseek ( fd , 0 , SEEK_SET ) ;
return fd ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_run_add_x11_args ( GPtrArray * argv_array ,
2016-05-11 13:14:11 +00:00
GArray * fd_array ,
2016-05-10 08:53:24 +00:00
char * * * envp_p ,
gboolean allowed )
2015-02-13 09:29:41 +00:00
{
2016-07-15 00:27:11 +00:00
g_autofree char * x11_socket = NULL ;
2016-05-10 08:53:24 +00:00
const char * display ;
2015-02-13 09:29:41 +00:00
2016-05-10 08:53:24 +00:00
/* Always cover /tmp/.X11-unix, that way we never see the host one in case
* we have access to the host / tmp . If you request X access we ' ll put the right
* thing in this anyway .
*/
add_args ( argv_array ,
" --tmpfs " , " /tmp/.X11-unix " ,
NULL ) ;
if ( ! allowed )
{
* envp_p = g_environ_unsetenv ( * envp_p , " DISPLAY " ) ;
return ;
}
g_debug ( " Allowing x11 access " ) ;
display = g_getenv ( " DISPLAY " ) ;
2015-02-13 09:29:41 +00:00
if ( display & & display [ 0 ] = = ' : ' & & g_ascii_isdigit ( display [ 1 ] ) )
{
const char * display_nr = & display [ 1 ] ;
const char * display_nr_end = display_nr ;
2015-03-20 15:21:19 +00:00
g_autofree char * d = NULL ;
2015-10-01 19:23:23 +00:00
g_autofree char * tmp_path = NULL ;
2015-02-13 09:29:41 +00:00
while ( g_ascii_isdigit ( * display_nr_end ) )
display_nr_end + + ;
d = g_strndup ( display_nr , display_nr_end - display_nr ) ;
x11_socket = g_strdup_printf ( " /tmp/.X11-unix/X%s " , d ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , x11_socket , " /tmp/.X11-unix/X99 " ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " DISPLAY " , " :99.0 " , TRUE ) ;
2015-10-01 19:23:23 +00:00
2016-01-28 11:01:08 +00:00
# ifdef ENABLE_XAUTH
int fd ;
2016-05-09 09:07:53 +00:00
fd = g_file_open_tmp ( " flatpak-xauth-XXXXXX " , & tmp_path , NULL ) ;
2015-10-01 19:23:23 +00:00
if ( fd > = 0 )
{
2016-01-28 11:01:08 +00:00
FILE * output = fdopen ( fd , " wb " ) ;
2015-10-01 19:23:23 +00:00
if ( output ! = NULL )
{
2016-04-29 09:39:39 +00:00
int tmp_fd = dup ( fd ) ;
if ( tmp_fd ! = - 1 )
{
g_autofree char * tmp_fd_str = g_strdup_printf ( " %d " , tmp_fd ) ;
2016-05-06 14:03:27 +00:00
g_autofree char * dest = g_strdup_printf ( " /run/user/%d/Xauthority " , getuid ( ) ) ;
2016-04-29 09:39:39 +00:00
write_xauth ( d , output ) ;
add_args ( argv_array ,
" --bind-data " , tmp_fd_str , dest ,
NULL ) ;
2016-05-11 13:14:11 +00:00
if ( fd_array )
g_array_append_val ( fd_array , tmp_fd ) ;
2016-04-29 09:39:39 +00:00
* envp_p = g_environ_setenv ( * envp_p , " XAUTHORITY " , dest , TRUE ) ;
2016-11-11 09:59:00 +00:00
2016-04-29 09:39:39 +00:00
}
2015-10-01 19:23:23 +00:00
fclose ( output ) ;
2016-04-29 09:39:39 +00:00
unlink ( tmp_path ) ;
2016-12-07 10:18:27 +00:00
if ( tmp_fd ! = - 1 )
lseek ( tmp_fd , 0 , SEEK_SET ) ;
2015-10-01 19:23:23 +00:00
}
else
2016-05-06 14:03:27 +00:00
{
close ( fd ) ;
}
2015-10-01 19:23:23 +00:00
}
2016-01-28 11:01:08 +00:00
# endif
2015-02-13 09:29:41 +00:00
}
2016-04-29 09:39:39 +00:00
else
2016-05-06 14:03:27 +00:00
{
* envp_p = g_environ_unsetenv ( * envp_p , " DISPLAY " ) ;
}
2016-04-29 09:39:39 +00:00
2015-02-13 09:29:41 +00:00
}
2015-05-12 12:44:08 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_run_add_wayland_args ( GPtrArray * argv_array ,
2016-05-06 14:03:27 +00:00
char * * * envp_p )
2015-02-13 09:29:41 +00:00
{
2016-04-29 09:39:39 +00:00
g_autofree char * wayland_socket = g_build_filename ( g_get_user_runtime_dir ( ) , " wayland-0 " , NULL ) ;
g_autofree char * sandbox_wayland_socket = g_strdup_printf ( " /run/user/%d/wayland-0 " , getuid ( ) ) ;
2015-02-13 09:29:41 +00:00
if ( g_file_test ( wayland_socket , G_FILE_TEST_EXISTS ) )
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , wayland_socket , sandbox_wayland_socket ,
NULL ) ;
2015-02-13 09:29:41 +00:00
}
}
2015-05-12 12:44:08 +00:00
static void
2016-05-06 14:37:47 +00:00
flatpak_run_add_pulseaudio_args ( GPtrArray * argv_array ,
2016-05-11 13:14:11 +00:00
GArray * fd_array ,
2016-05-06 14:03:27 +00:00
char * * * envp_p )
2015-02-13 09:29:41 +00:00
{
2016-07-15 00:27:11 +00:00
g_autofree char * pulseaudio_socket = g_build_filename ( g_get_user_runtime_dir ( ) , " pulse/native " , NULL ) ;
2016-04-29 09:39:39 +00:00
* envp_p = g_environ_unsetenv ( * envp_p , " PULSE_SERVER " ) ;
2015-02-13 09:29:41 +00:00
if ( g_file_test ( pulseaudio_socket , G_FILE_TEST_EXISTS ) )
{
2016-04-29 09:39:39 +00:00
gboolean share_shm = FALSE ; /* TODO: When do we add this? */
g_autofree char * client_config = g_strdup_printf ( " enable-shm=%s \n " , share_shm ? " yes " : " no " ) ;
g_autofree char * sandbox_socket_path = g_strdup_printf ( " /run/user/%d/pulse/native " , getuid ( ) ) ;
g_autofree char * pulse_server = g_strdup_printf ( " unix:/run/user/%d/pulse/native " , getuid ( ) ) ;
g_autofree char * config_path = g_strdup_printf ( " /run/user/%d/pulse/config " , getuid ( ) ) ;
int fd ;
g_autofree char * fd_str = NULL ;
fd = create_tmp_fd ( client_config , - 1 , NULL ) ;
if ( fd = = - 1 )
return ;
fd_str = g_strdup_printf ( " %d " , fd ) ;
2016-05-11 13:14:11 +00:00
if ( fd_array )
g_array_append_val ( fd_array , fd ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , pulseaudio_socket , sandbox_socket_path ,
" --bind-data " , fd_str , config_path ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " PULSE_SERVER " , pulse_server , TRUE ) ;
* envp_p = g_environ_setenv ( * envp_p , " PULSE_CLIENTCONFIG " , config_path , TRUE ) ;
2015-02-13 09:29:41 +00:00
}
}
2016-06-24 05:52:55 +00:00
static void
2016-06-28 13:05:01 +00:00
flatpak_run_add_journal_args ( GPtrArray * argv_array )
2016-06-24 05:52:55 +00:00
{
2016-07-15 00:27:11 +00:00
g_autofree char * journal_socket_socket = g_strdup ( " /run/systemd/journal/socket " ) ;
g_autofree char * journal_stdout_socket = g_strdup ( " /run/systemd/journal/stdout " ) ;
2016-06-24 05:52:55 +00:00
if ( g_file_test ( journal_socket_socket , G_FILE_TEST_EXISTS ) )
{
add_args ( argv_array ,
" --bind " , journal_socket_socket , journal_socket_socket ,
NULL ) ;
}
if ( g_file_test ( journal_stdout_socket , G_FILE_TEST_EXISTS ) )
{
add_args ( argv_array ,
" --bind " , journal_stdout_socket , journal_stdout_socket ,
NULL ) ;
}
}
2015-05-07 17:17:03 +00:00
static char *
create_proxy_socket ( char * template )
{
2017-01-23 17:24:21 +00:00
g_autofree char * proxy_socket_dir = g_build_filename ( g_get_user_runtime_dir ( ) , " .dbus-proxy " , NULL ) ;
g_autofree char * proxy_socket = g_build_filename ( proxy_socket_dir , template , NULL ) ;
2015-05-07 17:17:03 +00:00
int fd ;
2017-01-23 17:24:21 +00:00
if ( ! glnx_shutil_mkdir_p_at ( AT_FDCWD , proxy_socket_dir , 0755 , NULL , NULL ) )
return NULL ;
2015-05-07 17:17:03 +00:00
fd = g_mkstemp ( proxy_socket ) ;
if ( fd = = - 1 )
return NULL ;
close ( fd ) ;
return g_steal_pointer ( & proxy_socket ) ;
}
2017-03-22 18:50:48 +00:00
static gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_add_system_dbus_args ( FlatpakContext * context ,
char * * * envp_p ,
GPtrArray * argv_array ,
GPtrArray * dbus_proxy_argv ,
gboolean unrestricted )
2015-02-13 09:29:41 +00:00
{
const char * dbus_address = g_getenv ( " DBUS_SYSTEM_BUS_ADDRESS " ) ;
2016-01-29 07:50:11 +00:00
g_autofree char * real_dbus_address = NULL ;
2016-06-10 10:59:30 +00:00
g_autofree char * dbus_system_socket = NULL ;
2015-02-13 09:29:41 +00:00
2015-05-07 17:17:03 +00:00
if ( dbus_address ! = NULL )
dbus_system_socket = extract_unix_path_from_dbus_address ( dbus_address ) ;
else if ( g_file_test ( " /var/run/dbus/system_bus_socket " , G_FILE_TEST_EXISTS ) )
dbus_system_socket = g_strdup ( " /var/run/dbus/system_bus_socket " ) ;
2015-02-13 09:29:41 +00:00
2016-01-29 07:50:11 +00:00
if ( dbus_system_socket ! = NULL & & unrestricted )
2015-02-13 09:29:41 +00:00
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , dbus_system_socket , " /run/dbus/system_bus_socket " ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " DBUS_SYSTEM_BUS_ADDRESS " , " unix:path=/run/dbus/system_bus_socket " , TRUE ) ;
2016-01-29 07:50:11 +00:00
return TRUE ;
2015-02-13 09:29:41 +00:00
}
2016-01-29 07:50:11 +00:00
else if ( dbus_proxy_argv & &
g_hash_table_size ( context - > system_bus_policy ) > 0 )
2015-05-07 17:17:03 +00:00
{
2017-01-23 17:24:21 +00:00
g_autofree char * proxy_socket = create_proxy_socket ( " system-bus-proxy-XXXXXX " ) ;
2015-05-07 17:17:03 +00:00
if ( proxy_socket = = NULL )
2016-04-29 09:39:39 +00:00
return FALSE ;
2015-05-07 17:17:03 +00:00
2016-01-29 07:50:11 +00:00
if ( dbus_address )
real_dbus_address = g_strdup ( dbus_address ) ;
else
real_dbus_address = g_strdup_printf ( " unix:path=%s " , dbus_system_socket ) ;
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( real_dbus_address ) ) ;
2015-05-07 17:17:03 +00:00
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( proxy_socket ) ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , proxy_socket , " /run/dbus/system_bus_socket " ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " DBUS_SYSTEM_BUS_ADDRESS " , " unix:path=/run/dbus/system_bus_socket " , TRUE ) ;
2016-01-29 07:50:11 +00:00
return TRUE ;
2015-05-07 17:17:03 +00:00
}
2016-01-29 07:50:11 +00:00
return FALSE ;
2015-02-13 09:29:41 +00:00
}
2017-03-22 18:50:48 +00:00
static gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_add_session_dbus_args ( GPtrArray * argv_array ,
2016-05-06 14:03:27 +00:00
char * * * envp_p ,
2015-05-12 12:44:08 +00:00
GPtrArray * dbus_proxy_argv ,
2016-05-06 14:03:27 +00:00
gboolean unrestricted )
2015-02-13 09:29:41 +00:00
{
const char * dbus_address = g_getenv ( " DBUS_SESSION_BUS_ADDRESS " ) ;
char * dbus_session_socket = NULL ;
2016-04-29 09:39:39 +00:00
g_autofree char * sandbox_socket_path = g_strdup_printf ( " /run/user/%d/bus " , getuid ( ) ) ;
g_autofree char * sandbox_dbus_address = g_strdup_printf ( " unix:path=/run/user/%d/bus " , getuid ( ) ) ;
2015-02-13 09:29:41 +00:00
2015-05-07 17:17:03 +00:00
if ( dbus_address = = NULL )
2015-05-12 12:44:08 +00:00
return FALSE ;
2015-05-07 17:17:03 +00:00
2015-02-13 09:29:41 +00:00
dbus_session_socket = extract_unix_path_from_dbus_address ( dbus_address ) ;
2015-05-12 12:44:08 +00:00
if ( dbus_session_socket ! = NULL & & unrestricted )
2015-02-13 09:29:41 +00:00
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , dbus_session_socket , sandbox_socket_path ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " DBUS_SESSION_BUS_ADDRESS " , sandbox_dbus_address , TRUE ) ;
2015-05-12 12:44:08 +00:00
return TRUE ;
2015-02-13 09:29:41 +00:00
}
2015-05-07 17:17:03 +00:00
else if ( dbus_proxy_argv & & dbus_address ! = NULL )
{
2017-01-23 17:24:21 +00:00
g_autofree char * proxy_socket = create_proxy_socket ( " session-bus-proxy-XXXXXX " ) ;
2015-05-07 17:17:03 +00:00
if ( proxy_socket = = NULL )
2016-04-29 09:39:39 +00:00
return FALSE ;
2015-05-07 17:17:03 +00:00
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( dbus_address ) ) ;
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( proxy_socket ) ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , proxy_socket , sandbox_socket_path ,
NULL ) ;
* envp_p = g_environ_setenv ( * envp_p , " DBUS_SESSION_BUS_ADDRESS " , sandbox_dbus_address , TRUE ) ;
2015-05-12 12:44:08 +00:00
return TRUE ;
2015-05-07 17:17:03 +00:00
}
2015-05-12 12:44:08 +00:00
return FALSE ;
}
static void
2016-05-06 14:37:47 +00:00
flatpak_add_bus_filters ( GPtrArray * dbus_proxy_argv ,
GHashTable * ht ,
const char * app_id ,
FlatpakContext * context )
2015-05-12 12:44:08 +00:00
{
2015-05-22 14:55:45 +00:00
GHashTableIter iter ;
gpointer key , value ;
2015-05-12 12:44:08 +00:00
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( " --filter " ) ) ;
2016-01-29 07:50:11 +00:00
if ( app_id )
{
g_ptr_array_add ( dbus_proxy_argv , g_strdup_printf ( " --own=%s " , app_id ) ) ;
g_ptr_array_add ( dbus_proxy_argv , g_strdup_printf ( " --own=%s.* " , app_id ) ) ;
}
2015-05-12 12:44:08 +00:00
2016-01-29 07:50:11 +00:00
g_hash_table_iter_init ( & iter , ht ) ;
2015-05-22 14:55:45 +00:00
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
2016-05-06 14:37:47 +00:00
FlatpakPolicy policy = GPOINTER_TO_INT ( value ) ;
2015-05-22 14:55:45 +00:00
if ( policy > 0 )
2016-05-06 14:37:47 +00:00
g_ptr_array_add ( dbus_proxy_argv , g_strdup_printf ( " --%s=%s " , flatpak_policy_to_string ( policy ) , ( char * ) key ) ) ;
2015-05-22 14:55:45 +00:00
}
2015-02-13 09:29:41 +00:00
}
2015-02-13 09:41:01 +00:00
2015-09-22 11:57:20 +00:00
gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_add_extension_args ( GPtrArray * argv_array ,
2017-02-01 15:23:41 +00:00
char * * * envp_p ,
2016-05-06 14:03:27 +00:00
GKeyFile * metakey ,
const char * full_ref ,
2015-09-22 11:57:20 +00:00
GCancellable * cancellable ,
2016-05-06 14:03:27 +00:00
GError * * error )
2015-09-22 11:57:20 +00:00
{
g_auto ( GStrv ) parts = NULL ;
2016-01-11 14:34:54 +00:00
gboolean is_app ;
2016-01-20 11:33:55 +00:00
GList * extensions , * l ;
2017-02-01 18:42:57 +00:00
g_autoptr ( GHashTable ) mounted_tmpfs =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
2017-02-03 07:15:50 +00:00
g_autoptr ( GHashTable ) created_symlink =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ) ;
2015-09-22 11:57:20 +00:00
parts = g_strsplit ( full_ref , " / " , 0 ) ;
if ( g_strv_length ( parts ) ! = 4 )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Failed to determine parts from ref: %s " , full_ref ) ;
2015-09-22 11:57:20 +00:00
2016-01-11 14:34:54 +00:00
is_app = strcmp ( parts [ 0 ] , " app " ) = = 0 ;
2016-05-06 14:37:47 +00:00
extensions = flatpak_list_extensions ( metakey ,
2016-01-20 11:33:55 +00:00
parts [ 2 ] , parts [ 3 ] ) ;
for ( l = extensions ; l ! = NULL ; l = l - > next )
2015-09-22 11:57:20 +00:00
{
2016-05-06 14:37:47 +00:00
FlatpakExtension * ext = l - > data ;
2017-02-01 18:59:12 +00:00
g_autofree char * directory = g_build_filename ( is_app ? " /app " : " /usr " , ext - > directory , NULL ) ;
g_autofree char * full_directory = g_build_filename ( directory , ext - > subdir_suffix , NULL ) ;
2016-06-29 08:24:50 +00:00
g_autofree char * ref = g_build_filename ( full_directory , " .ref " , NULL ) ;
g_autofree char * real_ref = g_build_filename ( ext - > files_path , ext - > directory , " .ref " , NULL ) ;
2017-02-02 12:56:34 +00:00
int i ;
2015-09-22 11:57:20 +00:00
2016-06-29 13:56:10 +00:00
if ( ext - > needs_tmpfs )
{
2017-02-01 18:59:12 +00:00
g_autofree char * parent = g_path_get_dirname ( directory ) ;
2017-02-02 12:56:34 +00:00
2017-02-01 18:42:57 +00:00
if ( g_hash_table_lookup ( mounted_tmpfs , parent ) = = NULL )
{
add_args ( argv_array ,
" --tmpfs " , parent ,
NULL ) ;
g_hash_table_insert ( mounted_tmpfs , g_steal_pointer ( & parent ) , " mounted " ) ;
}
2016-06-29 13:56:10 +00:00
}
2016-06-29 08:24:50 +00:00
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , ext - > files_path , full_directory ,
2016-06-29 08:24:50 +00:00
NULL ) ;
if ( g_file_test ( real_ref , G_FILE_TEST_EXISTS ) )
add_args ( argv_array ,
" --lock-file " , ref ,
NULL ) ;
2017-02-01 15:23:41 +00:00
if ( ext - > add_ld_path )
{
g_autofree char * ld_path = g_build_filename ( full_directory , ext - > add_ld_path , NULL ) ;
const gchar * old_ld_path = g_environ_getenv ( * envp_p , " LD_LIBRARY_PATH " ) ;
g_autofree char * new_ld_path = NULL ;
if ( old_ld_path ! = NULL )
new_ld_path = g_strconcat ( old_ld_path , " : " , ld_path , NULL ) ;
else
new_ld_path = g_strdup ( new_ld_path ) ;
* envp_p = g_environ_setenv ( * envp_p , " LD_LIBRARY_PATH " , new_ld_path , TRUE ) ;
}
2017-02-02 12:56:34 +00:00
for ( i = 0 ; ext - > merge_dirs ! = NULL & & ext - > merge_dirs [ i ] ! = NULL ; i + + )
{
g_autofree char * parent = g_path_get_dirname ( directory ) ;
g_autofree char * merge_dir = g_build_filename ( parent , ext - > merge_dirs [ i ] , NULL ) ;
g_autofree char * source_dir = g_build_filename ( ext - > files_path , ext - > merge_dirs [ i ] , NULL ) ;
g_auto ( GLnxDirFdIterator ) source_iter = { 0 } ;
struct dirent * dent ;
if ( glnx_dirfd_iterator_init_at ( AT_FDCWD , source_dir , TRUE , & source_iter , NULL ) )
{
while ( glnx_dirfd_iterator_next_dent ( & source_iter , & dent , NULL , NULL ) & & dent ! = NULL )
{
g_autofree char * symlink_path = g_build_filename ( merge_dir , dent - > d_name , NULL ) ;
2017-02-03 07:15:50 +00:00
/* Only create the first, because extensions are listed in prio order */
if ( g_hash_table_lookup ( created_symlink , symlink_path ) = = NULL )
{
g_autofree char * symlink = g_build_filename ( directory , ext - > merge_dirs [ i ] , dent - > d_name , NULL ) ;
add_args ( argv_array ,
" --symlink " , symlink , symlink_path ,
NULL ) ;
g_hash_table_insert ( created_symlink , g_steal_pointer ( & symlink_path ) , " created " ) ;
}
2017-02-02 12:56:34 +00:00
}
}
}
2015-09-22 11:57:20 +00:00
}
2016-05-06 14:37:47 +00:00
g_list_free_full ( extensions , ( GDestroyNotify ) flatpak_extension_free ) ;
2016-01-20 11:33:55 +00:00
2015-09-22 11:57:20 +00:00
return TRUE ;
}
2017-01-19 14:04:46 +00:00
static char *
make_relative ( const char * base , const char * path )
{
GString * s = g_string_new ( " " ) ;
while ( * base ! = 0 )
{
while ( * base = = ' / ' )
base + + ;
if ( * base ! = 0 )
g_string_append ( s , " ../ " ) ;
while ( * base ! = ' / ' & & * base ! = 0 )
base + + ;
}
while ( * path = = ' / ' )
path + + ;
g_string_append ( s , path ) ;
return g_string_free ( s , FALSE ) ;
}
2016-11-14 09:14:45 +00:00
# define FAKE_MODE_HIDDEN 0
2016-11-11 21:21:07 +00:00
# define FAKE_MODE_SYMLINK G_MAXINT
2017-01-19 14:11:08 +00:00
typedef struct {
char * path ;
int level ;
guint mode ;
} ExportedPath ;
2016-11-11 21:21:07 +00:00
static gboolean
2016-11-14 09:14:45 +00:00
path_is_visible ( const char * * keys ,
guint n_keys ,
GHashTable * hash_table ,
const char * path )
2016-11-11 21:21:07 +00:00
{
guint i ;
2016-11-14 09:14:45 +00:00
gboolean is_visible = FALSE ;
2016-11-11 21:21:07 +00:00
2016-11-14 09:14:45 +00:00
/* The keys are sorted so shorter (i.e. parents) are first */
2016-11-11 21:21:07 +00:00
for ( i = 0 ; i < n_keys ; i + + )
{
const char * mounted_path = keys [ i ] ;
2017-01-19 14:11:08 +00:00
ExportedPath * ep = g_hash_table_lookup ( hash_table , mounted_path ) ;
2016-11-11 21:21:07 +00:00
2016-11-14 09:14:45 +00:00
if ( flatpak_has_path_prefix ( path , mounted_path ) )
{
2017-01-19 14:11:08 +00:00
if ( ep - > mode = = FAKE_MODE_HIDDEN )
2016-11-14 09:14:45 +00:00
is_visible = FALSE ;
2017-01-19 14:11:08 +00:00
else if ( ep - > mode ! = FAKE_MODE_SYMLINK )
2016-11-14 09:14:45 +00:00
is_visible = TRUE ;
}
2016-11-11 21:21:07 +00:00
}
2016-11-14 09:14:45 +00:00
return is_visible ;
2016-11-11 21:21:07 +00:00
}
2017-01-19 14:11:08 +00:00
static gint
compare_eps ( const ExportedPath * a ,
const ExportedPath * b )
{
if ( a - > level = = b - > level )
return g_strcmp0 ( a - > path , b - > path ) ;
else
return b - > level - a - > level ;
}
2016-11-11 21:21:07 +00:00
static void
add_file_args ( GPtrArray * argv_array ,
GHashTable * hash_table )
{
guint n_keys ;
g_autofree const char * * keys = ( const char * * ) g_hash_table_get_keys_as_array ( hash_table , & n_keys ) ;
2017-01-19 14:11:08 +00:00
g_autoptr ( GList ) eps = NULL ;
GList * l ;
eps = g_hash_table_get_values ( hash_table ) ;
eps = g_list_sort ( eps , ( GCompareFunc ) compare_eps ) ;
2016-11-11 21:21:07 +00:00
g_qsort_with_data ( keys , n_keys , sizeof ( char * ) , ( GCompareDataFunc ) flatpak_strcmp0_ptr , NULL ) ;
2017-01-19 14:11:08 +00:00
for ( l = eps ; l ! = NULL ; l = l - > next )
2016-11-11 21:21:07 +00:00
{
2017-01-19 14:11:08 +00:00
ExportedPath * ep = l - > data ;
const char * path = ep - > path ;
2016-11-11 21:21:07 +00:00
2017-01-19 14:11:08 +00:00
if ( ep - > mode = = FAKE_MODE_SYMLINK )
2016-11-11 21:21:07 +00:00
{
2016-11-14 09:14:45 +00:00
if ( ! path_is_visible ( keys , n_keys , hash_table , path ) )
2016-11-11 21:21:07 +00:00
{
g_autofree char * resolved = flatpak_resolve_link ( path , NULL ) ;
if ( resolved )
2017-02-28 09:44:54 +00:00
{
g_autofree char * parent = g_path_get_dirname ( path ) ;
g_autofree char * relative = make_relative ( parent , resolved ) ;
add_args ( argv_array , " --symlink " , relative , path , NULL ) ;
}
2016-11-11 21:21:07 +00:00
}
}
2017-01-19 14:11:08 +00:00
else if ( ep - > mode = = FAKE_MODE_HIDDEN )
2016-11-14 09:14:45 +00:00
{
/* Mount a tmpfs to hide the subdirectory, but only if
either its not visible ( then we can always create the
dir on the tmpfs , or if there is a pre - existing dir
we can mount the path on . */
if ( ! path_is_visible ( keys , n_keys , hash_table , path ) | |
g_file_test ( path , G_FILE_TEST_IS_DIR ) )
add_args ( argv_array , " --tmpfs " , path , NULL ) ;
}
2016-11-11 21:21:07 +00:00
else
2017-01-19 14:11:08 +00:00
{
add_args ( argv_array ,
( ep - > mode = = FLATPAK_FILESYSTEM_MODE_READ_ONLY ) ? " --ro-bind " : " --bind " ,
path , path , NULL ) ;
}
2016-11-11 21:21:07 +00:00
}
}
2016-11-14 09:14:45 +00:00
static void
add_hide_path ( GHashTable * hash_table ,
const char * path )
{
2016-12-13 09:20:28 +00:00
guint old_mode ;
2017-01-19 14:11:08 +00:00
ExportedPath * ep = g_new0 ( ExportedPath , 1 ) ;
ExportedPath * old_ep ;
2016-11-14 09:14:45 +00:00
2017-01-19 14:11:08 +00:00
old_ep = g_hash_table_lookup ( hash_table , path ) ;
if ( old_ep )
old_mode = old_ep - > mode ;
else
old_mode = 0 ;
ep - > path = g_strdup ( path ) ;
ep - > level = 0 ;
ep - > mode = MAX ( old_mode , FAKE_MODE_HIDDEN ) ;
g_hash_table_insert ( hash_table , ep - > path , ep ) ;
2016-11-14 09:14:45 +00:00
}
2017-01-19 14:11:08 +00:00
/* We use the level to make sure we get the ordering somewhat right.
* For instance if / symlink - > / z_dir is exported , then we want to create
* / z_dir before / symlink , because otherwise an export like / symlink / foo
* will fail . The approach we use is to just bump the sort prio based on the
* symlink resolve depth . This it not perfect , but gets the common situation
* such as - - filesystem = / link - - filesystem = / link / dir right .
*/
2017-01-19 09:43:17 +00:00
static gboolean
2017-01-19 14:11:08 +00:00
_add_expose_path ( GHashTable * hash_table ,
FlatpakFilesystemMode mode ,
const char * path ,
int level )
2016-04-29 09:39:39 +00:00
{
2017-01-19 09:43:17 +00:00
g_autofree char * canonical = flatpak_canonicalize_filename ( path ) ;
2016-04-29 09:39:39 +00:00
struct stat st ;
2017-01-19 09:43:17 +00:00
int i ;
if ( ! g_path_is_absolute ( path ) )
{
2017-01-19 14:11:08 +00:00
g_debug ( " Not exposing relative path %s " , path ) ;
2017-01-19 09:43:17 +00:00
return FALSE ;
}
for ( i = 0 ; dont_export_in [ i ] ! = NULL ; i + + )
{
/* Don't expose files in non-mounted dirs like /app or /usr, as
they are not the same as on the host , and we generally can ' t
create the parents for them anyway */
if ( g_str_has_prefix ( canonical , dont_export_in [ i ] ) )
{
g_debug ( " skipping export for path %s " , canonical ) ;
return FALSE ;
}
}
2016-04-29 09:39:39 +00:00
2016-11-11 21:21:07 +00:00
if ( lstat ( path , & st ) ! = 0 )
2017-01-19 09:43:17 +00:00
return FALSE ;
2016-04-29 09:39:39 +00:00
if ( S_ISDIR ( st . st_mode ) | |
2016-11-11 21:21:07 +00:00
S_ISREG ( st . st_mode ) | |
2016-11-22 10:39:58 +00:00
S_ISLNK ( st . st_mode ) | |
S_ISSOCK ( st . st_mode ) )
2016-04-29 09:39:39 +00:00
{
2017-01-19 14:11:08 +00:00
ExportedPath * old_ep = g_hash_table_lookup ( hash_table , path ) ;
guint old_mode = 0 ;
2016-11-11 21:21:07 +00:00
2017-01-19 14:11:08 +00:00
if ( old_ep ! = NULL )
old_mode = old_ep - > mode ;
2016-11-11 21:21:07 +00:00
if ( S_ISLNK ( st . st_mode ) )
{
g_autofree char * resolved = flatpak_resolve_link ( path , NULL ) ;
2017-01-19 09:43:17 +00:00
2017-01-19 14:11:08 +00:00
if ( resolved & & _add_expose_path ( hash_table , mode , resolved , level + 1 ) )
2017-01-19 09:43:17 +00:00
mode = FAKE_MODE_SYMLINK ;
2016-11-11 21:21:07 +00:00
else
mode = 0 ;
}
2017-01-19 09:43:17 +00:00
2016-11-11 21:21:07 +00:00
if ( mode > 0 )
2017-01-19 09:43:17 +00:00
{
2017-01-19 14:11:08 +00:00
ExportedPath * ep = g_new0 ( ExportedPath , 1 ) ;
ep - > path = g_strdup ( path ) ;
ep - > mode = MAX ( old_mode , mode ) ;
ep - > level = level ;
g_hash_table_insert ( hash_table , ep - > path , ep ) ;
2017-01-19 09:43:17 +00:00
return TRUE ;
}
2016-04-29 09:39:39 +00:00
}
2017-01-19 09:43:17 +00:00
return FALSE ;
2016-04-29 09:39:39 +00:00
}
2017-01-19 14:11:08 +00:00
static gboolean
add_expose_path ( GHashTable * hash_table ,
FlatpakFilesystemMode mode ,
const char * path )
{
return _add_expose_path ( hash_table , mode , path , 0 ) ;
}
2017-03-14 15:20:33 +00:00
gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_add_environment_args ( GPtrArray * argv_array ,
2016-05-11 13:14:11 +00:00
GArray * fd_array ,
2016-05-06 14:37:47 +00:00
char * * * envp_p ,
2017-03-14 15:20:33 +00:00
const char * app_info_path ,
FlatpakRunFlags flags ,
2016-05-06 14:37:47 +00:00
const char * app_id ,
FlatpakContext * context ,
2017-03-14 15:20:33 +00:00
GFile * app_id_dir ,
GCancellable * cancellable ,
GError * * error )
2015-02-13 09:41:01 +00:00
{
2015-05-25 13:28:29 +00:00
GHashTableIter iter ;
2015-09-09 12:11:05 +00:00
gpointer key , value ;
2015-05-12 12:44:08 +00:00
gboolean unrestricted_session_bus ;
2016-01-29 07:50:11 +00:00
gboolean unrestricted_system_bus ;
2015-05-25 13:28:29 +00:00
gboolean home_access = FALSE ;
GString * xdg_dirs_conf = NULL ;
2017-03-14 15:20:33 +00:00
g_autoptr ( GError ) my_error = NULL ;
2016-05-06 14:37:47 +00:00
FlatpakFilesystemMode fs_mode , home_mode ;
2016-11-14 09:22:57 +00:00
g_autoptr ( GFile ) user_flatpak_dir = NULL ;
2017-01-19 14:11:08 +00:00
g_autoptr ( GHashTable ) fs_paths = g_hash_table_new_full ( g_str_hash , g_str_equal , NULL , g_free ) ;
2017-03-14 15:20:33 +00:00
g_autoptr ( GPtrArray ) session_bus_proxy_argv = NULL ;
g_autoptr ( GPtrArray ) system_bus_proxy_argv = NULL ;
int sync_fds [ 2 ] = { - 1 , - 1 } ;
2015-02-19 19:57:53 +00:00
2017-03-14 15:20:33 +00:00
if ( ( flags & FLATPAK_RUN_FLAG_NO_SESSION_BUS_PROXY ) = = 0 )
session_bus_proxy_argv = g_ptr_array_new_with_free_func ( g_free ) ;
if ( ( flags & FLATPAK_RUN_FLAG_NO_SYSTEM_BUS_PROXY ) = = 0 )
system_bus_proxy_argv = g_ptr_array_new_with_free_func ( g_free ) ;
if ( ( context - > shares & FLATPAK_CONTEXT_SHARED_IPC ) = = 0 )
2015-02-13 09:41:01 +00:00
{
2016-04-29 09:39:39 +00:00
g_debug ( " Disallowing ipc access " ) ;
add_args ( argv_array , " --unshare-ipc " , NULL ) ;
2015-02-13 09:41:01 +00:00
}
2016-05-06 14:37:47 +00:00
if ( ( context - > shares & FLATPAK_CONTEXT_SHARED_NETWORK ) = = 0 )
2015-05-22 14:55:45 +00:00
{
2016-04-29 09:39:39 +00:00
g_debug ( " Disallowing network access " ) ;
add_args ( argv_array , " --unshare-net " , NULL ) ;
2015-05-22 14:55:45 +00:00
}
2016-06-14 20:33:14 +00:00
if ( context - > devices & FLATPAK_CONTEXT_DEVICE_ALL )
2015-03-05 14:55:36 +00:00
{
2016-06-14 20:33:14 +00:00
add_args ( argv_array ,
2016-06-18 20:52:39 +00:00
" --dev-bind " , " /dev " , " /dev " ,
2016-06-14 20:33:14 +00:00
NULL ) ;
}
else
{
add_args ( argv_array ,
" --dev " , " /dev " ,
NULL ) ;
if ( context - > devices & FLATPAK_CONTEXT_DEVICE_DRI )
2016-05-06 14:03:27 +00:00
{
2016-06-14 20:33:14 +00:00
g_debug ( " Allowing dri access " ) ;
2017-02-08 15:42:02 +00:00
int i ;
char * dri_devices [ ] = {
" /dev/dri " ,
/* mali */
" /dev/mali " ,
" /dev/umplock " ,
/* nvidia */
" /dev/nvidiactl " ,
" /dev/nvidia0 " ,
" /dev/nvidia-modeset " ,
} ;
for ( i = 0 ; i < G_N_ELEMENTS ( dri_devices ) ; i + + )
2017-01-19 16:59:19 +00:00
{
2017-02-08 15:42:02 +00:00
if ( g_file_test ( dri_devices [ i ] , G_FILE_TEST_EXISTS ) )
add_args ( argv_array , " --dev-bind " , dri_devices [ i ] , dri_devices [ i ] , NULL ) ;
2016-06-14 20:33:14 +00:00
}
2016-05-06 14:03:27 +00:00
}
2017-02-08 15:42:02 +00:00
2016-09-30 14:44:17 +00:00
if ( context - > devices & FLATPAK_CONTEXT_DEVICE_KVM )
{
g_debug ( " Allowing kvm access " ) ;
if ( g_file_test ( " /dev/kvm " , G_FILE_TEST_EXISTS ) )
add_args ( argv_array , " --dev-bind " , " /dev/kvm " , " /dev/kvm " , NULL ) ;
}
2015-03-05 14:55:36 +00:00
}
2016-05-06 14:37:47 +00:00
fs_mode = ( FlatpakFilesystemMode ) g_hash_table_lookup ( context - > filesystems , " host " ) ;
2015-11-26 16:22:37 +00:00
if ( fs_mode ! = 0 )
2015-02-13 09:41:01 +00:00
{
2016-04-29 09:39:39 +00:00
DIR * dir ;
struct dirent * dirent ;
2015-02-13 09:41:01 +00:00
g_debug ( " Allowing host-fs access " ) ;
2015-05-25 13:28:29 +00:00
home_access = TRUE ;
2016-04-29 09:39:39 +00:00
/* Bind mount most dirs in / into the new root */
dir = opendir ( " / " ) ;
if ( dir ! = NULL )
{
while ( ( dirent = readdir ( dir ) ) )
{
g_autofree char * path = NULL ;
if ( g_strv_contains ( dont_mount_in_root , dirent - > d_name ) )
continue ;
path = g_build_filename ( " / " , dirent - > d_name , NULL ) ;
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , fs_mode , path ) ;
2016-04-29 09:39:39 +00:00
}
2016-06-10 10:59:30 +00:00
closedir ( dir ) ;
2016-04-29 09:39:39 +00:00
}
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , fs_mode , " /run/media " ) ;
2015-02-13 09:41:01 +00:00
}
2015-11-26 16:22:37 +00:00
2016-05-06 14:37:47 +00:00
home_mode = ( FlatpakFilesystemMode ) g_hash_table_lookup ( context - > filesystems , " home " ) ;
2015-11-26 16:22:37 +00:00
if ( home_mode ! = 0 )
2015-02-13 09:41:01 +00:00
{
g_debug ( " Allowing homedir access " ) ;
2015-05-25 13:28:29 +00:00
home_access = TRUE ;
2016-04-29 09:39:39 +00:00
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , MAX ( home_mode , fs_mode ) , g_get_home_dir ( ) ) ;
2015-02-13 09:41:01 +00:00
}
2015-11-26 16:22:37 +00:00
if ( ! home_access )
2015-05-25 09:30:53 +00:00
{
2016-05-17 07:28:33 +00:00
/* Enable persistent mapping only if no access to real home dir */
2015-05-25 09:30:53 +00:00
g_hash_table_iter_init ( & iter , context - > persistent ) ;
while ( g_hash_table_iter_next ( & iter , & key , NULL ) )
{
const char * persist = key ;
g_autofree char * src = g_build_filename ( g_get_home_dir ( ) , " .var/app " , app_id , persist , NULL ) ;
g_autofree char * dest = g_build_filename ( g_get_home_dir ( ) , persist , NULL ) ;
g_mkdir_with_parents ( src , 0755 ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --bind " , src , dest ,
NULL ) ;
2015-05-25 09:30:53 +00:00
}
2015-05-25 13:28:29 +00:00
}
2016-08-24 12:11:45 +00:00
{
g_autofree char * run_user_app_dst = g_strdup_printf ( " /run/user/%d/app/%s " , getuid ( ) , app_id ) ;
g_autofree char * run_user_app_src = g_build_filename ( g_get_user_runtime_dir ( ) , " app " , app_id , NULL ) ;
if ( glnx_shutil_mkdir_p_at ( AT_FDCWD ,
run_user_app_src ,
0700 ,
NULL ,
NULL ) )
add_args ( argv_array ,
" --bind " , run_user_app_src , run_user_app_dst ,
NULL ) ;
}
2015-05-25 13:28:29 +00:00
g_hash_table_iter_init ( & iter , context - > filesystems ) ;
2015-09-09 12:11:05 +00:00
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
2015-05-25 13:28:29 +00:00
{
const char * filesystem = key ;
2016-05-06 14:37:47 +00:00
FlatpakFilesystemMode mode = GPOINTER_TO_INT ( value ) ;
2015-05-25 13:28:29 +00:00
2015-09-09 12:11:05 +00:00
if ( value = = NULL | |
strcmp ( filesystem , " host " ) = = 0 | |
2015-05-25 13:28:29 +00:00
strcmp ( filesystem , " home " ) = = 0 )
continue ;
if ( g_str_has_prefix ( filesystem , " xdg- " ) )
{
2016-02-25 15:51:45 +00:00
const char * path , * rest = NULL ;
2016-02-25 16:11:37 +00:00
const char * config_key = NULL ;
2016-02-25 15:51:45 +00:00
g_autofree char * subpath = NULL ;
2015-05-25 13:28:29 +00:00
2016-11-14 10:04:38 +00:00
if ( ! get_xdg_user_dir_from_string ( filesystem , & config_key , & rest , & path ) )
2015-05-25 13:28:29 +00:00
{
g_warning ( " Unsupported xdg dir %s \n " , filesystem ) ;
continue ;
}
2016-05-25 12:12:09 +00:00
if ( path = = NULL )
continue ; /* Unconfigured, ignore */
2015-05-25 13:28:29 +00:00
if ( strcmp ( path , g_get_home_dir ( ) ) = = 0 )
{
/* xdg-user-dirs sets disabled dirs to $HOME, and its in general not a good
idea to set full access to $ HOME other than explicitly , so we ignore
these */
g_debug ( " Xdg dir %s is $HOME (i.e. disabled), ignoring \n " , filesystem ) ;
continue ;
}
2016-02-25 15:51:45 +00:00
subpath = g_build_filename ( path , rest , NULL ) ;
2016-11-14 09:58:39 +00:00
if ( mode = = FLATPAK_FILESYSTEM_MODE_CREATE )
g_mkdir_with_parents ( subpath , 0755 ) ;
2016-02-25 15:51:45 +00:00
if ( g_file_test ( subpath , G_FILE_TEST_EXISTS ) )
2015-05-25 13:28:29 +00:00
{
if ( xdg_dirs_conf = = NULL )
xdg_dirs_conf = g_string_new ( " " ) ;
2016-02-25 16:11:37 +00:00
if ( config_key )
g_string_append_printf ( xdg_dirs_conf , " %s= \" %s \" \n " ,
config_key , path ) ;
2015-05-25 13:28:29 +00:00
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , mode , subpath ) ;
2015-05-25 13:28:29 +00:00
}
}
else if ( g_str_has_prefix ( filesystem , " ~/ " ) )
{
g_autofree char * path = NULL ;
2016-05-06 14:03:27 +00:00
path = g_build_filename ( g_get_home_dir ( ) , filesystem + 2 , NULL ) ;
2016-11-14 09:58:39 +00:00
if ( mode = = FLATPAK_FILESYSTEM_MODE_CREATE )
g_mkdir_with_parents ( path , 0755 ) ;
2015-11-26 14:37:17 +00:00
if ( g_file_test ( path , G_FILE_TEST_EXISTS ) )
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , mode , path ) ;
2015-05-25 13:28:29 +00:00
}
else if ( g_str_has_prefix ( filesystem , " / " ) )
{
2016-11-14 09:58:39 +00:00
if ( mode = = FLATPAK_FILESYSTEM_MODE_CREATE )
g_mkdir_with_parents ( filesystem , 0755 ) ;
2015-05-25 13:28:29 +00:00
if ( g_file_test ( filesystem , G_FILE_TEST_EXISTS ) )
2016-11-11 21:21:07 +00:00
add_expose_path ( fs_paths , mode , filesystem ) ;
2015-05-25 13:28:29 +00:00
}
else
2016-05-06 14:03:27 +00:00
{
g_warning ( " Unexpected filesystem arg %s \n " , filesystem ) ;
}
2015-05-25 13:28:29 +00:00
}
2016-04-29 09:39:39 +00:00
if ( app_id_dir )
2016-11-14 09:14:45 +00:00
{
g_autoptr ( GFile ) apps_dir = g_file_get_parent ( app_id_dir ) ;
/* Hide the .var/app dir by default (unless explicitly made visible) */
add_hide_path ( fs_paths , flatpak_file_get_path_cached ( apps_dir ) ) ;
/* But let the app write to the per-app dir in it */
add_expose_path ( fs_paths , FLATPAK_FILESYSTEM_MODE_READ_WRITE ,
flatpak_file_get_path_cached ( app_id_dir ) ) ;
}
2016-11-14 09:22:57 +00:00
/* Hide the flatpak dir by default (unless explicitly made visible) */
user_flatpak_dir = flatpak_get_user_base_dir_location ( ) ;
add_hide_path ( fs_paths , flatpak_file_get_path_cached ( user_flatpak_dir ) ) ;
2016-11-14 10:04:38 +00:00
/* This actually outputs the args for the hide/expose operations above */
2016-11-14 09:14:45 +00:00
add_file_args ( argv_array , fs_paths ) ;
2016-04-29 09:39:39 +00:00
2017-01-19 14:15:58 +00:00
/* Ensure we always have a homedir */
add_args ( argv_array ,
" --dir " , g_get_home_dir ( ) ,
NULL ) ;
2016-11-14 17:50:49 +00:00
/* Special case subdirectories of the cache, config and data xdg dirs.
* If these are accessible explicilty , in a read - write fashion , then
* we bind - mount these in the app - id dir . This allows applications to
* explicitly opt out of keeping some config / cache / data in the
* app - specific directory .
*/
if ( app_id_dir )
{
g_hash_table_iter_init ( & iter , context - > filesystems ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
{
const char * filesystem = key ;
FlatpakFilesystemMode mode = GPOINTER_TO_INT ( value ) ;
g_autofree char * xdg_path = NULL ;
const char * rest , * where ;
xdg_path = get_xdg_dir_from_string ( filesystem , & rest , & where ) ;
if ( xdg_path ! = NULL & & * rest ! = 0 & &
2017-01-27 09:43:59 +00:00
mode > = FLATPAK_FILESYSTEM_MODE_READ_WRITE )
2016-11-14 17:50:49 +00:00
{
g_autoptr ( GFile ) app_version = g_file_get_child ( app_id_dir , where ) ;
g_autoptr ( GFile ) app_version_subdir = g_file_resolve_relative_path ( app_version , rest ) ;
if ( g_file_test ( xdg_path , G_FILE_TEST_IS_DIR ) )
{
g_autofree char * xdg_path_in_app = g_file_get_path ( app_version_subdir ) ;
g_mkdir_with_parents ( xdg_path_in_app , 0755 ) ;
add_args ( argv_array ,
" --bind " , xdg_path , xdg_path_in_app ,
NULL ) ;
}
}
}
}
2015-07-10 10:36:54 +00:00
if ( home_access & & app_id_dir ! = NULL )
{
g_autofree char * src_path = g_build_filename ( g_get_user_config_dir ( ) ,
" user-dirs.dirs " ,
NULL ) ;
2016-08-22 08:20:19 +00:00
g_autofree char * path = g_build_filename ( flatpak_file_get_path_cached ( app_id_dir ) ,
2015-07-10 10:36:54 +00:00
" config/user-dirs.dirs " , NULL ) ;
2016-05-12 06:45:40 +00:00
if ( g_file_test ( src_path , G_FILE_TEST_EXISTS ) )
add_args ( argv_array ,
" --ro-bind " , src_path , path ,
NULL ) ;
2015-07-10 10:36:54 +00:00
}
else if ( xdg_dirs_conf ! = NULL & & app_id_dir ! = NULL )
2015-05-25 13:28:29 +00:00
{
g_autofree char * tmp_path = NULL ;
g_autofree char * path = NULL ;
int fd ;
2016-05-09 09:07:53 +00:00
fd = g_file_open_tmp ( " flatpak-user-dir-XXXXXX.dirs " , & tmp_path , NULL ) ;
2015-05-25 13:28:29 +00:00
if ( fd > = 0 )
{
close ( fd ) ;
if ( g_file_set_contents ( tmp_path , xdg_dirs_conf - > str , xdg_dirs_conf - > len , NULL ) )
{
2016-04-29 09:39:39 +00:00
int tmp_fd = open ( tmp_path , O_RDONLY ) ;
unlink ( tmp_path ) ;
2016-05-11 13:14:11 +00:00
if ( tmp_fd ! = - 1 )
2016-04-29 09:39:39 +00:00
{
g_autofree char * tmp_fd_str = g_strdup_printf ( " %d " , tmp_fd ) ;
2016-05-11 13:14:11 +00:00
if ( fd_array )
g_array_append_val ( fd_array , tmp_fd ) ;
2016-08-22 08:20:19 +00:00
path = g_build_filename ( flatpak_file_get_path_cached ( app_id_dir ) ,
2016-04-29 09:39:39 +00:00
" config/user-dirs.dirs " , NULL ) ;
add_args ( argv_array , " --file " , tmp_fd_str , path , NULL ) ;
}
2015-05-25 13:28:29 +00:00
}
}
g_string_free ( xdg_dirs_conf , TRUE ) ;
2015-05-25 09:30:53 +00:00
}
2015-02-13 09:41:01 +00:00
2016-05-11 13:14:11 +00:00
flatpak_run_add_x11_args ( argv_array , fd_array , envp_p ,
2016-05-10 08:53:24 +00:00
( context - > sockets & FLATPAK_CONTEXT_SOCKET_X11 ) ! = 0 ) ;
2015-02-13 09:41:01 +00:00
2016-05-06 14:37:47 +00:00
if ( context - > sockets & FLATPAK_CONTEXT_SOCKET_WAYLAND )
2015-02-13 09:41:01 +00:00
{
g_debug ( " Allowing wayland access " ) ;
2016-05-06 14:37:47 +00:00
flatpak_run_add_wayland_args ( argv_array , envp_p ) ;
2015-02-13 09:41:01 +00:00
}
2016-05-06 14:37:47 +00:00
if ( context - > sockets & FLATPAK_CONTEXT_SOCKET_PULSEAUDIO )
2015-02-13 09:41:01 +00:00
{
g_debug ( " Allowing pulseaudio access " ) ;
2016-05-11 13:14:11 +00:00
flatpak_run_add_pulseaudio_args ( argv_array , fd_array , envp_p ) ;
2015-02-13 09:41:01 +00:00
}
2016-05-06 14:37:47 +00:00
unrestricted_session_bus = ( context - > sockets & FLATPAK_CONTEXT_SOCKET_SESSION_BUS ) ! = 0 ;
2015-05-22 14:55:45 +00:00
if ( unrestricted_session_bus )
g_debug ( " Allowing session-dbus access " ) ;
2016-05-06 14:37:47 +00:00
if ( flatpak_run_add_session_dbus_args ( argv_array , envp_p , session_bus_proxy_argv , unrestricted_session_bus ) & &
2016-01-29 07:50:11 +00:00
! unrestricted_session_bus & & session_bus_proxy_argv )
2016-05-06 14:37:47 +00:00
flatpak_add_bus_filters ( session_bus_proxy_argv , context - > session_bus_policy , app_id , context ) ;
2015-05-12 12:44:08 +00:00
2016-05-06 14:37:47 +00:00
unrestricted_system_bus = ( context - > sockets & FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS ) ! = 0 ;
2016-01-29 07:50:11 +00:00
if ( unrestricted_system_bus )
g_debug ( " Allowing system-dbus access " ) ;
2016-05-06 14:37:47 +00:00
if ( flatpak_run_add_system_dbus_args ( context , envp_p , argv_array , system_bus_proxy_argv ,
2016-01-29 07:50:11 +00:00
unrestricted_system_bus ) & &
! unrestricted_system_bus & & system_bus_proxy_argv )
2016-05-06 14:37:47 +00:00
flatpak_add_bus_filters ( system_bus_proxy_argv , context - > system_bus_policy , NULL , context ) ;
2015-02-19 19:57:53 +00:00
2016-05-26 07:43:56 +00:00
if ( g_environ_getenv ( * envp_p , " LD_LIBRARY_PATH " ) ! = NULL )
{
/* LD_LIBRARY_PATH is overridden for setuid helper, so pass it as cmdline arg */
add_args ( argv_array ,
" --setenv " , " LD_LIBRARY_PATH " , g_environ_getenv ( * envp_p , " LD_LIBRARY_PATH " ) ,
NULL ) ;
* envp_p = g_environ_unsetenv ( * envp_p , " LD_LIBRARY_PATH " ) ;
}
2017-03-14 15:20:33 +00:00
/* Must run this before spawning the dbus proxy, to ensure it
ends up in the app cgroup */
if ( ! flatpak_run_in_transient_unit ( app_id , & my_error ) )
{
/* We still run along even if we don't get a cgroup, as nothing
really depends on it . Its just nice to have */
g_debug ( " Failed to run in transient scope: %s \n " , my_error - > message ) ;
g_clear_error ( & my_error ) ;
}
if ( ! add_dbus_proxy_args ( argv_array , session_bus_proxy_argv , ( flags & FLATPAK_RUN_FLAG_LOG_SESSION_BUS ) ! = 0 ,
sync_fds , app_info_path , error ) )
return FALSE ;
if ( ! add_dbus_proxy_args ( argv_array , system_bus_proxy_argv , ( flags & FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS ) ! = 0 ,
sync_fds , app_info_path , error ) )
return FALSE ;
if ( sync_fds [ 1 ] ! = - 1 )
close ( sync_fds [ 1 ] ) ;
return TRUE ;
2015-02-13 09:41:01 +00:00
}
2015-02-19 18:52:17 +00:00
2016-05-06 14:03:27 +00:00
static const struct { const char * env ;
const char * val ;
} default_exports [ ] = {
{ " PATH " , " /app/bin:/usr/bin " } ,
2016-04-29 09:39:39 +00:00
{ " LD_LIBRARY_PATH " , " /app/lib " } ,
2016-05-06 14:03:27 +00:00
{ " XDG_CONFIG_DIRS " , " /app/etc/xdg:/etc/xdg " } ,
{ " XDG_DATA_DIRS " , " /app/share:/usr/share " } ,
{ " SHELL " , " /bin/sh " } ,
2015-05-12 09:37:50 +00:00
} ;
2016-05-06 14:03:27 +00:00
static const struct { const char * env ;
const char * val ;
} devel_exports [ ] = {
{ " ACLOCAL_PATH " , " /app/share/aclocal " } ,
{ " C_INCLUDE_PATH " , " /app/include " } ,
{ " CPLUS_INCLUDE_PATH " , " /app/include " } ,
{ " LDFLAGS " , " -L/app/lib " } ,
{ " PKG_CONFIG_PATH " , " /app/lib/pkgconfig:/app/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig " } ,
{ " LC_ALL " , " en_US.utf8 " } ,
2015-05-12 09:37:50 +00:00
} ;
2015-05-12 09:05:52 +00:00
char * *
2016-05-06 14:37:47 +00:00
flatpak_run_get_minimal_env ( gboolean devel )
2015-02-19 18:52:17 +00:00
{
2015-05-12 09:05:52 +00:00
GPtrArray * env_array ;
2015-08-27 14:16:58 +00:00
static const char * const copy [ ] = {
2015-11-25 12:16:33 +00:00
" PWD " ,
2015-02-19 18:52:17 +00:00
" GDMSESSION " ,
" XDG_CURRENT_DESKTOP " ,
" XDG_SESSION_DESKTOP " ,
" DESKTOP_SESSION " ,
" EMAIL_ADDRESS " ,
" HOME " ,
" HOSTNAME " ,
" LOGNAME " ,
" REAL_NAME " ,
" TERM " ,
" USER " ,
" USERNAME " ,
} ;
2015-08-27 14:16:58 +00:00
static const char * const copy_nodevel [ ] = {
2015-02-19 18:52:17 +00:00
" LANG " ,
" LANGUAGE " ,
" LC_ALL " ,
" LC_ADDRESS " ,
" LC_COLLATE " ,
" LC_CTYPE " ,
" LC_IDENTIFICATION " ,
" LC_MEASUREMENT " ,
" LC_MESSAGES " ,
" LC_MONETARY " ,
" LC_NAME " ,
" LC_NUMERIC " ,
" LC_PAPER " ,
" LC_TELEPHONE " ,
" LC_TIME " ,
} ;
int i ;
2015-05-12 09:05:52 +00:00
env_array = g_ptr_array_new_with_free_func ( g_free ) ;
2016-05-06 14:03:27 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( default_exports ) ; i + + )
2015-05-12 09:37:50 +00:00
g_ptr_array_add ( env_array , g_strdup_printf ( " %s=%s " , default_exports [ i ] . env , default_exports [ i ] . val ) ) ;
2015-02-19 18:52:17 +00:00
if ( devel )
{
2015-05-12 09:37:50 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( devel_exports ) ; i + + )
g_ptr_array_add ( env_array , g_strdup_printf ( " %s=%s " , devel_exports [ i ] . env , devel_exports [ i ] . val ) ) ;
2015-02-19 18:52:17 +00:00
}
2016-05-06 14:03:27 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( copy ) ; i + + )
2015-02-19 18:52:17 +00:00
{
2016-05-06 14:03:27 +00:00
const char * current = g_getenv ( copy [ i ] ) ;
2015-02-19 18:52:17 +00:00
if ( current )
2015-05-12 09:05:52 +00:00
g_ptr_array_add ( env_array , g_strdup_printf ( " %s=%s " , copy [ i ] , current ) ) ;
2015-02-19 18:52:17 +00:00
}
if ( ! devel )
{
2016-05-06 14:03:27 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( copy_nodevel ) ; i + + )
2015-05-12 09:05:52 +00:00
{
2016-05-06 14:03:27 +00:00
const char * current = g_getenv ( copy_nodevel [ i ] ) ;
2015-05-12 09:05:52 +00:00
if ( current )
g_ptr_array_add ( env_array , g_strdup_printf ( " %s=%s " , copy_nodevel [ i ] , current ) ) ;
}
2015-02-19 18:52:17 +00:00
}
2015-05-12 09:05:52 +00:00
g_ptr_array_add ( env_array , NULL ) ;
2016-05-06 14:03:27 +00:00
return ( char * * ) g_ptr_array_free ( env_array , FALSE ) ;
2015-02-19 18:52:17 +00:00
}
2015-02-19 21:52:01 +00:00
2015-05-12 09:37:50 +00:00
char * *
2016-05-06 14:37:47 +00:00
flatpak_run_apply_env_default ( char * * envp )
2015-05-12 09:37:50 +00:00
{
int i ;
2016-05-06 14:03:27 +00:00
for ( i = 0 ; i < G_N_ELEMENTS ( default_exports ) ; i + + )
2015-05-12 09:37:50 +00:00
envp = g_environ_setenv ( envp , default_exports [ i ] . env , default_exports [ i ] . val , TRUE ) ;
return envp ;
}
char * *
2016-05-06 14:37:47 +00:00
flatpak_run_apply_env_appid ( char * * envp ,
2016-05-06 14:03:27 +00:00
GFile * app_dir )
2015-05-12 09:37:50 +00:00
{
g_autoptr ( GFile ) app_dir_data = NULL ;
g_autoptr ( GFile ) app_dir_config = NULL ;
g_autoptr ( GFile ) app_dir_cache = NULL ;
app_dir_data = g_file_get_child ( app_dir , " data " ) ;
app_dir_config = g_file_get_child ( app_dir , " config " ) ;
app_dir_cache = g_file_get_child ( app_dir , " cache " ) ;
2016-08-22 08:20:19 +00:00
envp = g_environ_setenv ( envp , " XDG_DATA_HOME " , flatpak_file_get_path_cached ( app_dir_data ) , TRUE ) ;
envp = g_environ_setenv ( envp , " XDG_CONFIG_HOME " , flatpak_file_get_path_cached ( app_dir_config ) , TRUE ) ;
envp = g_environ_setenv ( envp , " XDG_CACHE_HOME " , flatpak_file_get_path_cached ( app_dir_cache ) , TRUE ) ;
2015-05-12 09:37:50 +00:00
return envp ;
}
2015-05-12 09:13:44 +00:00
char * *
2016-05-06 14:37:47 +00:00
flatpak_run_apply_env_vars ( char * * envp , FlatpakContext * context )
2015-05-12 09:13:44 +00:00
{
2015-05-22 14:55:45 +00:00
GHashTableIter iter ;
gpointer key , value ;
2015-05-12 09:13:44 +00:00
2015-05-22 14:55:45 +00:00
g_hash_table_iter_init ( & iter , context - > env_vars ) ;
while ( g_hash_table_iter_next ( & iter , & key , & value ) )
2015-05-12 09:13:44 +00:00
{
2015-05-22 14:55:45 +00:00
const char * var = key ;
const char * val = value ;
if ( val & & val [ 0 ] ! = 0 )
envp = g_environ_setenv ( envp , var , val , TRUE ) ;
else
envp = g_environ_unsetenv ( envp , var ) ;
2015-05-12 09:13:44 +00:00
}
return envp ;
}
2015-02-19 21:52:01 +00:00
GFile *
2016-05-06 14:37:47 +00:00
flatpak_get_data_dir ( const char * app_id )
2015-02-19 21:52:01 +00:00
{
2015-03-20 15:21:19 +00:00
g_autoptr ( GFile ) home = g_file_new_for_path ( g_get_home_dir ( ) ) ;
g_autoptr ( GFile ) var_app = g_file_resolve_relative_path ( home , " .var/app " ) ;
2015-02-19 21:52:01 +00:00
return g_file_get_child ( var_app , app_id ) ;
}
GFile *
2016-05-06 14:37:47 +00:00
flatpak_ensure_data_dir ( const char * app_id ,
2016-05-06 14:03:27 +00:00
GCancellable * cancellable ,
GError * * error )
2015-02-19 21:52:01 +00:00
{
2016-05-06 14:37:47 +00:00
g_autoptr ( GFile ) dir = flatpak_get_data_dir ( app_id ) ;
2015-03-20 15:21:19 +00:00
g_autoptr ( GFile ) data_dir = g_file_get_child ( dir , " data " ) ;
g_autoptr ( GFile ) cache_dir = g_file_get_child ( dir , " cache " ) ;
2017-01-16 12:01:57 +00:00
g_autoptr ( GFile ) tmp_dir = g_file_get_child ( cache_dir , " tmp " ) ;
2015-03-20 15:21:19 +00:00
g_autoptr ( GFile ) config_dir = g_file_get_child ( dir , " config " ) ;
2015-02-19 21:52:01 +00:00
2016-08-22 07:15:46 +00:00
if ( ! flatpak_mkdir_p ( data_dir , cancellable , error ) )
2015-02-19 21:52:01 +00:00
return NULL ;
2016-08-22 07:15:46 +00:00
if ( ! flatpak_mkdir_p ( cache_dir , cancellable , error ) )
2015-02-19 21:52:01 +00:00
return NULL ;
2017-01-16 12:01:57 +00:00
if ( ! flatpak_mkdir_p ( tmp_dir , cancellable , error ) )
return NULL ;
2016-08-22 07:15:46 +00:00
if ( ! flatpak_mkdir_p ( config_dir , cancellable , error ) )
2015-02-19 21:52:01 +00:00
return NULL ;
return g_object_ref ( dir ) ;
}
2015-03-04 13:40:17 +00:00
2016-05-06 14:03:27 +00:00
struct JobData
{
char * job ;
2015-03-04 13:40:17 +00:00
GMainLoop * main_loop ;
} ;
static void
job_removed_cb ( SystemdManager * manager ,
2016-05-06 14:03:27 +00:00
guint32 id ,
char * job ,
char * unit ,
char * result ,
2015-03-04 13:40:17 +00:00
struct JobData * data )
{
if ( strcmp ( job , data - > job ) = = 0 )
g_main_loop_quit ( data - > main_loop ) ;
}
2016-01-28 10:15:58 +00:00
gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_in_transient_unit ( const char * appid , GError * * error )
2016-01-28 10:15:58 +00:00
{
g_autoptr ( GDBusConnection ) conn = NULL ;
g_autofree char * path = NULL ;
g_autofree char * address = NULL ;
g_autofree char * name = NULL ;
g_autofree char * job = NULL ;
2015-03-04 13:40:17 +00:00
SystemdManager * manager = NULL ;
GVariantBuilder builder ;
GVariant * properties = NULL ;
GVariant * aux = NULL ;
guint32 pid ;
GMainContext * main_context = NULL ;
GMainLoop * main_loop = NULL ;
struct JobData data ;
2016-01-28 10:15:58 +00:00
gboolean res = FALSE ;
2015-03-04 13:40:17 +00:00
2016-05-06 14:03:27 +00:00
path = g_strdup_printf ( " /run/user/%d/systemd/private " , getuid ( ) ) ;
2015-03-04 13:40:17 +00:00
if ( ! g_file_test ( path , G_FILE_TEST_EXISTS ) )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error ,
2017-02-21 14:41:43 +00:00
" No systemd user session available, cgroups not available " ) ;
2015-03-04 13:40:17 +00:00
main_context = g_main_context_new ( ) ;
main_loop = g_main_loop_new ( main_context , FALSE ) ;
g_main_context_push_thread_default ( main_context ) ;
address = g_strconcat ( " unix:path= " , path , NULL ) ;
conn = g_dbus_connection_new_for_address_sync ( address ,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT ,
NULL ,
2016-01-28 10:15:58 +00:00
NULL , error ) ;
2015-03-04 13:40:17 +00:00
if ( ! conn )
2016-01-28 10:15:58 +00:00
goto out ;
2015-03-04 13:40:17 +00:00
manager = systemd_manager_proxy_new_sync ( conn ,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ,
NULL ,
" /org/freedesktop/systemd1 " ,
2016-01-28 10:15:58 +00:00
NULL , error ) ;
2015-03-04 13:40:17 +00:00
if ( ! manager )
2016-01-28 10:15:58 +00:00
goto out ;
2015-03-04 13:40:17 +00:00
2016-05-09 09:07:53 +00:00
name = g_strdup_printf ( " flatpak-%s-%d.scope " , appid , getpid ( ) ) ;
2015-03-04 13:40:17 +00:00
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " a(sv) " ) ) ;
pid = getpid ( ) ;
g_variant_builder_add ( & builder , " (sv) " ,
" PIDs " ,
g_variant_new_fixed_array ( G_VARIANT_TYPE ( " u " ) ,
& pid , 1 , sizeof ( guint32 ) )
2016-05-06 14:03:27 +00:00
) ;
2015-03-04 13:40:17 +00:00
properties = g_variant_builder_end ( & builder ) ;
aux = g_variant_new_array ( G_VARIANT_TYPE ( " (sa(sv)) " ) , NULL , 0 ) ;
if ( ! systemd_manager_call_start_transient_unit_sync ( manager ,
name ,
" fail " ,
properties ,
aux ,
& job ,
NULL ,
2016-01-28 10:15:58 +00:00
error ) )
goto out ;
2015-03-04 13:40:17 +00:00
data . job = job ;
data . main_loop = main_loop ;
2016-05-06 14:03:27 +00:00
g_signal_connect ( manager , " job-removed " , G_CALLBACK ( job_removed_cb ) , & data ) ;
2015-03-04 13:40:17 +00:00
g_main_loop_run ( main_loop ) ;
2016-01-28 10:15:58 +00:00
res = TRUE ;
2016-05-06 14:03:27 +00:00
out :
2015-03-04 13:40:17 +00:00
if ( main_context )
{
g_main_context_pop_thread_default ( main_context ) ;
g_main_context_unref ( main_context ) ;
}
if ( main_loop )
g_main_loop_unref ( main_loop ) ;
if ( manager )
g_object_unref ( manager ) ;
2016-01-28 10:15:58 +00:00
return res ;
2015-03-04 13:40:17 +00:00
}
2015-12-07 11:27:53 +00:00
static void
2015-12-07 12:04:45 +00:00
add_font_path_args ( GPtrArray * argv_array )
2015-12-07 11:27:53 +00:00
{
g_autoptr ( GFile ) home = NULL ;
g_autoptr ( GFile ) user_font1 = NULL ;
g_autoptr ( GFile ) user_font2 = NULL ;
2016-06-03 17:28:35 +00:00
if ( g_file_test ( SYSTEM_FONTS_DIR , G_FILE_TEST_EXISTS ) )
{
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , SYSTEM_FONTS_DIR , " /run/host/fonts " ,
2016-06-03 17:28:35 +00:00
NULL ) ;
}
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
home = g_file_new_for_path ( g_get_home_dir ( ) ) ;
user_font1 = g_file_resolve_relative_path ( home , " .local/share/fonts " ) ;
user_font2 = g_file_resolve_relative_path ( home , " .fonts " ) ;
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
if ( g_file_query_exists ( user_font1 , NULL ) )
2015-12-07 11:27:53 +00:00
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , flatpak_file_get_path_cached ( user_font1 ) , " /run/host/user-fonts " ,
2016-04-29 09:39:39 +00:00
NULL ) ;
2015-12-07 11:27:53 +00:00
}
2015-12-07 12:04:45 +00:00
else if ( g_file_query_exists ( user_font2 , NULL ) )
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , flatpak_file_get_path_cached ( user_font2 ) , " /run/host/user-fonts " ,
2016-04-29 09:39:39 +00:00
NULL ) ;
2015-12-07 12:04:45 +00:00
}
}
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
static void
2016-05-06 14:37:47 +00:00
add_default_permissions ( FlatpakContext * app_context )
2015-12-07 12:04:45 +00:00
{
2016-05-06 14:37:47 +00:00
flatpak_context_set_session_bus_policy ( app_context ,
2016-06-09 14:03:54 +00:00
" org.freedesktop.portal.* " ,
2016-05-06 14:37:47 +00:00
FLATPAK_POLICY_TALK ) ;
2015-12-07 12:04:45 +00:00
}
2015-12-07 11:27:53 +00:00
2016-05-06 14:37:47 +00:00
static FlatpakContext *
2015-12-07 12:04:45 +00:00
compute_permissions ( GKeyFile * app_metadata ,
GKeyFile * runtime_metadata ,
2016-05-06 14:03:27 +00:00
GError * * error )
2015-12-07 12:04:45 +00:00
{
2016-05-06 14:37:47 +00:00
g_autoptr ( FlatpakContext ) app_context = NULL ;
2015-12-07 11:27:53 +00:00
2016-05-06 14:37:47 +00:00
app_context = flatpak_context_new ( ) ;
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
add_default_permissions ( app_context ) ;
2015-12-07 11:27:53 +00:00
2016-05-06 14:37:47 +00:00
if ( ! flatpak_context_load_metadata ( app_context , runtime_metadata , error ) )
2015-12-07 12:04:45 +00:00
return NULL ;
2015-12-07 11:27:53 +00:00
2016-10-19 15:30:58 +00:00
if ( app_metadata ! = NULL & &
! flatpak_context_load_metadata ( app_context , app_metadata , error ) )
2015-12-07 12:04:45 +00:00
return NULL ;
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
return g_steal_pointer ( & app_context ) ;
}
2015-12-07 11:27:53 +00:00
2016-09-02 12:01:44 +00:00
gboolean
flatpak_run_add_app_info_args ( GPtrArray * argv_array ,
GArray * fd_array ,
GFile * app_files ,
2016-09-07 10:19:13 +00:00
GFile * runtime_files ,
2016-09-02 12:01:44 +00:00
const char * app_id ,
2016-09-07 10:31:56 +00:00
const char * app_branch ,
2016-09-02 12:01:44 +00:00
const char * runtime_ref ,
FlatpakContext * final_app_context ,
2016-09-08 09:21:00 +00:00
char * * app_info_path_out ,
2016-09-02 12:01:44 +00:00
GError * * error )
2015-12-07 12:04:45 +00:00
{
g_autofree char * tmp_path = NULL ;
int fd ;
2016-09-08 08:16:40 +00:00
g_autoptr ( GKeyFile ) keyfile = NULL ;
g_autofree char * runtime_path = NULL ;
g_autofree char * fd_str = NULL ;
g_autofree char * old_dest = g_strdup_printf ( " /run/user/%d/flatpak-info " , getuid ( ) ) ;
2016-10-19 15:30:58 +00:00
const char * group ;
2015-12-07 11:27:53 +00:00
2016-05-09 09:07:53 +00:00
fd = g_file_open_tmp ( " flatpak-context-XXXXXX " , & tmp_path , NULL ) ;
2016-09-08 08:16:40 +00:00
if ( fd < 0 )
2015-12-07 12:04:45 +00:00
{
2016-09-14 15:32:45 +00:00
int errsv = errno ;
g_set_error ( error , G_IO_ERROR , g_io_error_from_errno ( errsv ) ,
_ ( " Failed to open flatpak-info temp file: %s " ) , g_strerror ( errsv ) ) ;
2016-09-08 08:16:40 +00:00
return FALSE ;
}
2015-12-07 11:27:53 +00:00
2016-09-08 08:16:40 +00:00
close ( fd ) ;
2015-12-07 11:27:53 +00:00
2016-09-08 08:16:40 +00:00
keyfile = g_key_file_new ( ) ;
2015-12-07 11:27:53 +00:00
2016-10-19 15:30:58 +00:00
if ( app_files )
group = " Application " ;
else
group = " Runtime " ;
g_key_file_set_string ( keyfile , group , " name " , app_id ) ;
g_key_file_set_string ( keyfile , group , " runtime " , runtime_ref ) ;
2016-09-07 10:19:13 +00:00
2016-10-19 15:30:58 +00:00
if ( app_files )
{
g_autofree char * app_path = g_file_get_path ( app_files ) ;
g_key_file_set_string ( keyfile , " Instance " , " app-path " , app_path ) ;
}
2016-09-08 08:16:40 +00:00
runtime_path = g_file_get_path ( runtime_files ) ;
2016-09-08 12:10:18 +00:00
g_key_file_set_string ( keyfile , " Instance " , " runtime-path " , runtime_path ) ;
if ( app_branch ! = NULL )
g_key_file_set_string ( keyfile , " Instance " , " branch " , app_branch ) ;
2015-12-07 11:27:53 +00:00
2016-09-19 14:33:48 +00:00
g_key_file_set_string ( keyfile , " Instance " , " flatpak-version " , PACKAGE_VERSION ) ;
2016-12-07 10:31:45 +00:00
if ( ( final_app_context - > sockets & FLATPAK_CONTEXT_SOCKET_SESSION_BUS ) = = 0 )
g_key_file_set_boolean ( keyfile , " Instance " , " session-bus-proxy " , TRUE ) ;
if ( ( final_app_context - > sockets & FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS ) = = 0 )
g_key_file_set_boolean ( keyfile , " Instance " , " system-bus-proxy " , TRUE ) ;
2016-09-08 08:16:40 +00:00
flatpak_context_save_metadata ( final_app_context , TRUE , keyfile ) ;
2015-12-07 12:04:45 +00:00
2016-09-08 08:16:40 +00:00
if ( ! g_key_file_save_to_file ( keyfile , tmp_path , error ) )
return FALSE ;
2016-04-29 09:39:39 +00:00
2016-09-08 08:16:40 +00:00
fd = open ( tmp_path , O_RDONLY ) ;
if ( fd = = - 1 )
{
2016-09-14 15:32:45 +00:00
int errsv = errno ;
g_set_error ( error , G_IO_ERROR , g_io_error_from_errno ( errsv ) ,
_ ( " Failed to open temp file: %s " ) , g_strerror ( errsv ) ) ;
2016-09-08 08:16:40 +00:00
return FALSE ;
2015-12-07 11:27:53 +00:00
}
2016-09-08 08:16:40 +00:00
unlink ( tmp_path ) ;
fd_str = g_strdup_printf ( " %d " , fd ) ;
if ( fd_array )
g_array_append_val ( fd_array , fd ) ;
add_args ( argv_array ,
" --ro-bind-data " , fd_str , " /.flatpak-info " ,
" --symlink " , " ../../../.flatpak-info " , old_dest ,
NULL ) ;
2016-09-08 09:21:00 +00:00
if ( app_info_path_out ! = NULL )
* app_info_path_out = g_strdup_printf ( " /proc/self/fd/%d " , fd ) ;
2015-12-07 12:04:45 +00:00
return TRUE ;
}
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
static void
2016-05-25 14:38:50 +00:00
add_monitor_path_args ( gboolean use_session_helper ,
GPtrArray * argv_array )
2015-12-07 12:04:45 +00:00
{
2016-05-09 09:07:53 +00:00
g_autoptr ( AutoFlatpakSessionHelper ) session_helper = NULL ;
2015-12-07 12:04:45 +00:00
g_autofree char * monitor_path = NULL ;
2015-12-07 11:27:53 +00:00
2016-05-25 14:38:50 +00:00
if ( use_session_helper )
{
session_helper =
flatpak_session_helper_proxy_new_for_bus_sync ( G_BUS_TYPE_SESSION ,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS ,
" org.freedesktop.Flatpak " ,
" /org/freedesktop/Flatpak/SessionHelper " ,
NULL , NULL ) ;
}
2015-12-07 11:27:53 +00:00
if ( session_helper & &
2016-05-09 09:07:53 +00:00
flatpak_session_helper_call_request_monitor_sync ( session_helper ,
2015-12-07 11:27:53 +00:00
& monitor_path ,
NULL , NULL ) )
{
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , monitor_path , " /run/host/monitor " ,
2016-04-29 09:39:39 +00:00
NULL ) ;
add_args ( argv_array ,
" --symlink " , " /run/host/monitor/localtime " , " /etc/localtime " ,
NULL ) ;
2016-11-23 14:36:12 +00:00
add_args ( argv_array ,
" --symlink " , " /run/host/monitor/resolv.conf " , " /etc/resolv.conf " ,
NULL ) ;
2015-12-07 11:27:53 +00:00
}
else
2016-04-29 09:39:39 +00:00
{
2016-11-23 14:36:12 +00:00
/* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
* non - existing targets ) , in which case we don ' t want to attempt to create
* bogus symlinks or bind mounts , as that will cause flatpak run to fail .
*/
if ( g_file_test ( " /etc/localtime " , G_FILE_TEST_EXISTS ) )
2016-04-29 09:39:39 +00:00
{
2016-11-23 14:36:12 +00:00
char localtime [ PATH_MAX + 1 ] ;
ssize_t symlink_size ;
2016-11-25 12:03:38 +00:00
gboolean is_reachable = FALSE ;
2016-11-23 14:36:12 +00:00
symlink_size = readlink ( " /etc/localtime " , localtime , sizeof ( localtime ) - 1 ) ;
if ( symlink_size > 0 )
{
2016-11-25 12:03:38 +00:00
g_autoptr ( GFile ) base_file = NULL ;
g_autoptr ( GFile ) target_file = NULL ;
g_autofree char * target_canonical = NULL ;
/* readlink() does not append a null byte to the buffer. */
2016-11-23 14:36:12 +00:00
localtime [ symlink_size ] = 0 ;
2016-11-25 12:03:38 +00:00
base_file = g_file_new_for_path ( " /etc " ) ;
target_file = g_file_resolve_relative_path ( base_file , localtime ) ;
target_canonical = g_file_get_path ( target_file ) ;
is_reachable = g_str_has_prefix ( target_canonical , " /usr/ " ) ;
}
if ( is_reachable )
{
2016-11-23 14:36:12 +00:00
add_args ( argv_array ,
" --symlink " , localtime , " /etc/localtime " ,
NULL ) ;
}
else
{
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , " /etc/localtime " , " /etc/localtime " ,
2016-11-23 14:36:12 +00:00
NULL ) ;
}
2016-04-29 09:39:39 +00:00
}
2016-11-23 14:36:12 +00:00
if ( g_file_test ( " /etc/resolv.conf " , G_FILE_TEST_EXISTS ) )
2016-05-06 14:03:27 +00:00
{
add_args ( argv_array ,
2017-01-26 16:05:23 +00:00
" --ro-bind " , " /etc/resolv.conf " , " /etc/resolv.conf " ,
2016-05-06 14:03:27 +00:00
NULL ) ;
}
2016-04-29 09:39:39 +00:00
}
2015-12-07 12:04:45 +00:00
}
static void
2016-05-06 14:03:27 +00:00
add_document_portal_args ( GPtrArray * argv_array ,
2015-12-07 12:04:45 +00:00
const char * app_id )
{
g_autoptr ( GDBusConnection ) session_bus = NULL ;
g_autofree char * doc_mount_path = NULL ;
2015-12-07 11:27:53 +00:00
session_bus = g_bus_get_sync ( G_BUS_TYPE_SESSION , NULL , NULL ) ;
if ( session_bus )
{
2016-05-06 14:03:27 +00:00
g_autoptr ( GError ) local_error = NULL ;
g_autoptr ( GDBusMessage ) reply = NULL ;
g_autoptr ( GDBusMessage ) msg =
2015-12-07 11:27:53 +00:00
g_dbus_message_new_method_call ( " org.freedesktop.portal.Documents " ,
" /org/freedesktop/portal/documents " ,
" org.freedesktop.portal.Documents " ,
" GetMountPoint " ) ;
g_dbus_message_set_body ( msg , g_variant_new ( " () " ) ) ;
reply =
g_dbus_connection_send_message_with_reply_sync ( session_bus , msg ,
G_DBUS_SEND_MESSAGE_FLAGS_NONE ,
30000 ,
NULL ,
NULL ,
NULL ) ;
if ( reply )
{
if ( g_dbus_message_to_gerror ( reply , & local_error ) )
2016-05-06 14:03:27 +00:00
{
2016-06-24 20:48:28 +00:00
g_message ( " Can't get document portal: %s \n " , local_error - > message ) ;
2016-05-06 14:03:27 +00:00
}
2015-12-07 11:27:53 +00:00
else
2015-12-07 12:04:45 +00:00
{
2016-04-29 09:39:39 +00:00
g_autofree char * src_path = NULL ;
g_autofree char * dst_path = NULL ;
2015-12-07 12:04:45 +00:00
g_variant_get ( g_dbus_message_get_body ( reply ) ,
" (^ay) " , & doc_mount_path ) ;
2016-04-29 09:39:39 +00:00
src_path = g_strdup_printf ( " %s/by-app/%s " ,
doc_mount_path , app_id ) ;
2016-05-06 14:03:27 +00:00
dst_path = g_strdup_printf ( " /run/user/%d/doc " , getuid ( ) ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array , " --bind " , src_path , dst_path , NULL ) ;
2015-12-07 12:04:45 +00:00
}
2015-12-07 11:27:53 +00:00
}
}
2015-12-07 12:04:45 +00:00
}
2015-12-07 11:27:53 +00:00
2017-03-22 18:50:48 +00:00
static gchar *
2016-09-08 09:21:00 +00:00
join_args ( GPtrArray * argv_array , gsize * len_out )
{
gchar * string ;
gchar * ptr ;
gint i ;
gsize len = 0 ;
for ( i = 0 ; i < argv_array - > len ; i + + )
len + = strlen ( argv_array - > pdata [ i ] ) + 1 ;
string = g_new ( gchar , len ) ;
* string = 0 ;
ptr = string ;
for ( i = 0 ; i < argv_array - > len ; i + + )
ptr = g_stpcpy ( ptr , argv_array - > pdata [ i ] ) + 1 ;
* len_out = len ;
return string ;
}
typedef struct {
int sync_fd ;
int app_info_fd ;
int bwrap_args_fd ;
} DbusProxySpawnData ;
2015-12-07 12:04:45 +00:00
static void
dbus_spawn_child_setup ( gpointer user_data )
{
2016-09-08 09:21:00 +00:00
DbusProxySpawnData * data = user_data ;
2016-05-06 14:03:27 +00:00
2016-09-08 09:21:00 +00:00
/* Unset CLOEXEC */
fcntl ( data - > sync_fd , F_SETFD , 0 ) ;
fcntl ( data - > app_info_fd , F_SETFD , 0 ) ;
fcntl ( data - > bwrap_args_fd , F_SETFD , 0 ) ;
}
/* This wraps the argv in a bwrap call, primary to allow the
command to be run with a proper / . flatpak - info with data
taken from app_info_fd */
static gboolean
prepend_bwrap_argv_wrapper ( GPtrArray * argv ,
int app_info_fd ,
int * bwrap_fd_out ,
GError * * error )
{
int i = 0 ;
g_auto ( GLnxDirFdIterator ) dir_iter = { 0 } ;
struct dirent * dent ;
g_autoptr ( GPtrArray ) bwrap_args = g_ptr_array_new_with_free_func ( g_free ) ;
gsize bwrap_args_len ;
glnx_fd_close int bwrap_args_fd = - 1 ;
g_autofree char * bwrap_args_data = NULL ;
2017-01-23 17:24:21 +00:00
g_autofree char * proxy_socket_dir = g_build_filename ( g_get_user_runtime_dir ( ) , " .dbus-proxy/ " , NULL ) ;
2016-09-08 09:21:00 +00:00
if ( ! glnx_dirfd_iterator_init_at ( AT_FDCWD , " / " , FALSE , & dir_iter , error ) )
return FALSE ;
while ( TRUE )
{
if ( ! glnx_dirfd_iterator_next_dent_ensure_dtype ( & dir_iter , & dent , NULL , error ) )
return FALSE ;
if ( dent = = NULL )
break ;
if ( strcmp ( dent - > d_name , " .flatpak-info " ) = = 0 )
continue ;
if ( dent - > d_type = = DT_DIR )
{
if ( strcmp ( dent - > d_name , " tmp " ) = = 0 | |
strcmp ( dent - > d_name , " var " ) = = 0 | |
strcmp ( dent - > d_name , " run " ) = = 0 )
g_ptr_array_add ( bwrap_args , g_strdup ( " --bind " ) ) ;
else
g_ptr_array_add ( bwrap_args , g_strdup ( " --ro-bind " ) ) ;
g_ptr_array_add ( bwrap_args , g_strconcat ( " / " , dent - > d_name , NULL ) ) ;
g_ptr_array_add ( bwrap_args , g_strconcat ( " / " , dent - > d_name , NULL ) ) ;
}
else if ( dent - > d_type = = DT_LNK )
{
ssize_t symlink_size ;
char path_buffer [ PATH_MAX + 1 ] ;
symlink_size = readlinkat ( dir_iter . fd , dent - > d_name , path_buffer , sizeof ( path_buffer ) - 1 ) ;
if ( symlink_size < 0 )
{
glnx_set_error_from_errno ( error ) ;
return FALSE ;
}
path_buffer [ symlink_size ] = 0 ;
g_ptr_array_add ( bwrap_args , g_strdup ( " --symlink " ) ) ;
g_ptr_array_add ( bwrap_args , g_strdup ( path_buffer ) ) ;
g_ptr_array_add ( bwrap_args , g_strconcat ( " / " , dent - > d_name , NULL ) ) ;
}
}
2017-01-23 17:24:21 +00:00
g_ptr_array_add ( bwrap_args , g_strdup ( " --bind " ) ) ;
g_ptr_array_add ( bwrap_args , g_strdup ( proxy_socket_dir ) ) ;
g_ptr_array_add ( bwrap_args , g_strdup ( proxy_socket_dir ) ) ;
2016-09-08 09:21:00 +00:00
g_ptr_array_add ( bwrap_args , g_strdup ( " --ro-bind-data " ) ) ;
g_ptr_array_add ( bwrap_args , g_strdup_printf ( " %d " , app_info_fd ) ) ;
g_ptr_array_add ( bwrap_args , g_strdup ( " /.flatpak-info " ) ) ;
bwrap_args_data = join_args ( bwrap_args , & bwrap_args_len ) ;
bwrap_args_fd = create_tmp_fd ( bwrap_args_data , bwrap_args_len , error ) ;
if ( bwrap_args_fd < 0 )
return FALSE ;
g_ptr_array_insert ( argv , i + + , g_strdup ( flatpak_get_bwrap ( ) ) ) ;
g_ptr_array_insert ( argv , i + + , g_strdup ( " --args " ) ) ;
g_ptr_array_insert ( argv , i + + , g_strdup_printf ( " %d " , bwrap_args_fd ) ) ;
* bwrap_fd_out = bwrap_args_fd ;
bwrap_args_fd = - 1 ; /* Steal it */
return TRUE ;
2015-12-07 12:04:45 +00:00
}
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
static gboolean
add_dbus_proxy_args ( GPtrArray * argv_array ,
GPtrArray * dbus_proxy_argv ,
2016-04-14 14:01:42 +00:00
gboolean enable_logging ,
2016-05-06 14:03:27 +00:00
int sync_fds [ 2 ] ,
2016-09-08 09:21:00 +00:00
const char * app_info_path ,
2016-05-06 14:03:27 +00:00
GError * * error )
2015-12-07 12:04:45 +00:00
{
char x = ' x ' ;
2016-05-03 08:27:36 +00:00
const char * proxy ;
2016-07-28 13:06:23 +00:00
g_autofree char * commandline = NULL ;
2016-09-08 09:21:00 +00:00
DbusProxySpawnData spawn_data ;
glnx_fd_close int app_info_fd = - 1 ;
glnx_fd_close int bwrap_args_fd = - 1 ;
2015-12-07 11:27:53 +00:00
2017-03-14 15:20:33 +00:00
if ( dbus_proxy_argv = = NULL | |
dbus_proxy_argv - > len = = 0 )
2015-12-07 12:04:45 +00:00
return TRUE ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
if ( sync_fds [ 0 ] = = - 1 )
2015-12-07 11:27:53 +00:00
{
2016-04-29 09:39:39 +00:00
g_autofree char * fd_str = NULL ;
if ( pipe ( sync_fds ) < 0 )
{
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( errno ) ,
_ ( " Unable to create sync pipe " ) ) ;
2016-04-29 09:39:39 +00:00
return FALSE ;
}
fd_str = g_strdup_printf ( " %d " , sync_fds [ 0 ] ) ;
add_args ( argv_array , " --sync-fd " , fd_str , NULL ) ;
2015-12-07 11:27:53 +00:00
}
2015-12-07 12:04:45 +00:00
2016-05-06 14:37:47 +00:00
proxy = g_getenv ( " FLATPAK_DBUSPROXY " ) ;
2016-05-03 08:27:36 +00:00
if ( proxy = = NULL )
proxy = DBUSPROXY ;
g_ptr_array_insert ( dbus_proxy_argv , 0 , g_strdup ( proxy ) ) ;
2016-04-29 09:39:39 +00:00
g_ptr_array_insert ( dbus_proxy_argv , 1 , g_strdup_printf ( " --fd=%d " , sync_fds [ 1 ] ) ) ;
2016-09-08 09:21:00 +00:00
2016-04-14 14:01:42 +00:00
if ( enable_logging )
2016-07-28 13:06:23 +00:00
g_ptr_array_add ( dbus_proxy_argv , g_strdup ( " --log " ) ) ;
2015-12-07 12:04:45 +00:00
g_ptr_array_add ( dbus_proxy_argv , NULL ) ; /* NULL terminate */
2016-09-08 09:21:00 +00:00
app_info_fd = open ( app_info_path , O_RDONLY ) ;
if ( app_info_fd = = - 1 )
{
int errsv = errno ;
g_set_error ( error , G_IO_ERROR , g_io_error_from_errno ( errsv ) ,
2016-09-14 16:47:56 +00:00
_ ( " Failed to open app info file: %s " ) , g_strerror ( errsv ) ) ;
2016-09-08 09:21:00 +00:00
return FALSE ;
}
if ( ! prepend_bwrap_argv_wrapper ( dbus_proxy_argv , app_info_fd , & bwrap_args_fd , error ) )
return FALSE ;
2017-02-21 17:56:11 +00:00
commandline = flatpak_quote_argv ( ( const char * * ) dbus_proxy_argv - > pdata ) ;
2016-08-05 17:33:32 +00:00
g_debug ( " Running '%s' " , commandline ) ;
2016-07-28 13:06:23 +00:00
2016-09-08 09:21:00 +00:00
spawn_data . sync_fd = sync_fds [ 1 ] ;
spawn_data . app_info_fd = app_info_fd ;
spawn_data . bwrap_args_fd = bwrap_args_fd ;
2015-12-07 12:04:45 +00:00
if ( ! g_spawn_async ( NULL ,
2016-05-06 14:03:27 +00:00
( char * * ) dbus_proxy_argv - > pdata ,
2015-12-07 12:04:45 +00:00
NULL ,
G_SPAWN_SEARCH_PATH ,
dbus_spawn_child_setup ,
2016-09-08 09:21:00 +00:00
& spawn_data ,
2015-12-07 12:04:45 +00:00
NULL , error ) )
2015-12-07 11:27:53 +00:00
{
2016-04-29 09:39:39 +00:00
close ( sync_fds [ 0 ] ) ;
close ( sync_fds [ 1 ] ) ;
2015-12-07 12:04:45 +00:00
return FALSE ;
2015-12-07 11:27:53 +00:00
}
2015-12-07 12:04:45 +00:00
/* Sync with proxy, i.e. wait until its listening on the sockets */
2016-04-29 09:39:39 +00:00
if ( read ( sync_fds [ 0 ] , & x , 1 ) ! = 1 )
2015-12-07 11:27:53 +00:00
{
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( errno ) ,
_ ( " Failed to sync with dbus proxy " ) ) ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
close ( sync_fds [ 0 ] ) ;
close ( sync_fds [ 1 ] ) ;
2015-12-07 12:04:45 +00:00
return FALSE ;
}
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
return TRUE ;
}
# ifdef ENABLE_SECCOMP
2016-09-29 15:17:37 +00:00
static const uint32_t seccomp_x86_64_extra_arches [ ] = { SCMP_ARCH_X86 , 0 , } ;
# ifdef SCMP_ARCH_AARCH64
static const uint32_t seccomp_aarch64_extra_arches [ ] = { SCMP_ARCH_ARM , 0 } ;
# endif
2016-04-29 09:39:39 +00:00
static inline void
cleanup_seccomp ( void * p )
{
2016-05-06 14:03:27 +00:00
scmp_filter_ctx * pp = ( scmp_filter_ctx * ) p ;
2016-04-29 09:39:39 +00:00
if ( * pp )
seccomp_release ( * pp ) ;
}
static gboolean
2016-05-06 14:03:27 +00:00
setup_seccomp ( GPtrArray * argv_array ,
2016-05-11 13:41:49 +00:00
GArray * fd_array ,
2016-04-29 09:39:39 +00:00
const char * arch ,
2016-09-29 15:17:37 +00:00
gboolean multiarch ,
2016-05-06 14:03:27 +00:00
gboolean devel ,
GError * * error )
2016-04-29 09:39:39 +00:00
{
2016-05-06 14:03:27 +00:00
__attribute__ ( ( cleanup ( cleanup_seccomp ) ) ) scmp_filter_ctx seccomp = NULL ;
2016-04-29 09:39:39 +00:00
/**** BEGIN NOTE ON CODE SHARING
*
* There are today a number of different Linux container
* implementations . That will likely continue for long into the
* future . But we can still try to share code , and it ' s important
* to do so because it affects what library and application writers
* can do , and we should support code portability between different
* container tools .
*
2016-05-09 10:21:28 +00:00
* This syscall blacklist is copied from linux - user - chroot , which was in turn
2016-04-29 09:39:39 +00:00
* clearly influenced by the Sandstorm . io blacklist .
*
* If you make any changes here , I suggest sending the changes along
* to other sandbox maintainers . Using the libseccomp list is also
* an appropriate venue :
* https : //groups.google.com/forum/#!topic/libseccomp
*
* A non - exhaustive list of links to container tooling that might
* want to share this blacklist :
*
* https : //github.com/sandstorm-io/sandstorm
* in src / sandstorm / supervisor . c + +
* http : //cgit.freedesktop.org/xdg-app/xdg-app/
2016-05-09 10:21:28 +00:00
* in common / flatpak - run . c
2016-04-29 09:39:39 +00:00
* https : //git.gnome.org/browse/linux-user-chroot
* in src / setup - seccomp . c
*
* * * * END NOTE ON CODE SHARING
*/
2016-05-06 14:03:27 +00:00
struct
{
int scall ;
2016-04-29 09:39:39 +00:00
struct scmp_arg_cmp * arg ;
} syscall_blacklist [ ] = {
/* Block dmesg */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( syslog ) } ,
2016-04-29 09:39:39 +00:00
/* Useless old syscall */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( uselib ) } ,
2016-04-29 09:39:39 +00:00
/* Don't allow you to switch to bsd emulation or whatnot */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( personality ) } ,
2016-04-29 09:39:39 +00:00
/* Don't allow disabling accounting */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( acct ) } ,
2016-04-29 09:39:39 +00:00
/* 16-bit code is unnecessary in the sandbox, and modify_ldt is a
historic source of interesting information leaks . */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( modify_ldt ) } ,
2016-04-29 09:39:39 +00:00
/* Don't allow reading current quota use */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( quotactl ) } ,
2016-04-29 09:39:39 +00:00
2016-09-18 20:50:32 +00:00
/* Don't allow access to the kernel keyring */
{ SCMP_SYS ( add_key ) } ,
{ SCMP_SYS ( keyctl ) } ,
{ SCMP_SYS ( request_key ) } ,
2016-04-29 09:39:39 +00:00
/* Scary VM/NUMA ops */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( move_pages ) } ,
{ SCMP_SYS ( mbind ) } ,
{ SCMP_SYS ( get_mempolicy ) } ,
{ SCMP_SYS ( set_mempolicy ) } ,
{ SCMP_SYS ( migrate_pages ) } ,
2016-04-29 09:39:39 +00:00
/* Don't allow subnamespace setups: */
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( unshare ) } ,
{ SCMP_SYS ( mount ) } ,
{ SCMP_SYS ( pivot_root ) } ,
{ SCMP_SYS ( clone ) , & SCMP_A0 ( SCMP_CMP_MASKED_EQ , CLONE_NEWUSER , CLONE_NEWUSER ) } ,
2017-01-17 15:36:56 +00:00
/* Don't allow faking input to the controlling tty (CVE-2017-5226) */
{ SCMP_SYS ( ioctl ) , & SCMP_A1 ( SCMP_CMP_EQ , ( int ) TIOCSTI ) } ,
2016-04-29 09:39:39 +00:00
} ;
2016-05-06 14:03:27 +00:00
struct
{
int scall ;
2016-04-29 09:39:39 +00:00
struct scmp_arg_cmp * arg ;
} syscall_nondevel_blacklist [ ] = {
/* Profiling operations; we expect these to be done by tools from outside
* the sandbox . In particular perf has been the source of many CVEs .
*/
2016-05-06 14:03:27 +00:00
{ SCMP_SYS ( perf_event_open ) } ,
{ SCMP_SYS ( ptrace ) }
2016-04-29 09:39:39 +00:00
} ;
/* Blacklist all but unix, inet, inet6 and netlink */
int socket_family_blacklist [ ] = {
AF_AX25 ,
AF_IPX ,
AF_APPLETALK ,
AF_NETROM ,
AF_BRIDGE ,
AF_ATMPVC ,
AF_X25 ,
AF_ROSE ,
AF_DECnet ,
AF_NETBEUI ,
AF_SECURITY ,
AF_KEY ,
AF_NETLINK + 1 , /* Last gets CMP_GE, so order is important */
} ;
int i , r ;
glnx_fd_close int fd = - 1 ;
g_autofree char * fd_str = NULL ;
g_autofree char * path = NULL ;
seccomp = seccomp_init ( SCMP_ACT_ALLOW ) ;
if ( ! seccomp )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Initialize seccomp failed " ) ;
2016-04-29 09:39:39 +00:00
if ( arch ! = NULL )
{
uint32_t arch_id = 0 ;
2016-09-29 15:17:37 +00:00
const uint32_t * extra_arches = NULL ;
2016-04-29 09:39:39 +00:00
if ( strcmp ( arch , " i386 " ) = = 0 )
2016-09-29 15:17:37 +00:00
{
arch_id = SCMP_ARCH_X86 ;
}
2016-04-29 09:39:39 +00:00
else if ( strcmp ( arch , " x86_64 " ) = = 0 )
2016-09-29 15:17:37 +00:00
{
arch_id = SCMP_ARCH_X86_64 ;
extra_arches = seccomp_x86_64_extra_arches ;
}
2016-05-16 09:12:29 +00:00
else if ( strcmp ( arch , " arm " ) = = 0 )
2016-09-29 15:17:37 +00:00
{
arch_id = SCMP_ARCH_ARM ;
}
2016-05-20 09:07:34 +00:00
# ifdef SCMP_ARCH_AARCH64
2016-05-16 09:12:29 +00:00
else if ( strcmp ( arch , " aarch64 " ) = = 0 )
2016-09-29 15:17:37 +00:00
{
arch_id = SCMP_ARCH_AARCH64 ;
extra_arches = seccomp_aarch64_extra_arches ;
}
2016-05-20 09:07:34 +00:00
# endif
2016-04-29 09:39:39 +00:00
/* We only really need to handle arches on multiarch systems.
* If only one arch is supported the default is fine */
if ( arch_id ! = 0 )
{
/* This *adds* the target arch, instead of replacing the
native one . This is not ideal , because we ' d like to only
allow the target arch , but we can ' t really disallow the
2016-05-09 09:07:53 +00:00
native arch at this point , because then bubblewrap
2016-05-27 06:46:11 +00:00
couldn ' t continue running . */
2016-04-29 09:39:39 +00:00
r = seccomp_arch_add ( seccomp , arch_id ) ;
if ( r < 0 & & r ! = - EEXIST )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Failed to add architecture to seccomp filter " ) ;
2016-09-29 15:17:37 +00:00
if ( multiarch & & extra_arches ! = NULL )
{
unsigned i ;
for ( i = 0 ; extra_arches [ i ] ! = 0 ; i + + )
{
r = seccomp_arch_add ( seccomp , extra_arches [ i ] ) ;
if ( r < 0 & & r ! = - EEXIST )
return flatpak_fail ( error , " Failed to add multiarch architecture to seccomp filter " ) ;
}
}
2016-04-29 09:39:39 +00:00
}
}
/* TODO: Should we filter the kernel keyring syscalls in some way?
* We do want them to be used by desktop apps , but they could also perhaps
* leak system stuff or secrets from other apps .
*/
for ( i = 0 ; i < G_N_ELEMENTS ( syscall_blacklist ) ; i + + )
{
int scall = syscall_blacklist [ i ] . scall ;
if ( syscall_blacklist [ i ] . arg )
2016-05-06 14:03:27 +00:00
r = seccomp_rule_add ( seccomp , SCMP_ACT_ERRNO ( EPERM ) , scall , 1 , * syscall_blacklist [ i ] . arg ) ;
2016-04-29 09:39:39 +00:00
else
2016-05-06 14:03:27 +00:00
r = seccomp_rule_add ( seccomp , SCMP_ACT_ERRNO ( EPERM ) , scall , 0 ) ;
2016-04-29 09:39:39 +00:00
if ( r < 0 & & r = = - EFAULT /* unknown syscall */ )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Failed to block syscall %d " , scall ) ;
2016-04-29 09:39:39 +00:00
}
if ( ! devel )
{
for ( i = 0 ; i < G_N_ELEMENTS ( syscall_nondevel_blacklist ) ; i + + )
{
int scall = syscall_nondevel_blacklist [ i ] . scall ;
if ( syscall_nondevel_blacklist [ i ] . arg )
2016-05-06 14:03:27 +00:00
r = seccomp_rule_add ( seccomp , SCMP_ACT_ERRNO ( EPERM ) , scall , 1 , * syscall_nondevel_blacklist [ i ] . arg ) ;
2016-04-29 09:39:39 +00:00
else
2016-05-06 14:03:27 +00:00
r = seccomp_rule_add ( seccomp , SCMP_ACT_ERRNO ( EPERM ) , scall , 0 ) ;
2016-04-29 09:39:39 +00:00
if ( r < 0 & & r = = - EFAULT /* unknown syscall */ )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Failed to block syscall %d " , scall ) ;
2016-04-29 09:39:39 +00:00
}
}
/* Socket filtering doesn't work on e.g. i386, so ignore failures here
* However , we need to user seccomp_rule_add_exact to avoid libseccomp doing
* something else : https : //github.com/seccomp/libseccomp/issues/8 */
for ( i = 0 ; i < G_N_ELEMENTS ( socket_family_blacklist ) ; i + + )
{
int family = socket_family_blacklist [ i ] ;
if ( i = = G_N_ELEMENTS ( socket_family_blacklist ) - 1 )
2016-10-06 10:22:06 +00:00
seccomp_rule_add_exact ( seccomp , SCMP_ACT_ERRNO ( EAFNOSUPPORT ) , SCMP_SYS ( socket ) , 1 , SCMP_A0 ( SCMP_CMP_GE , family ) ) ;
2016-04-29 09:39:39 +00:00
else
2016-10-06 10:22:06 +00:00
seccomp_rule_add_exact ( seccomp , SCMP_ACT_ERRNO ( EAFNOSUPPORT ) , SCMP_SYS ( socket ) , 1 , SCMP_A0 ( SCMP_CMP_EQ , family ) ) ;
2016-04-29 09:39:39 +00:00
}
2016-05-09 09:07:53 +00:00
fd = g_file_open_tmp ( " flatpak-seccomp-XXXXXX " , & path , error ) ;
2016-04-29 09:39:39 +00:00
if ( fd = = - 1 )
return FALSE ;
unlink ( path ) ;
if ( seccomp_export_bpf ( seccomp , fd ) ! = 0 )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Failed to export bpf " ) ;
2016-04-29 09:39:39 +00:00
lseek ( fd , 0 , SEEK_SET ) ;
fd_str = g_strdup_printf ( " %d " , fd ) ;
2016-05-11 13:41:49 +00:00
if ( fd_array )
g_array_append_val ( fd_array , fd ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --seccomp " , fd_str ,
NULL ) ;
fd = - 1 ; /* Don't close on success */
return TRUE ;
}
# endif
gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_setup_base_argv ( GPtrArray * argv_array ,
2016-05-11 13:33:49 +00:00
GArray * fd_array ,
2016-05-06 14:37:47 +00:00
GFile * runtime_files ,
GFile * app_id_dir ,
const char * arch ,
FlatpakRunFlags flags ,
GError * * error )
2016-04-29 09:39:39 +00:00
{
const char * usr_links [ ] = { " lib " , " lib32 " , " lib64 " , " bin " , " sbin " } ;
g_autofree char * run_dir = g_strdup_printf ( " /run/user/%d " , getuid ( ) ) ;
int i ;
int passwd_fd = - 1 ;
g_autofree char * passwd_fd_str = NULL ;
g_autofree char * passwd_contents = NULL ;
int group_fd = - 1 ;
g_autofree char * group_fd_str = NULL ;
g_autofree char * group_contents = NULL ;
struct group * g = getgrgid ( getgid ( ) ) ;
2016-05-06 14:03:27 +00:00
2016-04-29 09:39:39 +00:00
g_autoptr ( GFile ) etc = NULL ;
passwd_contents = g_strdup_printf ( " %s:x:%d:%d:%s:%s:%s \n "
" nfsnobody:x:65534:65534:Unmapped user:/:/sbin/nologin \n " ,
g_get_user_name ( ) ,
getuid ( ) , getgid ( ) ,
g_get_real_name ( ) ,
g_get_home_dir ( ) ,
DEFAULT_SHELL ) ;
if ( ( passwd_fd = create_tmp_fd ( passwd_contents , - 1 , error ) ) < 0 )
return FALSE ;
passwd_fd_str = g_strdup_printf ( " %d " , passwd_fd ) ;
2016-05-11 13:33:49 +00:00
if ( fd_array )
g_array_append_val ( fd_array , passwd_fd ) ;
2016-04-29 09:39:39 +00:00
group_contents = g_strdup_printf ( " %s:x:%d:%s \n "
2016-05-06 14:03:27 +00:00
" nfsnobody:x:65534: \n " ,
g - > gr_name ,
getgid ( ) , g_get_user_name ( ) ) ;
2016-04-29 09:39:39 +00:00
if ( ( group_fd = create_tmp_fd ( group_contents , - 1 , error ) ) < 0 )
return FALSE ;
group_fd_str = g_strdup_printf ( " %d " , group_fd ) ;
2016-05-11 13:33:49 +00:00
if ( fd_array )
g_array_append_val ( fd_array , group_fd ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
" --unshare-pid " ,
" --proc " , " /proc " ,
" --dir " , " /tmp " ,
2016-06-15 23:31:17 +00:00
" --dir " , " /var/tmp " ,
2016-04-29 09:39:39 +00:00
" --dir " , " /run/host " ,
" --dir " , run_dir ,
" --setenv " , " XDG_RUNTIME_DIR " , run_dir ,
2016-11-22 10:37:45 +00:00
" --symlink " , " ../run " , " /var/run " ,
2016-04-29 09:39:39 +00:00
" --ro-bind " , " /sys/block " , " /sys/block " ,
" --ro-bind " , " /sys/bus " , " /sys/bus " ,
" --ro-bind " , " /sys/class " , " /sys/class " ,
" --ro-bind " , " /sys/dev " , " /sys/dev " ,
" --ro-bind " , " /sys/devices " , " /sys/devices " ,
2017-01-25 14:26:39 +00:00
NULL ) ;
if ( flags & FLATPAK_RUN_FLAG_WRITABLE_ETC )
add_args ( argv_array ,
" --dir " , " /usr/etc " ,
" --symlink " , " usr/etc " , " /etc " ,
NULL ) ;
add_args ( argv_array ,
2016-04-29 09:39:39 +00:00
" --bind-data " , passwd_fd_str , " /etc/passwd " ,
" --bind-data " , group_fd_str , " /etc/group " ,
NULL ) ;
if ( g_file_test ( " /etc/machine-id " , G_FILE_TEST_EXISTS ) )
2017-01-26 16:05:23 +00:00
add_args ( argv_array , " --ro-bind " , " /etc/machine-id " , " /etc/machine-id " , NULL ) ;
2016-04-29 09:39:39 +00:00
else if ( g_file_test ( " /var/lib/dbus/machine-id " , G_FILE_TEST_EXISTS ) )
2017-01-26 16:05:23 +00:00
add_args ( argv_array , " --ro-bind " , " /var/lib/dbus/machine-id " , " /etc/machine-id " , NULL ) ;
2016-04-29 09:39:39 +00:00
2017-02-28 17:10:06 +00:00
if ( runtime_files )
etc = g_file_get_child ( runtime_files , " etc " ) ;
if ( etc ! = NULL & &
( flags & FLATPAK_RUN_FLAG_WRITABLE_ETC ) = = 0 & &
2017-01-25 14:26:39 +00:00
g_file_query_exists ( etc , NULL ) )
2016-04-29 09:39:39 +00:00
{
g_auto ( GLnxDirFdIterator ) dfd_iter = { 0 , } ;
struct dirent * dent ;
2016-05-06 14:03:27 +00:00
char path_buffer [ PATH_MAX + 1 ] ;
2016-04-29 09:39:39 +00:00
ssize_t symlink_size ;
2017-02-28 10:00:01 +00:00
gboolean inited ;
2016-04-29 09:39:39 +00:00
2017-02-28 10:00:01 +00:00
inited = glnx_dirfd_iterator_init_at ( AT_FDCWD , flatpak_file_get_path_cached ( etc ) , FALSE , & dfd_iter , NULL ) ;
2016-04-29 09:39:39 +00:00
2017-02-28 10:00:01 +00:00
while ( inited )
2016-04-29 09:39:39 +00:00
{
g_autofree char * src = NULL ;
g_autofree char * dest = NULL ;
if ( ! glnx_dirfd_iterator_next_dent_ensure_dtype ( & dfd_iter , & dent , NULL , NULL ) | | dent = = NULL )
break ;
if ( strcmp ( dent - > d_name , " passwd " ) = = 0 | |
strcmp ( dent - > d_name , " group " ) = = 0 | |
strcmp ( dent - > d_name , " machine-id " ) = = 0 | |
strcmp ( dent - > d_name , " resolv.conf " ) = = 0 | |
strcmp ( dent - > d_name , " localtime " ) = = 0 )
continue ;
2016-08-22 08:20:19 +00:00
src = g_build_filename ( flatpak_file_get_path_cached ( etc ) , dent - > d_name , NULL ) ;
2016-04-29 09:39:39 +00:00
dest = g_build_filename ( " /etc " , dent - > d_name , NULL ) ;
if ( dent - > d_type = = DT_LNK )
{
symlink_size = readlinkat ( dfd_iter . fd , dent - > d_name , path_buffer , sizeof ( path_buffer ) - 1 ) ;
if ( symlink_size < 0 )
{
glnx_set_error_from_errno ( error ) ;
return FALSE ;
}
path_buffer [ symlink_size ] = 0 ;
add_args ( argv_array , " --symlink " , path_buffer , dest , NULL ) ;
}
else
2016-05-06 14:03:27 +00:00
{
add_args ( argv_array , " --bind " , src , dest , NULL ) ;
}
2016-04-29 09:39:39 +00:00
}
}
if ( app_id_dir ! = NULL )
{
g_autoptr ( GFile ) app_cache_dir = g_file_get_child ( app_id_dir , " cache " ) ;
2017-01-16 12:01:57 +00:00
g_autoptr ( GFile ) app_tmp_dir = g_file_get_child ( app_cache_dir , " tmp " ) ;
2016-04-29 09:39:39 +00:00
g_autoptr ( GFile ) app_data_dir = g_file_get_child ( app_id_dir , " data " ) ;
g_autoptr ( GFile ) app_config_dir = g_file_get_child ( app_id_dir , " config " ) ;
add_args ( argv_array ,
/* These are nice to have as a fixed path */
2016-08-22 08:20:19 +00:00
" --bind " , flatpak_file_get_path_cached ( app_cache_dir ) , " /var/cache " ,
" --bind " , flatpak_file_get_path_cached ( app_data_dir ) , " /var/data " ,
" --bind " , flatpak_file_get_path_cached ( app_config_dir ) , " /var/config " ,
2017-01-16 12:01:57 +00:00
" --bind " , flatpak_file_get_path_cached ( app_tmp_dir ) , " /var/tmp " ,
2016-04-29 09:39:39 +00:00
NULL ) ;
}
2017-02-28 17:10:06 +00:00
for ( i = 0 ; runtime_files ! = NULL & & i < G_N_ELEMENTS ( usr_links ) ; i + + )
2016-04-29 09:39:39 +00:00
{
const char * subdir = usr_links [ i ] ;
g_autoptr ( GFile ) runtime_subdir = g_file_get_child ( runtime_files , subdir ) ;
if ( g_file_query_exists ( runtime_subdir , NULL ) )
{
g_autofree char * link = g_strconcat ( " usr/ " , subdir , NULL ) ;
g_autofree char * dest = g_strconcat ( " / " , subdir , NULL ) ;
add_args ( argv_array ,
" --symlink " , link , dest ,
NULL ) ;
}
}
# ifdef ENABLE_SECCOMP
if ( ! setup_seccomp ( argv_array ,
2016-05-11 13:41:49 +00:00
fd_array ,
2016-04-29 09:39:39 +00:00
arch ,
2016-09-29 15:17:37 +00:00
( flags & FLATPAK_RUN_FLAG_MULTIARCH ) ! = 0 ,
2016-05-06 14:37:47 +00:00
( flags & FLATPAK_RUN_FLAG_DEVEL ) ! = 0 ,
2016-04-29 09:39:39 +00:00
error ) )
return FALSE ;
# endif
2015-12-07 11:27:53 +00:00
2017-01-25 14:26:39 +00:00
if ( ( flags & FLATPAK_RUN_FLAG_WRITABLE_ETC ) = = 0 )
add_monitor_path_args ( ( flags & FLATPAK_RUN_FLAG_NO_SESSION_HELPER ) = = 0 , argv_array ) ;
2016-05-25 14:38:50 +00:00
2015-12-07 12:04:45 +00:00
return TRUE ;
}
2015-12-07 11:27:53 +00:00
2016-05-11 13:14:11 +00:00
static void
clear_fd ( gpointer data )
{
int * fd_p = data ;
if ( fd_p ! = NULL & & * fd_p ! = - 1 )
close ( * fd_p ) ;
}
static void
child_setup ( gpointer user_data )
{
GArray * fd_array = user_data ;
2016-05-11 13:33:49 +00:00
int i ;
2016-05-11 13:14:11 +00:00
/* If no fd_array was specified, don't care. */
if ( fd_array = = NULL )
return ;
2016-05-11 13:33:49 +00:00
/* Otherwise, mark not - close-on-exec all the fds in the array */
for ( i = 0 ; i < fd_array - > len ; i + + )
fcntl ( g_array_index ( fd_array , int , i ) , F_SETFD , 0 ) ;
2016-05-11 13:14:11 +00:00
}
2015-12-07 12:04:45 +00:00
gboolean
2016-05-06 14:37:47 +00:00
flatpak_run_app ( const char * app_ref ,
FlatpakDeploy * app_deploy ,
FlatpakContext * extra_context ,
const char * custom_runtime ,
const char * custom_runtime_version ,
FlatpakRunFlags flags ,
const char * custom_command ,
char * args [ ] ,
int n_args ,
GCancellable * cancellable ,
GError * * error )
{
g_autoptr ( FlatpakDeploy ) runtime_deploy = NULL ;
2015-12-07 12:04:45 +00:00
g_autoptr ( GFile ) app_files = NULL ;
g_autoptr ( GFile ) runtime_files = NULL ;
g_autoptr ( GFile ) app_id_dir = NULL ;
2016-01-12 08:57:20 +00:00
g_autofree char * default_runtime = NULL ;
2015-12-07 12:04:45 +00:00
g_autofree char * default_command = NULL ;
g_autofree char * runtime_ref = NULL ;
g_autoptr ( GKeyFile ) metakey = NULL ;
g_autoptr ( GKeyFile ) runtime_metakey = NULL ;
g_autoptr ( GPtrArray ) argv_array = NULL ;
2016-05-11 13:14:11 +00:00
g_autoptr ( GArray ) fd_array = NULL ;
2016-04-29 09:39:39 +00:00
g_autoptr ( GPtrArray ) real_argv_array = NULL ;
2015-12-07 12:04:45 +00:00
g_auto ( GStrv ) envp = NULL ;
const char * command = " /bin/sh " ;
2016-01-12 08:57:20 +00:00
g_autoptr ( GError ) my_error = NULL ;
g_auto ( GStrv ) runtime_parts = NULL ;
2015-12-07 12:04:45 +00:00
int i ;
2016-09-08 09:21:00 +00:00
g_autofree char * app_info_path = NULL ;
2016-05-06 14:37:47 +00:00
g_autoptr ( FlatpakContext ) app_context = NULL ;
g_autoptr ( FlatpakContext ) overrides = NULL ;
2015-12-07 12:04:45 +00:00
g_auto ( GStrv ) app_ref_parts = NULL ;
2015-12-07 11:27:53 +00:00
2016-05-06 14:37:47 +00:00
app_ref_parts = flatpak_decompose_ref ( app_ref , error ) ;
2015-12-07 12:04:45 +00:00
if ( app_ref_parts = = NULL )
return FALSE ;
2015-12-07 11:27:53 +00:00
2015-12-07 12:04:45 +00:00
argv_array = g_ptr_array_new_with_free_func ( g_free ) ;
2016-05-11 13:14:11 +00:00
fd_array = g_array_new ( FALSE , TRUE , sizeof ( int ) ) ;
g_array_set_clear_func ( fd_array , clear_fd ) ;
2016-10-19 15:30:58 +00:00
if ( app_deploy = = NULL )
2016-01-12 08:57:20 +00:00
{
2016-10-19 15:30:58 +00:00
g_assert ( g_str_has_prefix ( app_ref , " runtime/ " ) ) ;
default_runtime = g_strdup ( app_ref + strlen ( " runtime/ " ) ) ;
}
else
{
metakey = flatpak_deploy_get_metadata ( app_deploy ) ;
default_runtime = g_key_file_get_string ( metakey , " Application " ,
( flags & FLATPAK_RUN_FLAG_DEVEL ) ! = 0 ? " sdk " : " runtime " ,
& my_error ) ;
if ( my_error )
{
g_propagate_error ( error , g_steal_pointer ( & my_error ) ) ;
return FALSE ;
}
2016-01-12 08:57:20 +00:00
}
runtime_parts = g_strsplit ( default_runtime , " / " , 0 ) ;
if ( g_strv_length ( runtime_parts ) ! = 3 )
2016-05-06 14:37:47 +00:00
return flatpak_fail ( error , " Wrong number of components in runtime %s " , default_runtime ) ;
2016-01-12 08:57:20 +00:00
2015-12-07 12:04:45 +00:00
if ( custom_runtime )
{
2016-01-12 08:57:20 +00:00
g_auto ( GStrv ) custom_runtime_parts = g_strsplit ( custom_runtime , " / " , 0 ) ;
for ( i = 0 ; i < 3 & & custom_runtime_parts [ i ] ! = NULL ; i + + )
2015-12-07 12:34:50 +00:00
{
2016-01-12 08:57:20 +00:00
if ( strlen ( custom_runtime_parts [ i ] ) > 0 )
{
g_free ( runtime_parts [ i ] ) ;
runtime_parts [ i ] = g_steal_pointer ( & custom_runtime_parts [ i ] ) ;
}
2015-12-07 12:34:50 +00:00
}
2015-12-07 11:27:53 +00:00
}
2016-01-12 08:57:20 +00:00
if ( custom_runtime_version )
{
g_free ( runtime_parts [ 2 ] ) ;
runtime_parts [ 2 ] = g_strdup ( custom_runtime_version ) ;
}
2016-05-06 14:37:47 +00:00
runtime_ref = flatpak_compose_ref ( FALSE ,
2016-01-12 08:57:20 +00:00
runtime_parts [ 0 ] ,
runtime_parts [ 2 ] ,
runtime_parts [ 1 ] ,
error ) ;
if ( runtime_ref = = NULL )
return FALSE ;
2015-12-07 12:04:45 +00:00
2016-05-06 14:37:47 +00:00
runtime_deploy = flatpak_find_deploy_for_ref ( runtime_ref , cancellable , error ) ;
2015-12-07 12:04:45 +00:00
if ( runtime_deploy = = NULL )
return FALSE ;
2016-05-06 14:37:47 +00:00
runtime_metakey = flatpak_deploy_get_metadata ( runtime_deploy ) ;
2015-12-07 12:04:45 +00:00
app_context = compute_permissions ( metakey , runtime_metakey , error ) ;
if ( app_context = = NULL )
return FALSE ;
2016-10-19 15:30:58 +00:00
if ( app_deploy ! = NULL )
{
overrides = flatpak_deploy_get_overrides ( app_deploy ) ;
flatpak_context_merge ( app_context , overrides ) ;
}
2015-12-07 12:04:45 +00:00
2015-12-07 12:34:50 +00:00
if ( extra_context )
2016-05-06 14:37:47 +00:00
flatpak_context_merge ( app_context , extra_context ) ;
2015-12-07 12:04:45 +00:00
2016-05-06 14:37:47 +00:00
runtime_files = flatpak_deploy_get_files ( runtime_deploy ) ;
2016-10-19 15:30:58 +00:00
if ( app_deploy ! = NULL )
{
app_files = flatpak_deploy_get_files ( app_deploy ) ;
if ( ( app_id_dir = flatpak_ensure_data_dir ( app_ref_parts [ 1 ] , cancellable , error ) ) = = NULL )
return FALSE ;
}
2016-04-29 09:39:39 +00:00
envp = g_get_environ ( ) ;
2016-05-06 14:37:47 +00:00
envp = flatpak_run_apply_env_default ( envp ) ;
envp = flatpak_run_apply_env_vars ( envp , app_context ) ;
2016-10-19 15:30:58 +00:00
if ( app_id_dir ! = NULL )
envp = flatpak_run_apply_env_appid ( envp , app_id_dir ) ;
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
2016-08-22 08:20:19 +00:00
" --ro-bind " , flatpak_file_get_path_cached ( runtime_files ) , " /usr " ,
2016-04-29 09:39:39 +00:00
" --lock-file " , " /usr/.ref " ,
NULL ) ;
2016-10-19 15:30:58 +00:00
if ( app_files ! = NULL )
add_args ( argv_array ,
" --ro-bind " , flatpak_file_get_path_cached ( app_files ) , " /app " ,
" --lock-file " , " /app/.ref " ,
NULL ) ;
else
add_args ( argv_array ,
" --dir " , " /app " ,
NULL ) ;
2016-09-05 19:22:20 +00:00
if ( app_context - > features & FLATPAK_CONTEXT_FEATURE_DEVEL )
flags | = FLATPAK_RUN_FLAG_DEVEL ;
2016-09-29 15:17:37 +00:00
if ( app_context - > features & FLATPAK_CONTEXT_FEATURE_MULTIARCH )
flags | = FLATPAK_RUN_FLAG_MULTIARCH ;
2016-05-11 13:33:49 +00:00
if ( ! flatpak_run_setup_base_argv ( argv_array , fd_array , runtime_files , app_id_dir , app_ref_parts [ 2 ] , flags , error ) )
2015-12-07 12:04:45 +00:00
return FALSE ;
2016-09-08 09:21:00 +00:00
if ( ! flatpak_run_add_app_info_args ( argv_array , fd_array , app_files , runtime_files , app_ref_parts [ 1 ] , app_ref_parts [ 3 ] ,
runtime_ref , app_context , & app_info_path , error ) )
2015-12-07 12:04:45 +00:00
return FALSE ;
2016-10-19 15:30:58 +00:00
if ( metakey ! = NULL & &
2017-02-01 15:23:41 +00:00
! flatpak_run_add_extension_args ( argv_array , & envp , metakey , app_ref , cancellable , error ) )
2016-04-29 09:39:39 +00:00
return FALSE ;
2015-12-07 12:04:45 +00:00
2017-02-01 15:23:41 +00:00
if ( ! flatpak_run_add_extension_args ( argv_array , & envp , runtime_metakey , runtime_ref , cancellable , error ) )
2016-04-29 09:39:39 +00:00
return FALSE ;
2015-12-07 12:04:45 +00:00
add_document_portal_args ( argv_array , app_ref_parts [ 1 ] ) ;
2017-03-14 15:20:33 +00:00
if ( ! flatpak_run_add_environment_args ( argv_array , fd_array , & envp ,
app_info_path , flags ,
app_ref_parts [ 1 ] , app_context , app_id_dir , cancellable , error ) )
2016-01-29 07:50:11 +00:00
return FALSE ;
2017-03-14 15:20:33 +00:00
flatpak_run_add_journal_args ( argv_array ) ;
add_font_path_args ( argv_array ) ;
2015-12-07 12:04:45 +00:00
2016-04-29 09:39:39 +00:00
add_args ( argv_array ,
2016-05-09 09:07:53 +00:00
/* Not in base, because we don't want this for flatpak build */
2016-04-29 09:39:39 +00:00
" --symlink " , " /app/lib/debug/source " , " /run/build " ,
" --symlink " , " /usr/lib/debug/source " , " /run/build-runtime " ,
NULL ) ;
2015-12-07 12:04:45 +00:00
if ( custom_command )
2016-05-06 14:03:27 +00:00
{
command = custom_command ;
}
2016-10-19 15:30:58 +00:00
else if ( metakey )
2015-12-07 12:34:50 +00:00
{
default_command = g_key_file_get_string ( metakey , " Application " , " command " , & my_error ) ;
if ( my_error )
{
g_propagate_error ( error , g_steal_pointer ( & my_error ) ) ;
return FALSE ;
}
command = default_command ;
}
2015-12-07 12:04:45 +00:00
2016-04-29 09:39:39 +00:00
real_argv_array = g_ptr_array_new_with_free_func ( g_free ) ;
2016-05-06 14:37:47 +00:00
g_ptr_array_add ( real_argv_array , g_strdup ( flatpak_get_bwrap ( ) ) ) ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
{
gsize len ;
int arg_fd ;
g_autofree char * arg_fd_str = NULL ;
g_autofree char * args = join_args ( argv_array , & len ) ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
arg_fd = create_tmp_fd ( args , len , error ) ;
if ( arg_fd < 0 )
return FALSE ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
arg_fd_str = g_strdup_printf ( " %d " , arg_fd ) ;
2016-05-11 13:23:29 +00:00
g_array_append_val ( fd_array , arg_fd ) ;
2015-12-07 11:27:53 +00:00
2016-04-29 09:39:39 +00:00
add_args ( real_argv_array ,
" --args " , arg_fd_str ,
NULL ) ;
}
g_ptr_array_add ( real_argv_array , g_strdup ( command ) ) ;
for ( i = 0 ; i < n_args ; i + + )
g_ptr_array_add ( real_argv_array , g_strdup ( args [ i ] ) ) ;
g_ptr_array_add ( real_argv_array , NULL ) ;
2015-12-07 11:27:53 +00:00
2016-05-06 14:37:47 +00:00
if ( ( flags & FLATPAK_RUN_FLAG_BACKGROUND ) ! = 0 )
2015-12-07 11:27:53 +00:00
{
if ( ! g_spawn_async ( NULL ,
2016-05-06 14:03:27 +00:00
( char * * ) real_argv_array - > pdata ,
2015-12-07 11:27:53 +00:00
envp ,
2016-09-06 13:28:26 +00:00
G_SPAWN_SEARCH_PATH ,
2016-07-28 22:24:43 +00:00
child_setup , fd_array ,
2015-12-07 11:27:53 +00:00
NULL ,
error ) )
return FALSE ;
}
else
{
2016-05-06 14:37:47 +00:00
if ( execvpe ( flatpak_get_bwrap ( ) , ( char * * ) real_argv_array - > pdata , envp ) = = - 1 )
2015-12-07 11:27:53 +00:00
{
2016-07-23 17:59:45 +00:00
g_set_error_literal ( error , G_IO_ERROR , g_io_error_from_errno ( errno ) ,
_ ( " Unable to start app " ) ) ;
2015-12-07 11:27:53 +00:00
return FALSE ;
}
/* Not actually reached... */
}
return TRUE ;
}