Commit e692ad5a authored by Tomi Leppänen's avatar Tomi Leppänen

Merge branch 'jb48441' into 'master'

Limit dynamic modes to device owner

See merge request !55
parents 3142bf0d 6e98e56b
......@@ -49,6 +49,14 @@ AC_ARG_ENABLE([mer_ssu], AS_HELP_STRING([--enable-mer-ssu], [Enable MER SSU @<:@
esac],[mer_ssu=false])
AM_CONDITIONAL([USE_MER_SSU], [test x$mer_ssu = xtrue])
AC_ARG_ENABLE([sailfish_access_control], AS_HELP_STRING([--enable-sailfish-access-control], [Enable Sailfish Access Control @<:@default=false@:>@]),
[case "${enableval}" in
yes) sailfish_access_control=true ; CFLAGS="-DSAILFISH_ACCESS_CONTROL $CFLAGS" ;;
no) sailfish_access_control=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-sailfish-access-control]) ;;
esac],[sailfish_access_control=false])
AM_CONDITIONAL([SAILFISH_ACCESS_CONTROL], [test x$sailfish_access_control = xtrue])
AC_ARG_ENABLE([app_sync], AS_HELP_STRING([--enable-app-sync], [Enable application syncing @<:@default=true@:>@]),
[case "${enableval}" in
yes) app_sync=true ; CFLAGS="-DAPP_SYNC $CFLAGS" ;;
......@@ -100,6 +108,7 @@ PKG_CHECK_MODULES([USB_MODED], [
ssu-sysinfo
libsystemd
dsme
sailfishaccesscontrol
])
AC_SUBST(USB_MODED_LIBS)
......
......@@ -17,6 +17,7 @@ BuildRequires: doxygen
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(ssu-sysinfo)
BuildRequires: pkgconfig(dsme) >= 0.65.0
BuildRequires: pkgconfig(sailfishaccesscontrol)
Requires: lsof
Requires: usb-moded-configs
......@@ -327,7 +328,7 @@ when the UI fails.
%build
test -e Makefile || (%autogen)
test -e Makefile || (%configure --enable-app-sync --enable-meegodevlock --enable-debug --enable-connman --enable-systemd --enable-mer-ssu)
test -e Makefile || (%configure --enable-app-sync --enable-meegodevlock --enable-debug --enable-connman --enable-systemd --enable-mer-ssu --enable-sailfish-access-control)
make all doc %{?_smp_mflags}
%install
......
......@@ -80,6 +80,11 @@ usb_moded_SOURCES += \
usb_moded-appsync-dbus-private.h
endif
if SAILFISH_ACCESS_CONTROL
usb_moded_CPPFLAGS += `pkg-config --cflags sailfishaccesscontrol`
usb_moded_LDFLAGS += `pkg-config --libs sailfishaccesscontrol`
endif
usb_moded_util_CPPFLAGS = \
$(USB_MODED_CFLAGS)
......
......@@ -36,6 +36,9 @@
<method name="get_available_modes">
<arg name="modes" type="s" direction="out"/>
</method>
<method name="get_available_modes_for_user">
<arg name="modes" type="s" direction="out"/>
</method>
<method name="hide_mode">
<arg name="mode" type="s" direction="in"/>
<arg name="mode" type="s" direction="out"/>
......
......@@ -61,7 +61,7 @@ bool common_msleep_ (const char *file, int line, co
static bool common_mode_in_list (const char *mode, char *const *modes);
bool common_modename_is_internal (const char *modename);
int common_valid_mode (const char *mode);
gchar *common_get_mode_list (mode_list_type_t type);
gchar *common_get_mode_list (mode_list_type_t type, uid_t uid);
/* ========================================================================= *
* Functions
......@@ -205,7 +205,7 @@ void common_send_supported_modes_signal(void)
{
LOG_REGISTER_CONTEXT;
gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST);
gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST, 0);
umdbus_send_supported_modes_signal(mode_list);
g_free(mode_list);
}
......@@ -216,7 +216,7 @@ void common_send_available_modes_signal(void)
{
LOG_REGISTER_CONTEXT;
gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST);
gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, 0);
umdbus_send_available_modes_signal(mode_list);
g_free(mode_list);
}
......@@ -503,10 +503,12 @@ int common_valid_mode(const char *mode)
/** make a list of all available usb modes
*
* @param type The type of list to return. Supported or available.
* @param uid Uid of the process requesting the information;
* this is used to limit allowed modes, 0 returns all
*
* @return a comma-separated list of modes (MODE_ASK not included as it is not a real mode)
*/
gchar *common_get_mode_list(mode_list_type_t type)
gchar *common_get_mode_list(mode_list_type_t type, uid_t uid)
{
LOG_REGISTER_CONTEXT;
......@@ -544,6 +546,10 @@ gchar *common_get_mode_list(mode_list_type_t type)
{
modedata_t *data = iter->data;
/* skip dynamic modes that are not allowed */
if (!usbmoded_is_mode_permitted(data->mode_name, uid))
continue;
/* skip items in the hidden list */
if (common_mode_in_list(data->mode_name, hidden_modes_array))
continue;
......
......@@ -61,7 +61,7 @@ waitres_t common_wait (unsigned tot_ms, bool (*ready_c
bool common_msleep_ (const char *file, int line, const char *func, unsigned msec);
bool common_modename_is_internal (const char *modename);
int common_valid_mode (const char *mode);
gchar *common_get_mode_list (mode_list_type_t type);
gchar *common_get_mode_list (mode_list_type_t type, uid_t uid);
/* ========================================================================= *
* Macros
......
......@@ -58,6 +58,7 @@ void control_set_cable_state (cable_state_t cable_state);
cable_state_t control_get_cable_state (void);
void control_clear_cable_state (void);
bool control_get_connection_state (void);
void control_set_last_seen_user (uid_t uid);
/* ========================================================================= *
* Data
......@@ -89,6 +90,12 @@ static char *control_internal_mode = NULL;
*/
static cable_state_t control_cable_state = CABLE_STATE_UNKNOWN;
/** Last user seen
*
* Defaults to invalid user which has no rights.
*/
static uid_t control_last_seen_user = (uid_t)-1;
/* ========================================================================= *
* Functions
* ========================================================================= */
......@@ -337,12 +344,17 @@ void control_select_usb_mode(void)
/* If there is only one allowed mode, use it without
* going through ask-mode */
if( !strcmp(MODE_ASK, mode_to_set) ) {
// FIXME free() vs g_free() conflict
gchar *available = common_get_mode_list(AVAILABLE_MODES_LIST);
if( *available && !strchr(available, ',') ) {
free(mode_to_set), mode_to_set = available, available = 0;
if( control_last_seen_user == (uid_t)-1 ) {
/* Use charging only if no user has been seen */
free(mode_to_set), mode_to_set = 0;
} else {
// FIXME free() vs g_free() conflict
gchar *available = common_get_mode_list(AVAILABLE_MODES_LIST, control_last_seen_user);
if( *available && !strchr(available, ',') ) {
free(mode_to_set), mode_to_set = available, available = 0;
}
g_free(available);
}
g_free(available);
}
if( mode_to_set && usbmoded_can_export() ) {
......@@ -431,3 +443,12 @@ bool control_get_connection_state(void)
}
return connected;
}
/** Set the last seen user
*
* @param uid of last seen user, controls implicitly set modes
*/
void control_set_last_seen_user(uid_t uid)
{
control_last_seen_user = uid;
}
......@@ -49,5 +49,6 @@ void control_set_cable_state (cable_state_t cable_state);
cable_state_t control_get_cable_state (void);
void control_clear_cable_state (void);
bool control_get_connection_state (void);
void control_set_last_seen_user (uid_t uid);
#endif /* USB_MODED_CONTROL_H_ */
......@@ -42,6 +42,9 @@
/** Logical name for org.freedesktop.DBus.NameOwnerChanged signal */
# define DBUS_NAME_OWNER_CHANGED_SIG "NameOwnerChanged"
/** Logical name for org.freedesktop.DBus.GetNameOwner method */
# define DBUS_GET_CONNECTION_PID_REQ "GetConnectionUnixProcessID"
/* ========================================================================= *
* Types
* ========================================================================= */
......
......@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dbus/dbus-glib-lowlevel.h>
......@@ -84,6 +85,7 @@ int umdbus_send_hidden_modes_signal (const char *hidde
int umdbus_send_whitelisted_modes_signal(const char *whitelist);
static void umdbus_get_name_owner_cb (DBusPendingCall *pc, void *aptr);
gboolean umdbus_get_name_owner_async (const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc);
uid_t umdbus_get_sender_uid (const char *sender);
/* ========================================================================= *
* Data
......@@ -161,6 +163,9 @@ static const char umdbus_introspect_usbmoded[] =
" <method name=\"" USB_MODE_AVAILABLE_MODES_GET "\">\n"
" <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_AVAILABLE_MODES_FOR_USER "\">\n"
" <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_HIDE "\">\n"
" <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"
......@@ -284,6 +289,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
const char *member = dbus_message_get_member(msg);
const char *object = dbus_message_get_path(msg);
int type = dbus_message_get_type(msg);
const char *sender = dbus_message_get_sender(msg);
(void)user_data;
......@@ -340,11 +346,17 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
const char *mode = control_get_external_mode();
char *use = 0;
DBusError err = DBUS_ERROR_INIT;
uid_t uid = umdbus_get_sender_uid(sender);
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID)) {
log_err("parse error: %s: %s", err.name, err.message);
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
}
else if( !usbmoded_is_mode_permitted(use, uid) ) {
/* Insufficient permissions */
log_warning("Mode '%s' is not allowed for uid %d", use, uid);
reply = dbus_message_new_error(msg, DBUS_ERROR_ACCESS_DENIED, member);
}
else if( control_get_cable_state() != CABLE_STATE_PC_CONNECTED ) {
/* Mode change makes no sence unless we have a PC connection */
log_warning("Mode '%s' requested while not connected to pc", use);
......@@ -401,6 +413,11 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
#ifdef SAILFISH_ACCESS_CONTROL
/* do not let non-owner user hide modes */
else if (!sailfish_access_control_hasgroup(umdbus_get_sender_uid(sender), "sailfish-system"))
reply = dbus_message_new_error(msg, DBUS_ERROR_ACCESS_DENIED, member);
#endif
else
{
/* error checking is done when setting configuration */
......@@ -422,6 +439,11 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
#ifdef SAILFISH_ACCESS_CONTROL
/* do not let non-owner user unhide modes */
else if (!sailfish_access_control_hasgroup(umdbus_get_sender_uid(sender), "sailfish-system"))
reply = dbus_message_new_error(msg, DBUS_ERROR_ACCESS_DENIED, member);
#endif
else
{
/* error checking is done when setting configuration */
......@@ -500,7 +522,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
}
else if(!strcmp(member, USB_MODE_LIST))
{
gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST);
gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST, 0);
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID);
......@@ -508,12 +530,23 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
}
else if(!strcmp(member, USB_MODE_AVAILABLE_MODES_GET))
{
gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST);
gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, 0);
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID);
g_free(mode_list);
}
else if(!strcmp(member, USB_MODE_AVAILABLE_MODES_FOR_USER))
{
uid_t uid = umdbus_get_sender_uid(sender);
gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, uid);
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID);
g_free(mode_list);
control_set_last_seen_user(uid);
}
else if(!strcmp(member, USB_MODE_RESCUE_OFF))
{
usbmoded_set_rescue_mode(false);
......@@ -1323,3 +1356,71 @@ EXIT:
return ack;
}
/**
* Get uid of sender from D-Bus. This makes a synchronous D-Bus call
*
* @param name Name of sender from DBusMessage
* @return Uid of the sender
*/
uid_t umdbus_get_sender_uid(const char *name)
{
LOG_REGISTER_CONTEXT;
pid_t pid = (pid_t)-1;
uid_t uid = (uid_t)-1;
DBusMessage *req = 0;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
char path[256];
struct stat st;
if(!umdbus_connection)
goto EXIT;
req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
DBUS_GET_CONNECTION_PID_REQ);
if( !req ) {
log_err("could not create method call message");
goto EXIT;
}
if( !dbus_message_append_args(req,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID) ) {
log_err("could not add method call parameters");
goto EXIT;
}
/* Synchronous D-Bus call */
rsp = dbus_connection_send_with_reply_and_block(umdbus_connection, req, -1, &err);
if( !rsp && dbus_error_is_set(&err) ) {
log_err("could not get sender pid for %s: %s: %s", name, err.name, err.message);
goto EXIT;
}
if( !dbus_message_get_args(rsp, &err,
DBUS_TYPE_UINT32, &pid,
DBUS_TYPE_INVALID) ) {
log_err("parse error: %s: %s", err.name, err.message);
goto EXIT;
}
snprintf(path, sizeof path, "/proc/%d", (int)pid);
memset(&st, 0, sizeof st);
if( stat(path, &st) != -1 ) {
uid = st.st_uid;
}
EXIT:
if( req ) dbus_message_unref(req);
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
return uid;
}
......@@ -59,23 +59,24 @@
# define USB_MODE_TARGET_CONFIG_SIGNAL_NAME "sig_usb_taget_mode_config_ind"
/* supported methods */
# define USB_MODE_STATE_REQUEST "mode_request" /* returns the current mode */
# define USB_MODE_TARGET_STATE_GET "get_target_state" /* returns the target mode */
# define USB_MODE_RESCUE_OFF "rescue_off" /* turns rescue mode off so normal mode selection is restored */
# define USB_MODE_CONFIG_GET "get_config" /* returns the mode set in the config */
# define USB_MODE_LIST "get_modes" /* returns a comma-separated list of supported modes for ui's */
# define USB_MODE_HIDE "hide_mode" /* hide a mode */
# define USB_MODE_UNHIDE "unhide_mode" /* unhide a mode */
# define USB_MODE_HIDDEN_GET "get_hidden" /* return the hidden modes */
# define USB_MODE_STATE_SET "set_mode" /* set a mode (only works when connected) */
# define USB_MODE_CONFIG_SET "set_config" /* set the mode that needs to be activated in the config file */
# define USB_MODE_NETWORK_SET "net_config" /* set the network config in the config file */
# define USB_MODE_NETWORK_GET "get_net_config" /* get the network config from the config file */
# define USB_MODE_WHITELISTED_MODES_GET "get_whitelisted_modes" /* get the list of whitelisted modes */
# define USB_MODE_WHITELISTED_MODES_SET "set_whitelisted_modes" /* set the list of whitelisted modes */
# define USB_MODE_WHITELISTED_SET "set_whitelisted" /* sets whether an specific mode is in the whitelist */
# define USB_MODE_AVAILABLE_MODES_GET "get_available_modes" /* returns a comma separated list of modes which are currently available for selection */
# define USB_MODE_TARGET_CONFIG_GET "get_target_mode_config" /* returns current target mode configuration */
# define USB_MODE_STATE_REQUEST "mode_request" /* returns the current mode */
# define USB_MODE_TARGET_STATE_GET "get_target_state" /* returns the target mode */
# define USB_MODE_RESCUE_OFF "rescue_off" /* turns rescue mode off so normal mode selection is restored */
# define USB_MODE_CONFIG_GET "get_config" /* returns the mode set in the config */
# define USB_MODE_LIST "get_modes" /* returns a comma-separated list of supported modes for ui's */
# define USB_MODE_HIDE "hide_mode" /* hide a mode */
# define USB_MODE_UNHIDE "unhide_mode" /* unhide a mode */
# define USB_MODE_HIDDEN_GET "get_hidden" /* return the hidden modes */
# define USB_MODE_STATE_SET "set_mode" /* set a mode (only works when connected) */
# define USB_MODE_CONFIG_SET "set_config" /* set the mode that needs to be activated in the config file */
# define USB_MODE_NETWORK_SET "net_config" /* set the network config in the config file */
# define USB_MODE_NETWORK_GET "get_net_config" /* get the network config from the config file */
# define USB_MODE_WHITELISTED_MODES_GET "get_whitelisted_modes" /* get the list of whitelisted modes */
# define USB_MODE_WHITELISTED_MODES_SET "set_whitelisted_modes" /* set the list of whitelisted modes */
# define USB_MODE_WHITELISTED_SET "set_whitelisted" /* sets whether an specific mode is in the whitelist */
# define USB_MODE_AVAILABLE_MODES_GET "get_available_modes" /* returns a comma separated list of modes which are currently available for selection */
# define USB_MODE_AVAILABLE_MODES_FOR_USER "get_available_modes_for_user" /* returns a comma separated list of modes which are currently available and permitted for user to select */
# define USB_MODE_TARGET_CONFIG_GET "get_target_mode_config" /* returns current target mode configuration */
/**
* (Transient) states reported by "sig_usb_state_ind" that are not modes.
......
......@@ -65,6 +65,10 @@
#include <errno.h>
#include <string.h>
#ifdef SAILFISH_ACCESS_CONTROL
# include <sailfishaccesscontrol.h>
#endif
#ifdef SYSTEMD
# include <systemd/sd-daemon.h>
#endif
......@@ -116,6 +120,7 @@ bool usbmoded_get_rescue_mode (void);
void usbmoded_set_rescue_mode (bool rescue_mode);
bool usbmoded_get_diag_mode (void);
void usbmoded_set_diag_mode (bool diag_mode);
bool usbmoded_is_mode_permitted (const char *modename, uid_t uid);
void usbmoded_set_cable_connection_delay(int delay_ms);
int usbmoded_get_cable_connection_delay(void);
static gboolean usbmoded_allow_suspend_timer_cb (gpointer aptr);
......@@ -340,6 +345,41 @@ void usbmoded_set_diag_mode(bool diag_mode)
}
}
/* ------------------------------------------------------------------------- *
* ACCESS_CHECKS
* ------------------------------------------------------------------------- */
bool usbmoded_is_mode_permitted(const char *modename, uid_t uid)
{
#ifdef SAILFISH_ACCESS_CONTROL
LOG_REGISTER_CONTEXT;
bool allowed = true;
modedata_t *data = 0;
/* all modes are allowed for root */
if( uid == 0 )
goto EXIT;
/* non-dynamic modes are allowed for all */
if( !(data = usbmoded_dup_modedata(modename)) )
goto EXIT;
/* dynamic modes are allowed for device owner and denied for others */
allowed = sailfish_access_control_hasgroup(uid, "sailfish-system");
EXIT:
modedata_free(data);
return allowed;
#else
return true;
#endif
}
/* ------------------------------------------------------------------------- *
* CABLE_CONNECT_DELAY
* ------------------------------------------------------------------------- */
......
......@@ -75,6 +75,7 @@ bool usbmoded_get_rescue_mode (void);
void usbmoded_set_rescue_mode (bool rescue_mode);
bool usbmoded_get_diag_mode (void);
void usbmoded_set_diag_mode (bool diag_mode);
bool usbmoded_is_mode_permitted (const char *modename, uid_t uid);
void usbmoded_set_cable_connection_delay(int delay_ms);
int usbmoded_get_cable_connection_delay(void);
void usbmoded_allow_suspend (void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment