Skip to content

Commit

Permalink
Merge branch 'jb49457_user_specific_mode' into 'master'
Browse files Browse the repository at this point in the history
[config] Set and get user specific mode. Fixes JB#49457

See merge request mer-core/usb-moded!60
  • Loading branch information
Tomin1 committed Jun 3, 2020
2 parents 8c821dc + 7b5d0b6 commit a1719dc
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 41 deletions.
4 changes: 2 additions & 2 deletions configure.ac
Expand Up @@ -49,9 +49,9 @@ 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@:>@]),
AC_ARG_ENABLE([sailfish_access_control], AS_HELP_STRING([--enable-sailfish-access-control], [Enable Sailfish Access Control, implies --enable-systemd @<:@default=false@:>@]),
[case "${enableval}" in
yes) sailfish_access_control=true ; CFLAGS="-DSAILFISH_ACCESS_CONTROL $CFLAGS" ;;
yes) sailfish_access_control=true ; CFLAGS="-DSAILFISH_ACCESS_CONTROL $CFLAGS" ; enable_systemd=yes ;;
no) sailfish_access_control=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-sailfish-access-control]) ;;
esac],[sailfish_access_control=false])
Expand Down
5 changes: 5 additions & 0 deletions docs/usb_moded-doc.txt
Expand Up @@ -110,6 +110,11 @@ Also the default usb mode can be configured there. For example:

[usbmode]
mode = ask
mode_100001 = charging

This says that default mode for user with uid 100001 is charging and other users default to mode ask.
Modes with uid are only used when built with --enable-sailfish-access-control and
only users with uid higher than 100000 and lower or equal to 999999 can have user specific usb modes.

The other settings and config dirs will be handled later in the appsync and dynamic modes part.
(This is optional and can be compiled out)
Expand Down
5 changes: 5 additions & 0 deletions src/usb_moded-common.h
Expand Up @@ -98,4 +98,9 @@ gchar *common_get_mode_list (mode_list_type_t type, uid_t ui
# define common_msleep(msec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(msec))
# define common_sleep(sec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000)

/* ========================================================================= *
* Constants
* ========================================================================= */
# define UID_UNKNOWN ((uid_t)-1)

#endif /* USB_MODED_COMMON_H_ */
11 changes: 9 additions & 2 deletions src/usb_moded-config-private.h
Expand Up @@ -52,6 +52,11 @@
# define USB_MODED_DYNAMIC_CONFIG_DIR "/var/lib/usb-moded"
# define USB_MODED_DYNAMIC_CONFIG_FILE USB_MODED_DYNAMIC_CONFIG_DIR"/usb-moded.ini"

#ifdef SAILFISH_ACCESS_CONTROL
# define MIN_ADDITIONAL_USER 100001
# define MAX_ADDITIONAL_USER 999999
#endif

/* ========================================================================= *
* Prototypes
* ========================================================================= */
Expand All @@ -71,9 +76,11 @@ char *config_get_trigger_mode (void);
char *config_get_trigger_property (void);
char *config_get_trigger_value (void);
char *config_get_conf_string (const gchar *entry, const gchar *key);
char *config_get_mode_setting (void);
gchar *config_get_user_conf_string (const gchar *entry, const gchar *base_key, uid_t uid);
char *config_get_mode_setting (uid_t uid);
set_config_result_t config_set_config_setting (const char *entry, const char *key, const char *value);
set_config_result_t config_set_mode_setting (const char *mode);
set_config_result_t config_set_user_config_setting (const char *entry, const char *base_key, const char *value, uid_t uid);
set_config_result_t config_set_mode_setting (const char *mode, uid_t uid);
set_config_result_t config_set_hide_mode_setting (const char *mode);
set_config_result_t config_set_unhide_mode_setting (const char *mode);
set_config_result_t config_set_mode_whitelist (const char *whitelist);
Expand Down
76 changes: 64 additions & 12 deletions src/usb_moded-config.c
Expand Up @@ -80,10 +80,13 @@ static char *config_get_network_netmask (void);
static char *config_get_network_nat_interface(void);
static int config_get_conf_int (const gchar *entry, const gchar *key);
char *config_get_conf_string (const gchar *entry, const gchar *key);
static gchar *config_make_user_key_string (const gchar *base_key, uid_t uid);
gchar *config_get_user_conf_string (const gchar *entry, const gchar *base_key, uid_t uid);
static char *config_get_kcmdline_string (const char *entry);
char *config_get_mode_setting (void);
char *config_get_mode_setting (uid_t uid);
set_config_result_t config_set_config_setting (const char *entry, const char *key, const char *value);
set_config_result_t config_set_mode_setting (const char *mode);
set_config_result_t config_set_user_config_setting (const char *entry, const char *base_key, const char *value, uid_t uid);
set_config_result_t config_set_mode_setting (const char *mode, uid_t uid);
static char *config_make_modes_string (const char *key, const char *mode_name, int include);
set_config_result_t config_set_hide_mode_setting (const char *mode);
set_config_result_t config_set_unhide_mode_setting (const char *mode);
Expand Down Expand Up @@ -290,6 +293,34 @@ char *config_get_conf_string(const gchar *entry, const gchar *key)
return val;
}

static gchar *config_make_user_key_string(const gchar *base_key, uid_t uid)
{
LOG_REGISTER_CONTEXT;

gchar *key = 0;
#ifdef SAILFISH_ACCESS_CONTROL
/* If uid is for an additional user, construct a key */
if( uid >= MIN_ADDITIONAL_USER && uid <= MAX_ADDITIONAL_USER )
key = g_strdup_printf("%s_%d", base_key, (int)uid);
#endif
return key;
}

gchar *config_get_user_conf_string(const gchar *entry, const gchar *base_key, uid_t uid)
{
LOG_REGISTER_CONTEXT;

gchar *value = 0;
gchar *key = config_make_user_key_string(base_key, uid);
if( key )
value = config_get_conf_string(entry, key);
/* Fallback to global config if user doesn't have a value set */
if( !value )
value = config_get_conf_string(entry, base_key);
g_free(key);
return value;
}

static char * config_get_kcmdline_string(const char *entry)
{
LOG_REGISTER_CONTEXT;
Expand Down Expand Up @@ -368,7 +399,7 @@ static char * config_get_kcmdline_string(const char *entry)
return ret;
}

char * config_get_mode_setting(void)
char * config_get_mode_setting(uid_t uid)
{
LOG_REGISTER_CONTEXT;

Expand All @@ -378,11 +409,18 @@ char * config_get_mode_setting(void)
if( (mode = config_get_kcmdline_string(MODE_SETTING_KEY)) )
goto EXIT;

if( (mode = config_get_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY)) )
goto EXIT;
mode = config_get_user_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY, uid);

/* If no default mode is configured, treat it as charging only */
mode = g_strdup(MODE_CHARGING);
if( !mode )
mode = g_strdup(MODE_CHARGING);
/* If mode is not allowed, i.e. non-existent or not whitelisted or permitted, use MODE_ASK */
else if( strcmp(mode, MODE_ASK) && (common_valid_mode(mode) || !usbmoded_is_mode_permitted(mode, uid)) ) {
log_warning("default mode '%s' is not valid for uid '%d', reset to '%s'",
mode, (int)uid, MODE_ASK);
g_free(mode), mode = g_strdup(MODE_ASK);
config_set_mode_setting(mode, uid);
}

EXIT:
return mode;
Expand Down Expand Up @@ -426,17 +464,30 @@ set_config_result_t config_set_config_setting(const char *entry, const char *key
return ret;
}

set_config_result_t config_set_mode_setting(const char *mode)
set_config_result_t config_set_user_config_setting(const char *entry, const char *base_key, const char *value, uid_t uid)
{
LOG_REGISTER_CONTEXT;

gchar *key = config_make_user_key_string(base_key, uid);
set_config_result_t ret = config_set_config_setting(entry, key ?: base_key, value);
g_free(key);
return ret;
}

set_config_result_t config_set_mode_setting(const char *mode, uid_t uid)
{
LOG_REGISTER_CONTEXT;

/* Don't write values that don't exist */
if (strcmp(mode, MODE_ASK) && common_valid_mode(mode))
return SET_CONFIG_ERROR;

int ret = config_set_config_setting(MODE_SETTING_ENTRY,
MODE_SETTING_KEY, mode);
/* Don't write values that are not permitted */
if (!usbmoded_is_mode_permitted(mode, uid))
return SET_CONFIG_ERROR;

return ret;
return config_set_user_config_setting(MODE_SETTING_ENTRY,
MODE_SETTING_KEY, mode, uid);
}

/* Builds the string used for hidden modes, when hide set to one builds the
Expand Down Expand Up @@ -558,9 +609,10 @@ set_config_result_t config_set_mode_whitelist(const char *whitelist)
char *mode_setting;
const char *current_mode;

mode_setting = config_get_mode_setting();
uid_t current_user = control_get_current_user();
mode_setting = config_get_mode_setting(current_user);
if (strcmp(mode_setting, MODE_ASK) && common_valid_mode(mode_setting))
config_set_mode_setting(MODE_ASK);
config_set_mode_setting(MODE_ASK, current_user);
g_free(mode_setting);

current_mode = control_get_usb_mode();
Expand Down
46 changes: 32 additions & 14 deletions src/usb_moded-control.c
Expand Up @@ -34,6 +34,15 @@
#include <string.h>
#include <stdlib.h>

#ifdef SYSTEMD
# include <systemd/sd-login.h>
#endif

/* Sanity check, configure should take care of this */
#if defined SAILFISH_ACCESS_CONTROL && !defined SYSTEMD
# error if SAILFISH_ACCESS_CONTROL is defined, SYSTEMD must be defined as well
#endif

/* ========================================================================= *
* Prototypes
* ========================================================================= */
Expand All @@ -59,7 +68,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);
uid_t control_get_current_user (void);

/* ========================================================================= *
* Data
Expand Down Expand Up @@ -91,12 +100,6 @@ 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
* ========================================================================= */
Expand Down Expand Up @@ -340,17 +343,22 @@ void control_select_usb_mode(void)
goto EXIT;
}

mode_to_set = config_get_mode_setting();
uid_t current_user = control_get_current_user();
/* If current user could not be determined, assume that device is
* booting up or between sessions. Therefore we either must use whatever
* is configured as global mode or let device lock to prevent the mode
* so that it can be set again once the device is unlocked */
mode_to_set = config_get_mode_setting((current_user == UID_UNKNOWN) ? 0 : current_user);

/* If there is only one allowed mode, use it without
* going through ask-mode */
if( !strcmp(MODE_ASK, mode_to_set) ) {
if( control_last_seen_user == (uid_t)-1 ) {
if( current_user == UID_UNKNOWN ) {
/* 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);
gchar *available = common_get_mode_list(AVAILABLE_MODES_LIST, current_user);
if( *available && !strchr(available, ',') ) {
free(mode_to_set), mode_to_set = available, available = 0;
}
Expand Down Expand Up @@ -445,11 +453,21 @@ bool control_get_connection_state(void)
return connected;
}

/** Set the last seen user
/**
* Get the user using the device
*
* When built without Sailfish access control support,
* this returns root's uid (0) unconditionally.
*
* @param uid of last seen user, controls implicitly set modes
* @return current user on seat0 or UID_UNKNOWN if it can not be determined
*/
void control_set_last_seen_user(uid_t uid)
uid_t control_get_current_user(void)
{
control_last_seen_user = uid;
#ifdef SAILFISH_ACCESS_CONTROL
uid_t uid = UID_UNKNOWN;
sd_seat_get_active("seat0", 0, &uid);
return uid;
#else
return 0;
#endif
}
2 changes: 1 addition & 1 deletion src/usb_moded-control.h
Expand Up @@ -50,6 +50,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);
uid_t control_get_current_user (void);

#endif /* USB_MODED_CONTROL_H_ */
18 changes: 10 additions & 8 deletions src/usb_moded-dbus.c
Expand Up @@ -57,6 +57,8 @@
#define INIT_DONE_SIGNAL "init_done"
#define INIT_DONE_MATCH "type='signal',interface='"INIT_DONE_INTERFACE"',member='"INIT_DONE_SIGNAL"'"

# define PID_UNKNOWN ((pid_t)-1)

/* ========================================================================= *
* Prototypes
* ========================================================================= */
Expand Down Expand Up @@ -422,15 +424,16 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
}
else if(!strcmp(member, USB_MODE_CONFIG_SET))
{
char *config = 0;
char *config = 0;
DBusError err = DBUS_ERROR_INIT;
uid_t uid = umdbus_get_sender_uid(sender);

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);
else
{
/* error checking is done when setting configuration */
int ret = config_set_mode_setting(config);
int ret = config_set_mode_setting(config, uid);
if (SET_CONFIG_OK(ret))
{
if((reply = dbus_message_new_method_return(msg)))
Expand Down Expand Up @@ -549,7 +552,8 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
}
else if(!strcmp(member, USB_MODE_CONFIG_GET))
{
char *config = config_get_mode_setting();
uid_t uid = umdbus_get_sender_uid(sender);
char *config = config_get_mode_setting(uid);

if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
Expand Down Expand Up @@ -579,8 +583,6 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB
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))
{
Expand Down Expand Up @@ -1396,14 +1398,14 @@ gboolean umdbus_get_name_owner_async(const char *name,
* 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
* @return Uid of the sender or UID_UNKNOWN if it can not be determined
*/
uid_t umdbus_get_sender_uid(const char *name)
{
LOG_REGISTER_CONTEXT;

pid_t pid = (pid_t)-1;
uid_t uid = (uid_t)-1;
pid_t pid = PID_UNKNOWN;
uid_t uid = UID_UNKNOWN;
DBusMessage *req = 0;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
Expand Down
11 changes: 9 additions & 2 deletions src/usb_moded.c
Expand Up @@ -363,6 +363,12 @@ bool usbmoded_is_mode_permitted(const char *modename, uid_t uid)
if( uid == 0 )
goto EXIT;

/* non-existing special value, deny everything */
if( uid == UID_UNKNOWN ) {
allowed = false;
goto EXIT;
}

/* non-dynamic modes are allowed for all */
if( !(data = usbmoded_dup_modedata(modename)) )
goto EXIT;
Expand Down Expand Up @@ -621,12 +627,13 @@ void usbmoded_handle_signal(int signum)

/* If default mode selection became invalid,
* revert setting to "ask" */
gchar *config = config_get_mode_setting();
uid_t current_user = control_get_current_user();
gchar *config = config_get_mode_setting(current_user);
if( g_strcmp0(config, MODE_ASK) &&
common_valid_mode(config) ) {
log_warning("default mode '%s' is not valid, reset to '%s'",
config, MODE_ASK);
config_set_mode_setting(MODE_ASK);
config_set_mode_setting(MODE_ASK, current_user);
}
else {
log_debug("default mode '%s' is still valid", config);
Expand Down

0 comments on commit a1719dc

Please sign in to comment.