mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2026-10-28 09:43:51 +00:00
Implement Polkit agent for platforms that lack them (#244)
* attempt to set up polkit listener * implement polkit agent functionality * finalized polkit implementation * add warning for installing polkit rule * docker: install libpolkit-agent-1-dev * add uninstall polkit option --------- Co-authored-by: MattKC <mattkc@noreply.git.mattkc.com>
This commit is contained in:
1 parent
6bf8d4898b
commit
61e2a91028
30 files changed
+894
-260
No files matched your search
@@ -23,7 +23,6 @@ OPTION(VANILLA_BUILD_GUI "Build SDL2 GUI app" ON)
|
||||
OPTION(VANILLA_BUILD_TESTS "Build unit tests for Vanilla" OFF)
|
||||
OPTION(VANILLA_BUILD_PIPE "Build vanilla-pipe for connecting to Wii U (Linux only)" ${LINUX})
|
||||
OPTION(VANILLA_BUILD_VENDORED "Build Vanilla with \"vendored\" third-party libraries" ${vendored_default})
|
||||
OPTION(VANILLA_INSTALL_POLKIT_RULE "Install vanilla-pipe with Polkit rule to allow use without entering password" ON)
|
||||
|
||||
add_subdirectory(lib)
|
||||
if (VANILLA_BUILD_PIPE)
|
||||
|
||||
@@ -45,7 +45,8 @@ RUN if [ "${ARCH}" = "aarch64" ]; then export DEBARCH="arm64"; export DEBGCC="gc
|
||||
&& apt -y install libice-dev:$DEBARCH \
|
||||
&& apt -y install libgbm-dev:$DEBARCH \
|
||||
&& apt -y install libva-dev:$DEBARCH \
|
||||
&& apt -y install libxkbcommon-dev:$DEBARCH
|
||||
&& apt -y install libxkbcommon-dev:$DEBARCH \
|
||||
&& apt -y install libpolkit-agent-1-dev:$DEBARCH
|
||||
|
||||
# Install newer version of CMake
|
||||
ENV CMAKE_VER=3.31.5
|
||||
|
||||
+12
-2
@@ -251,6 +251,8 @@ list(APPEND VANILLA_GUI_SRC
|
||||
menu/menu_region.c
|
||||
menu/menu_rename.c
|
||||
menu/menu_settings.c
|
||||
menu/menu_sudo.c
|
||||
menu/menu_sudo_warning.c
|
||||
menu/menu_sync.c
|
||||
pipemgmt.c
|
||||
platform.c
|
||||
@@ -318,10 +320,18 @@ if (APPLE)
|
||||
target_link_libraries(vanilla PRIVATE "-framework VideoToolbox" "-framework CoreMedia" iconv)
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
# Assume this platform is capable of running vanilla-pipe
|
||||
if (VANILLA_BUILD_PIPE)
|
||||
# Assume this platform is capable of running vanilla-pipe
|
||||
target_compile_definitions(vanilla PRIVATE VANILLA_PIPE_AVAILABLE)
|
||||
|
||||
# Find Polkit and GLIB libraries
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_POLKIT polkit-agent-1 REQUIRED IMPORTED_TARGET)
|
||||
target_include_directories(vanilla PRIVATE ${PC_POLKIT_INCLUDE_DIRS})
|
||||
target_link_libraries(vanilla PRIVATE ${PC_POLKIT_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
# Link with DRM if available
|
||||
find_package(DRM)
|
||||
if (DRM_FOUND)
|
||||
|
||||
@@ -45,6 +45,13 @@ static const char *lang_str[__VPI_LANG_T_COUNT] = {
|
||||
"America",
|
||||
"Europe",
|
||||
"Quit",
|
||||
"Authentication failed. Please try again.",
|
||||
"Don't ask again",
|
||||
"WARNING",
|
||||
"This option will install a Polkit rule that will allow Vanilla's backend to run as root without password entry.\n\nThere are inherent risks to bypassing security systems. Only enable this if you are willing to accept those risks.\n\nNOTE: If you are using the Steam Deck, this will also disable read-only access to your system partition.",
|
||||
"I acknowledge",
|
||||
"Enable Root Password Skip",
|
||||
"Disable Root Password Skip"
|
||||
};
|
||||
|
||||
const char *lang(vpi_lang_t id)
|
||||
|
||||
@@ -46,6 +46,13 @@ typedef enum {
|
||||
VPI_LANG_REGION_AMERICA,
|
||||
VPI_LANG_REGION_EUROPE,
|
||||
VPI_LANG_QUIT,
|
||||
VPI_LANG_AUTH_FAIL,
|
||||
VPI_LANG_AUTH_DONT_ASK_AGAIN,
|
||||
VPI_LANG_AUTH_WARNING,
|
||||
VPI_LANG_AUTH_WARNING_MESSAGE,
|
||||
VPI_LANG_AUTH_WARNING_ACKNOWLEDGE,
|
||||
VPI_LANG_ENABLE_PASSWORD_SKIP,
|
||||
VPI_LANG_DISABLE_PASSWORD_SKIP,
|
||||
__VPI_LANG_T_COUNT
|
||||
} vpi_lang_t;
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ int SDL_main(int argc, const char **argv)
|
||||
vpi_menu_init(vui);
|
||||
|
||||
while (vui_update_sdl(vui)) {
|
||||
vpi_update_pipe();
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "lang.h"
|
||||
#include "menu_connection.h"
|
||||
#include "menu_main.h"
|
||||
#include "menu_sudo.h"
|
||||
#include "menu_sync.h"
|
||||
#include "pipemgmt.h"
|
||||
#include "ui/ui_anim.h"
|
||||
@@ -23,7 +24,7 @@ void vpi_menu_create_background(vui_context_t *vui, int layer, vui_rect_t *bkg_r
|
||||
bkg_rect->y = m;
|
||||
bkg_rect->w = scrw-m-m;
|
||||
bkg_rect->h = scrh-m-m;
|
||||
|
||||
|
||||
vui_rect_create(vui, bkg_rect->x, bkg_rect->y, bkg_rect->w, bkg_rect->h, scrh*1/10, vui_color_create(0, 0, 0, 0.66f), layer);
|
||||
}
|
||||
|
||||
@@ -78,6 +79,8 @@ void vpi_menu_start_pipe(vui_context_t *vui, int fade_fglayer, vui_callback_t su
|
||||
int r = vpi_start_pipe();
|
||||
if (r == VANILLA_SUCCESS) {
|
||||
success_action(vui, success_data);
|
||||
} else if (r == VANILLA_REQUIRES_PASSWORD_HANDLING) {
|
||||
vpi_menu_sudo(vui, success_action, success_data, cancel_action, cancel_data, fade_fglayer);
|
||||
} else {
|
||||
if (cancel_action) {
|
||||
cancel_action(vui, cancel_data);
|
||||
@@ -132,4 +135,4 @@ static void do_quit(vui_context_t *vui, void *v)
|
||||
void vpi_menu_quit_vanilla(vui_context_t *vui)
|
||||
{
|
||||
vui_transition_fade_black_in(vui, do_quit, 0);
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ static void local_connection_menu(vui_context_t *vui, void *v)
|
||||
update_wireless_buttons(vui);
|
||||
|
||||
vpi_menu_create_back_button(vui, fglayer, return_to_connection, (void *) (intptr_t) fglayer);
|
||||
|
||||
|
||||
vui_transition_fade_layer_in(vui, fglayer, 0, 0);
|
||||
}
|
||||
|
||||
@@ -193,11 +193,11 @@ static void via_server_connection_menu(vui_context_t *vui, void *v)
|
||||
ip_text = inet_ntoa(in);
|
||||
}
|
||||
|
||||
ip_textedit = vui_textedit_create(vui, textedit_x, bkg_rect.y + bkg_rect.h * 3 / 7, textedit_w, textedit_h, ip_text, VUI_FONT_SIZE_NORMAL, fglayer);
|
||||
ip_textedit = vui_textedit_create(vui, textedit_x, bkg_rect.y + bkg_rect.h * 3 / 7, textedit_w, textedit_h, ip_text, VUI_FONT_SIZE_NORMAL, 0, fglayer);
|
||||
|
||||
error_lbl = vui_label_create(vui, textedit_x, bkg_rect.y + bkg_rect.h * 4 / 7, textedit_w, BTN_SZ, "Invalid IP address", vui_color_create(1,0,0,1), VUI_FONT_SIZE_SMALL, fglayer);
|
||||
vui_label_update_visible(vui, error_lbl, 0);
|
||||
|
||||
|
||||
vui_button_create(vui, textedit_x, bkg_rect.y + bkg_rect.h * 5 / 7, textedit_w, BTN_SZ, lang(VPI_LANG_OK_BTN), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, check_ip_address, (void *) (intptr_t) fglayer);
|
||||
|
||||
vpi_menu_create_back_button(vui, fglayer, return_to_connection, (void *) (intptr_t) fglayer);
|
||||
@@ -259,7 +259,7 @@ void vpi_menu_connection_and_return_to(vui_context_t *vui, int fade_fglayer, vui
|
||||
|
||||
// Back button
|
||||
vpi_menu_create_back_button(vui, fglayer, return_to_settings, (void *) (intptr_t) bglayer);
|
||||
|
||||
|
||||
vui_transition_fade_layer_in(vui, fade_fglayer ? fglayer : bglayer, 0, 0);
|
||||
|
||||
g_continue_callback = success_callback;
|
||||
@@ -271,4 +271,4 @@ void vpi_menu_connection_and_return_to(vui_context_t *vui, int fade_fglayer, vui
|
||||
void vpi_menu_connection(vui_context_t *vui, void *v)
|
||||
{
|
||||
vpi_menu_connection_and_return_to(vui, (intptr_t) v, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ void vpi_menu_rename(vui_context_t *vui, void *v)
|
||||
|
||||
const int textedit_w = bkg_rect.w / 2;
|
||||
const int textedit_h = vui_get_font_height(vui, VUI_FONT_SIZE_NORMAL);
|
||||
textedit = vui_textedit_create(vui, bkg_rect.x + bkg_rect.w/2 - textedit_w/2, bkg_rect.y + bkg_rect.h * 1 / 3, textedit_w, textedit_h, vpi_config.connected_console_entries[console].name, VUI_FONT_SIZE_NORMAL, fglayer);
|
||||
textedit = vui_textedit_create(vui, bkg_rect.x + bkg_rect.w/2 - textedit_w/2, bkg_rect.y + bkg_rect.h * 1 / 3, textedit_w, textedit_h, vpi_config.connected_console_entries[console].name, VUI_FONT_SIZE_NORMAL, 0, fglayer);
|
||||
|
||||
static const int ok_btn_w = BTN_SZ * 3;
|
||||
static const int cancel_btn_w = BTN_SZ * 3;
|
||||
@@ -50,4 +50,4 @@ void vpi_menu_rename(vui_context_t *vui, void *v)
|
||||
vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - (ok_btn_w + cancel_btn_w)/2 + ok_btn_w, bkg_rect.y + bkg_rect.h * 3 / 4, cancel_btn_w, BTN_SZ, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, vpi_menu_rename_return_to_edit, v);
|
||||
|
||||
vui_transition_fade_layer_in(vui, fglayer, 0, 0);
|
||||
}
|
||||
}
|
||||
+83
-28
@@ -1,11 +1,17 @@
|
||||
#include "menu_settings.h"
|
||||
|
||||
#include <vanilla.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "lang.h"
|
||||
#include "menu_common.h"
|
||||
#include "menu_connection.h"
|
||||
#include "menu_gamepad.h"
|
||||
#include "menu_main.h"
|
||||
#include "menu_region.h"
|
||||
#include "menu_sudo_warning.h"
|
||||
#include "pipe/def.h"
|
||||
#include "ui/ui_anim.h"
|
||||
|
||||
static void return_to_main(vui_context_t *vui, int btn, void *v)
|
||||
@@ -37,56 +43,105 @@ static void thunk_to_quit(vui_context_t *vui, int button, void *v)
|
||||
vpi_menu_quit_vanilla(vui);
|
||||
}
|
||||
|
||||
static void do_polkit_install(vui_context_t *vui, void *v)
|
||||
{
|
||||
int install = (intptr_t) v;
|
||||
if (install) {
|
||||
vanilla_install_polkit(vpi_config.server_address);
|
||||
} else {
|
||||
vanilla_uninstall_polkit(vpi_config.server_address);
|
||||
}
|
||||
vpi_menu_settings(vui, 0);
|
||||
}
|
||||
|
||||
static void thunk_to_start_pipe_for_polkit_rule_install(vui_context_t *vui, void *v)
|
||||
{
|
||||
vpi_menu_start_pipe(vui, 0, do_polkit_install, v, 0, 0);
|
||||
}
|
||||
|
||||
int tmp_fglayer;
|
||||
static void install_polkit_rule_ack(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, tmp_fglayer, thunk_to_start_pipe_for_polkit_rule_install, v);
|
||||
}
|
||||
|
||||
static void install_polkit_rule_cancel(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, tmp_fglayer, vpi_menu_settings, 0);
|
||||
}
|
||||
|
||||
static void install_polkit_rule(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
tmp_fglayer = vui_layer_create(vui);
|
||||
|
||||
vpi_menu_create_sudo_warning(vui, tmp_fglayer, install_polkit_rule_ack, v, install_polkit_rule_cancel, 0);
|
||||
|
||||
vui_transition_fade_layer_in(vui, tmp_fglayer, 0, 0);
|
||||
}
|
||||
|
||||
static void transition_to_install_polkit_rule(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
int layer = (intptr_t) v;
|
||||
vui_transition_fade_layer_out(vui, layer, install_polkit_rule, (void *) (intptr_t) 1);
|
||||
}
|
||||
|
||||
static void transition_to_uninstall_polkit_rule(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
int layer = (intptr_t) v;
|
||||
vui_transition_fade_layer_out(vui, layer, thunk_to_start_pipe_for_polkit_rule_install, 0);
|
||||
}
|
||||
|
||||
void vpi_menu_settings(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int fglayer = vui_layer_create(vui);
|
||||
|
||||
uint8_t console = (uintptr_t) v;
|
||||
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
static const int SETTINGS_NAMES[] = {
|
||||
const int PW_SKIP_SETTING = 3;
|
||||
|
||||
static int SETTINGS_NAMES[] = {
|
||||
VPI_LANG_CONNECTION,
|
||||
VPI_LANG_GAMEPAD,
|
||||
VPI_LANG_REGION,
|
||||
VPI_LANG_QUIT,
|
||||
-1,
|
||||
};
|
||||
|
||||
// Highlight currently implemented functionality
|
||||
static const int SETTINGS_ENABLED[] = {
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
};
|
||||
|
||||
// Highlight currently implemented functionality
|
||||
static const vui_button_callback_t SETTINGS_ACTION[] = {
|
||||
static vui_button_callback_t SETTINGS_ACTION[] = {
|
||||
transition_to_connection,
|
||||
transition_to_gamepad,
|
||||
transition_to_region,
|
||||
thunk_to_quit,
|
||||
0,
|
||||
};
|
||||
|
||||
const int settings_cols = 2;
|
||||
const int settings_rows = 2;
|
||||
const int settings_w = scrw/3;
|
||||
const int settings_h = scrh/3;
|
||||
const int settings_x = scrw/2 - (settings_w*settings_cols)/2;
|
||||
const int settings_y = scrh/2 - (settings_h*settings_rows)/2;
|
||||
for (int y = 0; y < settings_rows; y++) {
|
||||
for (int x = 0; x < settings_cols; x++) {
|
||||
int index = y * settings_cols + x;
|
||||
int b = vui_button_create(vui, settings_x + settings_w * x, settings_y + settings_h * y, settings_w, settings_h, lang(SETTINGS_NAMES[index]), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, SETTINGS_ACTION[index], (void *) (intptr_t) fglayer);
|
||||
vui_button_update_enabled(vui, b, SETTINGS_ENABLED[index]);
|
||||
}
|
||||
}
|
||||
#ifdef VANILLA_PIPE_AVAILABLE
|
||||
int pw_skip_str;
|
||||
vui_button_callback_t pw_skip_action;
|
||||
if (access(POLKIT_ACTION_DST, F_OK) == 0) {
|
||||
SETTINGS_NAMES[PW_SKIP_SETTING] = VPI_LANG_DISABLE_PASSWORD_SKIP;
|
||||
SETTINGS_ACTION[PW_SKIP_SETTING] = transition_to_uninstall_polkit_rule;
|
||||
} else {
|
||||
SETTINGS_NAMES[PW_SKIP_SETTING] = VPI_LANG_ENABLE_PASSWORD_SKIP;
|
||||
SETTINGS_ACTION[PW_SKIP_SETTING] = transition_to_install_polkit_rule;
|
||||
}
|
||||
#endif
|
||||
|
||||
int btnw = scrw*3/4;
|
||||
int btnx = scrw/2 - btnw/2;
|
||||
int btny = scrh/10;
|
||||
for (int index = 0; index < sizeof(SETTINGS_NAMES)/sizeof(int); index++) {
|
||||
if (SETTINGS_ACTION[index]) {
|
||||
vui_button_create(vui, btnx, btny + BTN_SZ * index, btnw, BTN_SZ, lang(SETTINGS_NAMES[index]), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, SETTINGS_ACTION[index], (void *) (intptr_t) fglayer);
|
||||
}
|
||||
}
|
||||
|
||||
// Back button
|
||||
vpi_menu_create_back_button(vui, fglayer, return_to_main, (void *) (intptr_t) fglayer);
|
||||
|
||||
vui_transition_fade_layer_in(vui, fglayer, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "menu_sudo.h"
|
||||
|
||||
#ifdef VANILLA_PIPE_AVAILABLE
|
||||
|
||||
#include "config.h"
|
||||
#include "lang.h"
|
||||
#include "menu_common.h"
|
||||
#include "menu_main.h"
|
||||
#include "menu_sudo_warning.h"
|
||||
#include "ui/ui_anim.h"
|
||||
#include "pipemgmt.h"
|
||||
|
||||
static int fglayer;
|
||||
static int textedit;
|
||||
static vui_callback_t g_success_action;
|
||||
static void *g_success_data;
|
||||
static vui_callback_t g_cancel_action;
|
||||
static void *g_cancel_data;
|
||||
|
||||
static int ok_btn;
|
||||
static int cancel_btn;
|
||||
static int err_lbl;
|
||||
static int remember_btn;
|
||||
static int warning_layer;
|
||||
|
||||
static int remember_warning_displayed = 0;
|
||||
|
||||
static void return_to_main(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
int layer = (intptr_t) v;
|
||||
vpi_cancel_pw();
|
||||
if (g_cancel_action) {
|
||||
g_cancel_action(vui, g_cancel_data);
|
||||
}
|
||||
vui_transition_fade_layer_out(vui, layer, vpi_menu_main, (void *) (intptr_t) 1);
|
||||
}
|
||||
|
||||
static void show_error(vui_context_t *vui, void *v)
|
||||
{
|
||||
vpi_menu_show_error(vui, (int) (intptr_t) v, 1, return_to_main, (void *) (intptr_t) fglayer);
|
||||
}
|
||||
|
||||
static void pw_callback(int result, void *v)
|
||||
{
|
||||
vui_context_t *vui = (vui_context_t *) v;
|
||||
|
||||
switch (result) {
|
||||
case VPI_POLKIT_RESULT_SUCCESS:
|
||||
{
|
||||
int r = vpi_start_epilog();
|
||||
|
||||
if (vui_button_get_checked(vui, remember_btn)) {
|
||||
vanilla_install_polkit(vpi_config.server_address);
|
||||
}
|
||||
|
||||
if (r == VANILLA_SUCCESS) {
|
||||
vui_transition_fade_layer_out(vui, fglayer, g_success_action, g_success_data);
|
||||
} else {
|
||||
vui_transition_fade_layer_out(vui, fglayer, show_error, (void *) (intptr_t) r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VPI_POLKIT_RESULT_RETRY:
|
||||
vui_label_update_text(vui, err_lbl, lang(VPI_LANG_AUTH_FAIL));
|
||||
vui_textedit_update_text(vui, textedit, "");
|
||||
|
||||
vui_button_update_enabled(vui, ok_btn, 1);
|
||||
vui_button_update_enabled(vui, cancel_btn, 1);
|
||||
vui_button_update_enabled(vui, remember_btn, 1);
|
||||
vui_textedit_update_enabled(vui, textedit, 1);
|
||||
break;
|
||||
case VPI_POLKIT_RESULT_FAIL:
|
||||
vui_transition_fade_layer_out(vui, fglayer, show_error, (void *) (intptr_t) VANILLA_PASSWORD_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void submit_pw(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
char buf[1024];
|
||||
vui_textedit_get_text(vui, textedit, buf, sizeof(buf));
|
||||
vpi_submit_pw(buf, pw_callback, vui);
|
||||
|
||||
vui_button_update_enabled(vui, ok_btn, 0);
|
||||
vui_button_update_enabled(vui, cancel_btn, 0);
|
||||
vui_button_update_enabled(vui, remember_btn, 0);
|
||||
vui_textedit_update_enabled(vui, textedit, 0);
|
||||
vui_label_update_text(vui, err_lbl, "");
|
||||
}
|
||||
|
||||
static void hide_warning(vui_context_t *vui, int enable)
|
||||
{
|
||||
vui_layer_set_enabled(vui, warning_layer, 0);
|
||||
vui_layer_set_enabled(vui, fglayer, 1);
|
||||
vui_button_update_checked(vui, remember_btn, enable);
|
||||
if (enable) remember_warning_displayed = 1;
|
||||
}
|
||||
|
||||
static void hide_warning_and_ack(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
hide_warning(vui, 1);
|
||||
}
|
||||
|
||||
static void hide_warning_and_cancel(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
hide_warning(vui, 0);
|
||||
}
|
||||
|
||||
static void dont_ask_again_btn_pressed(vui_context_t *vui, int btn, void *userdata)
|
||||
{
|
||||
int v = !vui_button_get_checked(vui, btn);
|
||||
|
||||
if (v == 1 && !remember_warning_displayed) {
|
||||
vui_layer_set_enabled(vui, warning_layer, 1);
|
||||
vui_layer_set_enabled(vui, fglayer, 0);
|
||||
} else {
|
||||
vui_button_update_checked(vui, btn, v);
|
||||
}
|
||||
}
|
||||
|
||||
void vpi_menu_sudo(vui_context_t *vui, vui_callback_t success_action, void *success_data, vui_callback_t cancel_action, void *cancel_data, int fade_fglayer)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int bglayer = vui_layer_create(vui);
|
||||
fglayer = vui_layer_create(vui);
|
||||
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
vpi_menu_create_background(vui, bglayer, &bkg_rect, &margin);
|
||||
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h*1/10, bkg_rect.w, bkg_rect.h, lang(VPI_LANG_SUDO_HELP_1), vui_color_create(1,1,1,1), VUI_FONT_SIZE_NORMAL, fglayer);
|
||||
vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h*3/10, bkg_rect.w, bkg_rect.h, lang(VPI_LANG_SUDO_HELP_2), vui_color_create(1,1,1,1), VUI_FONT_SIZE_SMALL, fglayer);
|
||||
|
||||
const int textedit_w = bkg_rect.w / 2;
|
||||
const int textedit_h = vui_get_font_height(vui, VUI_FONT_SIZE_NORMAL);
|
||||
textedit = vui_textedit_create(vui, bkg_rect.x + bkg_rect.w/2 - textedit_w/2, bkg_rect.y + bkg_rect.h * 4/10, textedit_w, textedit_h, "", VUI_FONT_SIZE_NORMAL, 1, fglayer);
|
||||
|
||||
g_success_action = success_action;
|
||||
g_success_data = success_data;
|
||||
g_cancel_action = cancel_action;
|
||||
g_cancel_data = cancel_data;
|
||||
|
||||
err_lbl = vui_label_create(vui, bkg_rect.x, bkg_rect.y + bkg_rect.h*11/20, bkg_rect.w, bkg_rect.h, "", vui_color_create(1,0,0,1), VUI_FONT_SIZE_TINY, fglayer);
|
||||
|
||||
static const int ok_btn_w = BTN_SZ * 3;
|
||||
static const int cancel_btn_w = BTN_SZ * 3;
|
||||
|
||||
remember_btn = vui_button_create(vui, bkg_rect.w/2 - textedit_w/2, bkg_rect.y + bkg_rect.h * 6 / 10, textedit_w, BTN_SZ * 3 / 4, lang(VPI_LANG_AUTH_DONT_ASK_AGAIN), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, dont_ask_again_btn_pressed, 0);
|
||||
vui_button_update_checkable(vui, remember_btn, 1);
|
||||
|
||||
ok_btn = vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - (ok_btn_w + cancel_btn_w)/2, bkg_rect.y + bkg_rect.h * 3 / 4, ok_btn_w, BTN_SZ, lang(VPI_LANG_OK_BTN), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, submit_pw, 0);
|
||||
cancel_btn = vui_button_create(vui, bkg_rect.x + bkg_rect.w/2 - (ok_btn_w + cancel_btn_w)/2 + ok_btn_w, bkg_rect.y + bkg_rect.h * 3 / 4, cancel_btn_w, BTN_SZ, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_BUTTON, fglayer, return_to_main, (void *) (intptr_t) fglayer);
|
||||
|
||||
warning_layer = vui_layer_create(vui);
|
||||
vpi_menu_create_sudo_warning(vui, warning_layer, hide_warning_and_ack, 0, hide_warning_and_cancel, 0);
|
||||
vui_layer_set_enabled(vui, warning_layer, 0);
|
||||
|
||||
vui_transition_fade_layer_in(vui, fade_fglayer ? fglayer : bglayer, 0, 0);
|
||||
}
|
||||
|
||||
#endif // VANILLA_PIPE_AVAILABLE
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef VANILLA_PI_MENU_SUDO_H
|
||||
#define VANILLA_PI_MENU_SUDO_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vpi_menu_sudo(vui_context_t *vui, vui_callback_t success_action, void *success_data, vui_callback_t cancel_action, void *cancel_data, int fade_fglayer);
|
||||
|
||||
#endif // VANILLA_PI_MENU_SUDO_H
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "menu_sudo_warning.h"
|
||||
|
||||
#include "lang.h"
|
||||
#include "menu_common.h"
|
||||
|
||||
void vpi_menu_create_sudo_warning(vui_context_t *vui, int layer, vui_button_callback_t ack_action, void *ack_action_userdata, vui_button_callback_t cancel_action, void *cancel_action_userdata)
|
||||
{
|
||||
vui_rect_t bkg_rect;
|
||||
int margin;
|
||||
|
||||
vpi_menu_create_background(vui, layer, &bkg_rect, &margin);
|
||||
|
||||
int warning_lbl_w = bkg_rect.w * 3 / 4;
|
||||
int warning_lbl_x = bkg_rect.x + bkg_rect.w/2 - warning_lbl_w/2;
|
||||
vui_label_create(vui, warning_lbl_x, bkg_rect.y + bkg_rect.h*1/15, warning_lbl_w, bkg_rect.h, lang(VPI_LANG_AUTH_WARNING), vui_color_create(1,0,0,1), VUI_FONT_SIZE_NORMAL, layer);
|
||||
vui_label_create(vui, warning_lbl_x, bkg_rect.y + bkg_rect.h*4/20, warning_lbl_w, bkg_rect.h, lang(VPI_LANG_AUTH_WARNING_MESSAGE), vui_color_create(1,1,1,1), VUI_FONT_SIZE_SMALL, layer);
|
||||
|
||||
const int ack_btn_w = BTN_SZ * 4;
|
||||
const int cancel_btn_w = BTN_SZ * 3;
|
||||
|
||||
const int btn_x = bkg_rect.x + bkg_rect.w/2 - (ack_btn_w+cancel_btn_w)/2;
|
||||
const int btn_y = bkg_rect.y + bkg_rect.h * 3 / 4;
|
||||
vui_button_create(vui, btn_x, btn_y, ack_btn_w, BTN_SZ, lang(VPI_LANG_AUTH_WARNING_ACKNOWLEDGE), 0, VUI_BUTTON_STYLE_BUTTON, layer, ack_action, ack_action_userdata);
|
||||
vui_button_create(vui, btn_x + ack_btn_w, btn_y, cancel_btn_w, BTN_SZ, lang(VPI_LANG_CANCEL_BTN), 0, VUI_BUTTON_STYLE_BUTTON, layer, cancel_action, cancel_action_userdata);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef VANILLA_PI_MENU_SUDO_WARNING_H
|
||||
#define VANILLA_PI_MENU_SUDO_WARNING_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vpi_menu_create_sudo_warning(vui_context_t *vui, int layer, vui_button_callback_t ack_action, void *ack_action_userdata, vui_button_callback_t cancel_action, void *cancel_action_userdata);
|
||||
|
||||
#endif // VANILLA_PI_MENU_SUDO_WARNING_H
|
||||
+329
-32
@@ -15,14 +15,171 @@
|
||||
#include <unistd.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
|
||||
#include <polkit/polkit.h>
|
||||
#include <polkitagent/polkitagent.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "platform.h"
|
||||
|
||||
static pid_t pipe_pid = -1;
|
||||
static pid_t potential_pipe_pid = -1;
|
||||
static int pipe_input;
|
||||
static int pipe_err;
|
||||
static pthread_t pipe_log_thread = 0;
|
||||
|
||||
static int err_pipes[2], in_pipes[2];
|
||||
|
||||
static gpointer polkit_handle = 0;
|
||||
static GMainContext *gmainctx = 0;
|
||||
static PolkitAgentSession *pk_session = 0;
|
||||
|
||||
typedef struct {
|
||||
PolkitAgentListener parent;
|
||||
} VanillaPolkitListener;
|
||||
|
||||
typedef struct {
|
||||
PolkitAgentListenerClass parent_class;
|
||||
} VanillaPolkitListenerClass;
|
||||
|
||||
static VanillaPolkitListener *listener = 0;
|
||||
static vpi_pw_callback pk_pw_callback = 0;
|
||||
static void *pk_pw_callback_userdata = 0;
|
||||
static PolkitIdentity *pk_identity = 0;
|
||||
static GTask *pk_task = 0;
|
||||
static int pk_attempts = 0;
|
||||
static int pk_ignore_complete = 0;
|
||||
static char pk_cookie[256]; // TODO: No actual idea how long a Polkit cookie usually is
|
||||
|
||||
G_DEFINE_TYPE(VanillaPolkitListener, vanilla_polkit_listener, POLKIT_AGENT_TYPE_LISTENER)
|
||||
|
||||
static void try_again();
|
||||
|
||||
static void on_request(PolkitAgentSession *s, const gchar *prompt, gboolean echo_on, gpointer user_data)
|
||||
{
|
||||
vpilog("Polkit authentication requested\n");
|
||||
pk_session = s;
|
||||
}
|
||||
|
||||
static void on_show_info(PolkitAgentSession *s, const gchar *text, gpointer user_data)
|
||||
{
|
||||
vpilog("Info\n");
|
||||
if (text) vpilog("%s\n", text);
|
||||
}
|
||||
|
||||
static void on_show_error(PolkitAgentSession *s, const gchar *text, gpointer user_data)
|
||||
{
|
||||
vpilog("Error\n");
|
||||
if (text) vpilog("Error: %s\n", text);
|
||||
}
|
||||
|
||||
static void on_complete(PolkitAgentSession *s, gboolean gained, gpointer data)
|
||||
{
|
||||
vpilog("Complete: %i\n", gained);
|
||||
|
||||
g_object_unref(pk_session);
|
||||
pk_session = 0;
|
||||
|
||||
if (!pk_ignore_complete) {
|
||||
pk_attempts++;
|
||||
|
||||
if (pk_pw_callback) {
|
||||
int cb_ret;
|
||||
if (gained) {
|
||||
cb_ret = VPI_POLKIT_RESULT_SUCCESS;
|
||||
g_task_return_boolean(pk_task, gained);
|
||||
g_object_unref(pk_task);
|
||||
pk_task = 0;
|
||||
} else if (pk_attempts < 3) {
|
||||
cb_ret = VPI_POLKIT_RESULT_RETRY;
|
||||
try_again();
|
||||
} else {
|
||||
cb_ret = VPI_POLKIT_RESULT_FAIL;
|
||||
g_task_return_error(pk_task, g_error_new_literal(G_IO_ERROR, G_IO_ERROR_FAILED, "Maximum retries exceeded"));
|
||||
// g_task_return_boolean(pk_task, gained);
|
||||
g_object_unref(pk_task);
|
||||
pk_task = 0;
|
||||
}
|
||||
pk_pw_callback(cb_ret, pk_pw_callback_userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void try_again()
|
||||
{
|
||||
pk_ignore_complete = 0;
|
||||
|
||||
g_main_context_push_thread_default(gmainctx);
|
||||
|
||||
PolkitAgentSession *session = polkit_agent_session_new(pk_identity, pk_cookie);
|
||||
g_signal_connect(session, "request", G_CALLBACK(on_request), NULL);
|
||||
g_signal_connect(session, "show-info", G_CALLBACK(on_show_info), NULL);
|
||||
g_signal_connect(session, "show-error", G_CALLBACK(on_show_error), NULL);
|
||||
|
||||
// When session completes, call the async callback with success/failure.
|
||||
g_signal_connect(session, "completed", G_CALLBACK(on_complete), NULL);
|
||||
|
||||
// Start PAM conversation
|
||||
polkit_agent_session_initiate(session);
|
||||
|
||||
vpilog("Polkit session initiated\n");
|
||||
|
||||
g_main_context_pop_thread_default(gmainctx);
|
||||
}
|
||||
|
||||
static void vanilla_polkit_initiate_authentication(PolkitAgentListener *listener,
|
||||
const gchar *action_id,
|
||||
const gchar *message,
|
||||
const gchar *icon_name,
|
||||
PolkitDetails *details,
|
||||
const gchar *cookie,
|
||||
GList *identities,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_main_context_push_thread_default(gmainctx);
|
||||
|
||||
pk_identity = identities->data;
|
||||
g_object_ref(pk_identity);
|
||||
|
||||
pk_task = g_task_new(listener, cancellable, callback, user_data);
|
||||
|
||||
strncpy(pk_cookie, cookie, sizeof(pk_cookie));
|
||||
|
||||
try_again();
|
||||
|
||||
g_main_context_pop_thread_default(gmainctx);
|
||||
}
|
||||
|
||||
static gboolean vanilla_polkit_initiate_authentication_finish(PolkitAgentListener *listener,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean(G_TASK(res), error);
|
||||
}
|
||||
|
||||
static void vanilla_polkit_listener_finalize(GObject *object)
|
||||
{
|
||||
g_return_if_fail(object != NULL);
|
||||
g_return_if_fail(G_TYPE_CHECK_INSTANCE_TYPE((object), vanilla_polkit_listener_get_type()));
|
||||
G_OBJECT_CLASS(vanilla_polkit_listener_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void vanilla_polkit_listener_class_init(VanillaPolkitListenerClass *self)
|
||||
{
|
||||
GObjectClass *g_object_class = G_OBJECT_CLASS(self);
|
||||
g_object_class->finalize = vanilla_polkit_listener_finalize;
|
||||
|
||||
PolkitAgentListenerClass *lklass = POLKIT_AGENT_LISTENER_CLASS(self);
|
||||
lklass->initiate_authentication = vanilla_polkit_initiate_authentication;
|
||||
lklass->initiate_authentication_finish = vanilla_polkit_initiate_authentication_finish;
|
||||
}
|
||||
|
||||
static void vanilla_polkit_listener_init(VanillaPolkitListener *self)
|
||||
{
|
||||
}
|
||||
|
||||
void *vpi_pipe_log_thread(void *data)
|
||||
{
|
||||
char buf[512];
|
||||
@@ -69,6 +226,105 @@ void sigint_handler(int signal)
|
||||
raise(signal);
|
||||
}
|
||||
|
||||
void vpi_close_polkit_session()
|
||||
{
|
||||
if (polkit_handle) {
|
||||
pk_ignore_complete = 1;
|
||||
if (pk_session) {
|
||||
polkit_agent_session_cancel(pk_session);
|
||||
pk_session = 0;
|
||||
}
|
||||
|
||||
if (pk_task) {
|
||||
g_task_return_boolean(pk_task, 0);
|
||||
g_object_unref(pk_task);
|
||||
pk_task = 0;
|
||||
}
|
||||
|
||||
vpilog("Unregistering Polkit listener\n");
|
||||
polkit_agent_listener_unregister(polkit_handle);
|
||||
polkit_handle = 0;
|
||||
|
||||
g_object_unref(listener);
|
||||
listener = 0;
|
||||
|
||||
g_main_context_unref(gmainctx);
|
||||
gmainctx = 0;
|
||||
|
||||
if (pk_identity) {
|
||||
g_object_unref(pk_identity);
|
||||
pk_identity = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vpi_cancel_pw()
|
||||
{
|
||||
// Close existing pkexec process
|
||||
if (potential_pipe_pid != -1) {
|
||||
kill(potential_pipe_pid, SIGTERM);
|
||||
potential_pipe_pid = -1;
|
||||
close(in_pipes[1]);
|
||||
close(err_pipes[0]);
|
||||
|
||||
close(err_pipes[1]);
|
||||
close(in_pipes[0]);
|
||||
}
|
||||
vpi_close_polkit_session();
|
||||
}
|
||||
|
||||
void vpi_submit_pw(const char *s, vpi_pw_callback callback, void *userdata)
|
||||
{
|
||||
pk_pw_callback = callback;
|
||||
pk_pw_callback_userdata = userdata;
|
||||
polkit_agent_session_response(pk_session, s);
|
||||
}
|
||||
|
||||
int vpi_start_epilog()
|
||||
{
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
|
||||
char ready_buf[500];
|
||||
memset(ready_buf, 0, sizeof(ready_buf));
|
||||
size_t read_count = 0;
|
||||
while (read_count < sizeof(ready_buf)) {
|
||||
ssize_t this_read = read(err_pipes[0], ready_buf + read_count, sizeof(ready_buf));
|
||||
if (this_read > 0) {
|
||||
read_count += this_read;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this_read <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!memcmp(ready_buf, "READY", 5)) {
|
||||
ret = VANILLA_SUCCESS;
|
||||
|
||||
pipe_input = in_pipes[1];
|
||||
pipe_err = err_pipes[0];
|
||||
|
||||
pthread_create(&pipe_log_thread, 0, vpi_pipe_log_thread, (void *) (intptr_t) pipe_err);
|
||||
|
||||
pipe_pid = potential_pipe_pid;
|
||||
} else {
|
||||
vpilog("GOT INVALID SIGNAL: %.*s\n", sizeof(ready_buf), ready_buf);
|
||||
|
||||
// Kill seems to break a lot of things so I guess we'll just leave it orphaned
|
||||
// kill(pipe_pid, SIGKILL);
|
||||
pipe_pid = -1;
|
||||
close(in_pipes[1]);
|
||||
close(err_pipes[0]);
|
||||
}
|
||||
|
||||
close(err_pipes[1]);
|
||||
close(in_pipes[0]);
|
||||
|
||||
vpi_close_polkit_session();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vpi_start_pipe()
|
||||
{
|
||||
if (pipe_pid != -1) {
|
||||
@@ -76,8 +332,51 @@ int vpi_start_pipe()
|
||||
return VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
{
|
||||
PolkitAuthority *auth = polkit_authority_get_sync(NULL, NULL);
|
||||
PolkitSubject *sub = polkit_unix_process_new_for_owner(getpid(), 0, -1);
|
||||
PolkitAuthorizationResult *res =
|
||||
polkit_authority_check_authorization_sync(
|
||||
auth, sub, "com.mattkc.vanilla", NULL,
|
||||
POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, NULL, NULL);
|
||||
|
||||
gboolean ok = res && polkit_authorization_result_get_is_authorized(res);
|
||||
|
||||
if (res) g_object_unref(res);
|
||||
g_object_unref(sub);
|
||||
g_object_unref(auth);
|
||||
|
||||
// gboolean ok = polkit_authorization_result_get_is_authorized(res);
|
||||
// gboolean chall = polkit_authorization_result_get_is_challenge(res);
|
||||
if (!ok) {
|
||||
g_autoptr(PolkitSubject) subject = polkit_unix_session_new_for_process_sync(getpid(), NULL, NULL);
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
pk_session = 0;
|
||||
pk_attempts = 0;
|
||||
|
||||
gmainctx = g_main_context_new();
|
||||
g_main_context_push_thread_default(gmainctx);
|
||||
|
||||
listener = g_object_new(vanilla_polkit_listener_get_type(), NULL);
|
||||
vpilog("Registered Polkit listener\n");
|
||||
polkit_handle = polkit_agent_listener_register(
|
||||
POLKIT_AGENT_LISTENER(listener),
|
||||
POLKIT_AGENT_REGISTER_FLAGS_NONE,
|
||||
subject,
|
||||
NULL, NULL, &error
|
||||
);
|
||||
g_main_context_pop_thread_default(gmainctx);
|
||||
if (!polkit_handle) {
|
||||
g_main_context_unref(gmainctx);
|
||||
gmainctx = 0;
|
||||
|
||||
vpilog("Failed to register Polkit listener: %s\n", error->message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up pipes so child stdout can be read by the parent process
|
||||
int err_pipes[2], in_pipes[2];
|
||||
pipe(in_pipes);
|
||||
pipe(err_pipes);
|
||||
|
||||
@@ -121,6 +420,7 @@ int vpi_start_pipe()
|
||||
strcat(exe, "/vanilla-pipe");
|
||||
|
||||
r = execlp(pkexec, pkexec, exe, "-local", vpi_config.wireless_interface, (const char *) 0);
|
||||
// r = execlp(pkexec, pkexec, "/usr/bin/gparted", (const char *) 0);
|
||||
|
||||
// Handle failure to execute, use _exit so we don't interfere with the host
|
||||
_exit(1);
|
||||
@@ -138,44 +438,35 @@ int vpi_start_pipe()
|
||||
sigaction(SIGINT, &sa, &old_sigint_action);
|
||||
sigaction(SIGTERM, &sa, &old_sigterm_action);
|
||||
|
||||
char ready_buf[500];
|
||||
memset(ready_buf, 0, sizeof(ready_buf));
|
||||
size_t read_count = 0;
|
||||
while (read_count < sizeof(ready_buf)) {
|
||||
ssize_t this_read = read(err_pipes[0], ready_buf + read_count, sizeof(ready_buf));
|
||||
if (this_read > 0) {
|
||||
read_count += this_read;
|
||||
break;
|
||||
}
|
||||
potential_pipe_pid = pid;
|
||||
|
||||
if (this_read <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!memcmp(ready_buf, "READY", 5)) {
|
||||
ret = VANILLA_SUCCESS;
|
||||
pipe_pid = pid;
|
||||
if (polkit_handle) {
|
||||
// We'll need to handle this...
|
||||
ret = VANILLA_REQUIRES_PASSWORD_HANDLING;
|
||||
|
||||
pipe_input = in_pipes[1];
|
||||
pipe_err = err_pipes[0];
|
||||
|
||||
pthread_create(&pipe_log_thread, 0, vpi_pipe_log_thread, (void *) (intptr_t) pipe_err);
|
||||
} else {
|
||||
vpilog("GOT INVALID SIGNAL: %.*s\n", sizeof(ready_buf), ready_buf);
|
||||
|
||||
// Kill seems to break a lot of things so I guess we'll just leave it orphaned
|
||||
// kill(pipe_pid, SIGKILL);
|
||||
close(in_pipes[1]);
|
||||
close(err_pipes[0]);
|
||||
}
|
||||
|
||||
close(err_pipes[1]);
|
||||
close(in_pipes[0]);
|
||||
// Keep handling synchronous by waiting for polkit to send us a
|
||||
// "request" signal before returning to the password prompt
|
||||
while (!pk_session) {
|
||||
g_main_context_iteration(gmainctx, 1);
|
||||
}
|
||||
} else {
|
||||
// Polkit will be handled for us, wait for it to finish
|
||||
ret = vpi_start_epilog();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void vpi_update_pipe()
|
||||
{
|
||||
if (gmainctx) {
|
||||
while (g_main_context_pending(gmainctx)) {
|
||||
g_main_context_iteration(gmainctx, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vpi_stop_pipe()
|
||||
{
|
||||
if (pipe_pid != -1) {
|
||||
@@ -196,6 +487,7 @@ void vpi_stop_pipe()
|
||||
sigaction(SIGINT, &old_sigint_action, NULL);
|
||||
sigaction(SIGTERM, &old_sigterm_action, NULL);
|
||||
}
|
||||
vpi_close_polkit_session();
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -205,4 +497,9 @@ void vpi_stop_pipe()
|
||||
{
|
||||
}
|
||||
|
||||
// Empty function
|
||||
void vpi_update_pipe()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
+14
-1
@@ -1,9 +1,22 @@
|
||||
#ifndef VANILLA_PI_PIPE_MGMT_H
|
||||
#define VANILLA_PI_PIPE_MGMT_H
|
||||
|
||||
#define VANILLA_REQUIRES_PASSWORD_HANDLING -1000
|
||||
#define VANILLA_PASSWORD_FAILED -1001
|
||||
|
||||
#ifdef VANILLA_PIPE_AVAILABLE
|
||||
int vpi_start_pipe();
|
||||
int vpi_start_epilog();
|
||||
void vpi_cancel_pw();
|
||||
|
||||
#define VPI_POLKIT_RESULT_SUCCESS 0
|
||||
#define VPI_POLKIT_RESULT_RETRY 1
|
||||
#define VPI_POLKIT_RESULT_FAIL 2
|
||||
|
||||
typedef void (*vpi_pw_callback)(int result, void *userdata);
|
||||
void vpi_submit_pw(const char *s, vpi_pw_callback callback, void *userdata);
|
||||
#endif
|
||||
void vpi_stop_pipe();
|
||||
void vpi_update_pipe();
|
||||
|
||||
#endif // VANILLA_PI_PIPE_MGMT_H
|
||||
#endif // VANILLA_PI_PIPE_MGMT_H
|
||||
+11
-3
@@ -52,6 +52,7 @@ void vui_reset(vui_context_t *ctx)
|
||||
ctx->button_active = -1;
|
||||
ctx->layers = 1;
|
||||
ctx->layer_opacity[0] = 1;
|
||||
ctx->layer_enabled[0] = 1;
|
||||
ctx->selected_button = -1;
|
||||
ctx->cancel_button = -1;
|
||||
ctx->active_textedit = -1;
|
||||
@@ -365,7 +366,7 @@ void vui_process_mousedown(vui_context_t *ctx, int x, int y)
|
||||
for (int i = 0; i < ctx->button_count; i++) {
|
||||
vui_button_t *btn = &ctx->buttons[i];
|
||||
|
||||
if (btn->visible && btn->enabled && point_inside_button(btn, x, y)) {
|
||||
if (btn->visible && btn->enabled && point_inside_button(btn, x, y) && ctx->layer_enabled[btn->layer]) {
|
||||
press_button(ctx, i);
|
||||
button_pressed = 1;
|
||||
break;
|
||||
@@ -377,7 +378,7 @@ void vui_process_mousedown(vui_context_t *ctx, int x, int y)
|
||||
for (int i = 0; i < ctx->textedit_count; i++) {
|
||||
vui_textedit_t *edit = &ctx->textedits[i];
|
||||
|
||||
if (edit->visible && edit->enabled && point_inside_textedit(edit, x, y)) {
|
||||
if (edit->visible && edit->enabled && point_inside_textedit(edit, x, y) && ctx->layer_enabled[edit->layer]) {
|
||||
new_active_textedit = i;
|
||||
break;
|
||||
}
|
||||
@@ -545,6 +546,7 @@ int vui_layer_create(vui_context_t *ctx)
|
||||
|
||||
// Set layer defaults
|
||||
ctx->layer_opacity[cur_layer] = 1.0f;
|
||||
ctx->layer_enabled[cur_layer] = 1;
|
||||
|
||||
vui_color_t *layerbg = &ctx->layer_color[cur_layer];
|
||||
layerbg->r = 0;
|
||||
@@ -572,6 +574,11 @@ void vui_layer_set_opacity(vui_context_t *ctx, int layer, float opacity)
|
||||
ctx->layer_opacity[layer] = opacity;
|
||||
}
|
||||
|
||||
void vui_layer_set_enabled(vui_context_t *ctx, int layer, int enabled)
|
||||
{
|
||||
ctx->layer_enabled[layer] = enabled;
|
||||
}
|
||||
|
||||
vui_color_t vui_color_create(float r, float g, float b, float a)
|
||||
{
|
||||
vui_color_t c;
|
||||
@@ -626,7 +633,7 @@ void vui_label_update_visible(vui_context_t *ctx, int index, int visible)
|
||||
lbl->visible = visible;
|
||||
}
|
||||
|
||||
int vui_textedit_create(vui_context_t *ctx, int x, int y, int w, int h, const char *initial_text, vui_font_size_t size, int layer)
|
||||
int vui_textedit_create(vui_context_t *ctx, int x, int y, int w, int h, const char *initial_text, vui_font_size_t size, int password, int layer)
|
||||
{
|
||||
if (ctx->textedit_count == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
@@ -640,6 +647,7 @@ int vui_textedit_create(vui_context_t *ctx, int x, int y, int w, int h, const ch
|
||||
edit->y = y;
|
||||
edit->w = w;
|
||||
edit->h = h;
|
||||
edit->password = password;
|
||||
|
||||
edit->layer = layer;
|
||||
edit->size = size;
|
||||
|
||||
+2
-1
@@ -84,6 +84,7 @@ void vui_set_background(vui_context_t *ctx, const char *background_image);
|
||||
*/
|
||||
int vui_layer_create(vui_context_t *ctx);
|
||||
void vui_layer_set_opacity(vui_context_t *ctx, int layer, float opacity);
|
||||
void vui_layer_set_enabled(vui_context_t *ctx, int layer, int enabled);
|
||||
void vui_layer_set_bgcolor(vui_context_t *ctx, int layer, vui_color_t color);
|
||||
int vui_layer_destroy(vui_context_t *ctx);
|
||||
|
||||
@@ -114,7 +115,7 @@ void vui_label_update_visible(vui_context_t *ctx, int label, int visible);
|
||||
/**
|
||||
* TextEdit-related functions
|
||||
*/
|
||||
int vui_textedit_create(vui_context_t *ctx, int x, int y, int w, int h, const char *initial_text, vui_font_size_t size, int layer);
|
||||
int vui_textedit_create(vui_context_t *ctx, int x, int y, int w, int h, const char *initial_text, vui_font_size_t size, int password, int layer);
|
||||
void vui_textedit_get_text(vui_context_t *ctx, int textedit, char *output, size_t output_size);
|
||||
void vui_textedit_update_text(vui_context_t *ctx, int textedit, const char *text);
|
||||
void vui_textedit_update_visible(vui_context_t *ctx, int textedit, int visible);
|
||||
|
||||
+3
-1
@@ -6,7 +6,7 @@
|
||||
#include "ui.h"
|
||||
|
||||
#define MAX_BUTTON_COUNT 16
|
||||
#define MAX_BUTTON_TEXT 256
|
||||
#define MAX_BUTTON_TEXT 512
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
@@ -52,6 +52,7 @@ typedef struct {
|
||||
int visible;
|
||||
int enabled;
|
||||
int cursor;
|
||||
int password;
|
||||
} vui_textedit_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -121,6 +122,7 @@ typedef struct vui_context_t {
|
||||
int screen_height;
|
||||
int layers;
|
||||
float layer_opacity[MAX_BUTTON_COUNT];
|
||||
int layer_enabled[MAX_BUTTON_COUNT];
|
||||
vui_color_t layer_color[MAX_BUTTON_COUNT];
|
||||
char background_image[MAX_BUTTON_TEXT];
|
||||
int background_enabled;
|
||||
|
||||
+75
-26
@@ -25,6 +25,8 @@
|
||||
#include "ui_util.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define PW_CHAR_SIZE 20
|
||||
#define PW_CHAR_PAD 2
|
||||
|
||||
typedef struct {
|
||||
SDL_Texture *texture;
|
||||
@@ -56,6 +58,7 @@ typedef struct {
|
||||
SDL_Texture *toast_tex;
|
||||
struct timeval toast_expiry;
|
||||
AVFrame *frame;
|
||||
SDL_Texture *pw_tex;
|
||||
|
||||
uint8_t *audio_buffer;
|
||||
size_t audio_buffer_size;
|
||||
@@ -422,6 +425,7 @@ int vui_init_sdl(vui_context_t *ctx, int fullscreen)
|
||||
sdl_ctx->background = 0;
|
||||
sdl_ctx->last_shown_toast = 0;
|
||||
sdl_ctx->toast_tex = 0;
|
||||
sdl_ctx->pw_tex = 0;
|
||||
memset(sdl_ctx->layer_data, 0, sizeof(sdl_ctx->layer_data));
|
||||
memset(sdl_ctx->label_data, 0, sizeof(sdl_ctx->label_data));
|
||||
memset(sdl_ctx->button_cache, 0, sizeof(sdl_ctx->button_cache));
|
||||
@@ -461,6 +465,11 @@ void vui_close_sdl(vui_context_t *ctx)
|
||||
SDL_CloseAudioDevice(sdl_ctx->mic);
|
||||
}
|
||||
|
||||
if (sdl_ctx->pw_tex) {
|
||||
SDL_DestroyTexture(sdl_ctx->pw_tex);
|
||||
sdl_ctx->pw_tex = 0;
|
||||
}
|
||||
|
||||
SDL_DestroyTexture(sdl_ctx->toast_tex);
|
||||
if (sdl_ctx->game_tex) SDL_DestroyTexture(sdl_ctx->game_tex);
|
||||
SDL_DestroyTexture(sdl_ctx->background);
|
||||
@@ -902,24 +911,51 @@ void vui_draw_sdl(vui_context_t *ctx, SDL_Renderer *renderer)
|
||||
TTF_Font *font = get_font(sdl_ctx, edit->size);
|
||||
|
||||
if (edit->text[0]) {
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, edit->text, c);
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_ctx->renderer, surface);
|
||||
|
||||
SDL_Rect src;
|
||||
src.x = src.y = 0;
|
||||
src.w = surface->w;
|
||||
src.h = surface->h;
|
||||
if (edit->password) {
|
||||
if (!sdl_ctx->pw_tex) {
|
||||
sdl_ctx->pw_tex = vui_sdl_load_texture(sdl_ctx->renderer, "circle_big.svg");
|
||||
}
|
||||
|
||||
if (src.w > rect.w) {
|
||||
src.w = rect.w;
|
||||
} else {
|
||||
rect.w = src.w;
|
||||
}
|
||||
uint8_t f = (edit->enabled ? 1 : 0.5f) * 0xFF;
|
||||
SDL_SetTextureAlphaMod(sdl_ctx->pw_tex, f);
|
||||
SDL_SetTextureColorMod(sdl_ctx->pw_tex, f, f, f);
|
||||
|
||||
SDL_RenderCopy(renderer, texture, &src, &rect);
|
||||
const char *cc = edit->text;
|
||||
SDL_Rect pwr;
|
||||
pwr.x = rect.x;
|
||||
pwr.y = rect.y + rect.h/2 - PW_CHAR_SIZE/2;
|
||||
pwr.w = PW_CHAR_SIZE;
|
||||
pwr.h = PW_CHAR_SIZE;
|
||||
while (*cc != 0) {
|
||||
SDL_RenderCopy(renderer, sdl_ctx->pw_tex, 0, &pwr);
|
||||
cc++;
|
||||
pwr.x += PW_CHAR_SIZE + PW_CHAR_PAD;
|
||||
}
|
||||
} else {
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, edit->text, c);
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl_ctx->renderer, surface);
|
||||
SDL_Rect src;
|
||||
src.x = src.y = 0;
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_DestroyTexture(texture);
|
||||
src.w = surface->w;
|
||||
src.h = surface->h;
|
||||
|
||||
if (src.w > rect.w) {
|
||||
src.w = rect.w;
|
||||
} else {
|
||||
rect.w = src.w;
|
||||
}
|
||||
|
||||
uint8_t f = (edit->enabled ? 1 : 0.5f) * 0xFF;
|
||||
SDL_SetTextureAlphaMod(texture, f);
|
||||
SDL_SetTextureColorMod(texture, f, f, f);
|
||||
|
||||
SDL_RenderCopy(renderer, texture, &src, &rect);
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->active_textedit == i) {
|
||||
@@ -927,23 +963,27 @@ void vui_draw_sdl(vui_context_t *ctx, SDL_Renderer *renderer)
|
||||
gettimeofday(&now, 0);
|
||||
time_t diff = (now.tv_sec - ctx->active_textedit_time.tv_sec) * 1000000 + (now.tv_usec - ctx->active_textedit_time.tv_usec);
|
||||
if ((diff % 1000000) < 500000) {
|
||||
char tmp_ate[MAX_BUTTON_TEXT];
|
||||
|
||||
char *copy_end = edit->text;
|
||||
for (int i = 0; i < edit->cursor; i++) {
|
||||
copy_end = vui_utf8_advance(copy_end);
|
||||
}
|
||||
|
||||
size_t len = copy_end - edit->text;
|
||||
strncpy(tmp_ate, edit->text, len);
|
||||
tmp_ate[len] = 0;
|
||||
|
||||
int tw;
|
||||
TTF_SizeUTF8(font, tmp_ate, &tw, 0);
|
||||
int cursor_x = rect.x + tw;
|
||||
int cursor_x;
|
||||
if (edit->password) {
|
||||
cursor_x = rect.x + (PW_CHAR_SIZE + PW_CHAR_PAD) * len - PW_CHAR_PAD/2;
|
||||
} else {
|
||||
char tmp_ate[MAX_BUTTON_TEXT];
|
||||
strncpy(tmp_ate, edit->text, len);
|
||||
tmp_ate[len] = 0;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a);
|
||||
SDL_RenderDrawLine(renderer, cursor_x, rect.y, cursor_x, rect.y + rect.h);
|
||||
int tw;
|
||||
TTF_SizeUTF8(font, tmp_ate, &tw, 0);
|
||||
cursor_x = rect.x + tw;
|
||||
}
|
||||
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a);
|
||||
SDL_RenderDrawLine(renderer, cursor_x, rect.y, cursor_x, rect.y + rect.h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1442,9 +1482,18 @@ int vui_update_sdl(vui_context_t *vui)
|
||||
vui_draw_sdl(vui, renderer);
|
||||
|
||||
// Flatten layers
|
||||
for (int i = vui->layers - 1; i > 0; i--) {
|
||||
SDL_Texture *bg = sdl_ctx->layer_data[i-1];
|
||||
SDL_Texture *fg = sdl_ctx->layer_data[i];
|
||||
int el[MAX_BUTTON_COUNT];
|
||||
int el_count = 0;
|
||||
for (int i = 0; i < vui->layers; i++) {
|
||||
if (vui->layer_enabled[i]) {
|
||||
el[el_count] = i;
|
||||
el_count++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = el_count - 1; i > 0; i--) {
|
||||
SDL_Texture *bg = sdl_ctx->layer_data[el[i-1]];
|
||||
SDL_Texture *fg = sdl_ctx->layer_data[el[i]];
|
||||
|
||||
SDL_SetRenderTarget(renderer, bg);
|
||||
SDL_SetTextureColorMod(fg, vui->layer_opacity[i] * 0xFF, vui->layer_opacity[i] * 0xFF, vui->layer_opacity[i] * 0xFF);
|
||||
|
||||
@@ -279,6 +279,35 @@ exit_pipe:
|
||||
close(skt);
|
||||
}
|
||||
|
||||
int install_polkit_internal(thread_data_t *data, int install)
|
||||
{
|
||||
clear_interrupt();
|
||||
|
||||
SERVER_ADDRESS = data->server_address;
|
||||
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
|
||||
int pipe_cc_skt = -1;
|
||||
if (SERVER_ADDRESS != VANILLA_ADDRESS_DIRECT) {
|
||||
vanilla_pipe_command_t cmd;
|
||||
cmd.control_code = install ? VANILLA_PIPE_CC_INSTALL_POLKIT : VANILLA_PIPE_CC_UNINSTALL_POLKIT;
|
||||
|
||||
// Connect to backend pipe
|
||||
ret = connect_to_backend(&pipe_cc_skt, &cmd, sizeof(cmd.control_code) + sizeof(cmd.connection));
|
||||
|
||||
// No interrupt is required here because VANILLA_PIPE_CC_INSTALL_POLKIT
|
||||
// does not start a thread in the pipe
|
||||
}
|
||||
|
||||
if (pipe_cc_skt != -1) {
|
||||
// Disconnect from pipe if necessary
|
||||
send_unbind_cc(pipe_cc_skt);
|
||||
close(pipe_cc_skt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void connect_as_gamepad_internal(thread_data_t *data)
|
||||
{
|
||||
clear_interrupt();
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef struct thread_data_t
|
||||
|
||||
void sync_internal(thread_data_t *data);
|
||||
void connect_as_gamepad_internal(thread_data_t *data);
|
||||
int install_polkit_internal(thread_data_t *data, int install);
|
||||
void send_to_console(int fd, const void *data, size_t data_size, uint16_t port);
|
||||
int push_event(event_loop_t *loop, int type, const void *data, size_t size);
|
||||
int get_event(event_loop_t *loop, vanilla_event_t *event, int wait);
|
||||
@@ -54,4 +55,4 @@ void free_event_buffer_arena();
|
||||
void *get_event_buffer();
|
||||
void release_event_buffer(void *buffer);
|
||||
|
||||
#endif // VANILLA_GAMEPAD_H
|
||||
#endif // VANILLA_GAMEPAD_H
|
||||
@@ -203,6 +203,20 @@ int vanilla_sync(uint16_t code, uint32_t server_address)
|
||||
return vanilla_start_internal(server_address, (vanilla_bssid_t){.bssid = {0}}, (vanilla_psk_t){.psk = {0}}, sync_internal, (void *) (uintptr_t) code);
|
||||
}
|
||||
|
||||
int vanilla_install_polkit(uint32_t server_address)
|
||||
{
|
||||
thread_data_t data;
|
||||
data.server_address = server_address;
|
||||
return install_polkit_internal(&data, 1);
|
||||
}
|
||||
|
||||
int vanilla_uninstall_polkit(uint32_t server_address)
|
||||
{
|
||||
thread_data_t data;
|
||||
data.server_address = server_address;
|
||||
return install_polkit_internal(&data, 0);
|
||||
}
|
||||
|
||||
int vanilla_poll_event(vanilla_event_t *event)
|
||||
{
|
||||
return get_event(&event_loop, event, 0);
|
||||
|
||||
@@ -125,6 +125,9 @@ typedef struct {
|
||||
int vanilla_start(uint32_t server_address, vanilla_bssid_t bssid, vanilla_psk_t psk);
|
||||
int vanilla_sync(uint16_t code, uint32_t server_address);
|
||||
|
||||
int vanilla_install_polkit(uint32_t server_address);
|
||||
int vanilla_uninstall_polkit(uint32_t server_address);
|
||||
|
||||
int vanilla_poll_event(vanilla_event_t *event);
|
||||
int vanilla_wait_event(vanilla_event_t *event);
|
||||
int vanilla_free_event(vanilla_event_t *event);
|
||||
|
||||
+6
-1
@@ -16,10 +16,15 @@
|
||||
#define VANILLA_PIPE_CC_SYNC_SUCCESS 0x87
|
||||
#define VANILLA_PIPE_CC_CONNECTED 0x88
|
||||
#define VANILLA_PIPE_CC_DISCONNECTED 0x89
|
||||
#define VANILLA_PIPE_CC_INSTALL_POLKIT 0x8A
|
||||
#define VANILLA_PIPE_CC_UNINSTALL_POLKIT 0x8B
|
||||
#define VANILLA_PIPE_CC_QUIT 0x90
|
||||
|
||||
#define VANILLA_PIPE_LOCAL_SOCKET "/tmp/vanilla-pipe_%i.sock"
|
||||
|
||||
#define POLKIT_ACTION_DST "/usr/share/polkit-1/actions/com.mattkc.vanilla.policy"
|
||||
#define POLKIT_RULE_DST "/usr/share/polkit-1/rules.d/com.mattkc.vanilla.rules"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint16_t code;
|
||||
@@ -39,4 +44,4 @@ typedef struct {
|
||||
} vanilla_pipe_command_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // VANILLA_PIPE_DEF_H
|
||||
#endif // VANILLA_PIPE_DEF_H
|
||||
@@ -227,18 +227,3 @@ target_link_libraries(vanilla-pipe PRIVATE
|
||||
${OPENSSL_LIBRARIES}
|
||||
wpa_supplicant_drc
|
||||
)
|
||||
|
||||
# Handle polkit files
|
||||
if (VANILLA_INSTALL_POLKIT_RULE)
|
||||
set(PIPE_BIN "${CMAKE_INSTALL_PREFIX}/bin/vanilla-pipe")
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/polkit/com.mattkc.vanilla.policy.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/polkit/com.mattkc.vanilla.policy"
|
||||
@ONLY
|
||||
)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/polkit/com.mattkc.vanilla.policy" DESTINATION share/polkit-1/actions)
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/polkit/com.mattkc.vanilla.rules" DESTINATION share/polkit-1/rules.d)
|
||||
else()
|
||||
# Install script that can do it later
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/polkit/vanilla-polkit-install.sh" DESTINATION bin)
|
||||
endif()
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
<vendor>MattKC</vendor>
|
||||
<vendor_url>https://mattkc.com</vendor_url>
|
||||
<action id="com.mattkc.vanilla">
|
||||
<description>Run Vanilla Pipe as root</description>
|
||||
<message>Authentication is required to run Vanilla Pipe as root</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@PIPE_BIN@</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
|
||||
</action>
|
||||
</policyconfig>
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Allow all users to run vanilla-pipe as root without having to enter a password
|
||||
*
|
||||
* This provides convenience, especially on platforms more suited for touch
|
||||
* controls, however it could be dangerous to allow a program unrestricted
|
||||
* administrator access, so it should be used with caution.
|
||||
*/
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "com.mattkc.vanilla") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then
|
||||
echo "$0 must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
echo "vanilla-pipe Polkit Install Script"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
echo "This script will install a Polkit action and rule that will allow vanilla-pipe"
|
||||
echo "to run as root without entering a password."
|
||||
echo ""
|
||||
echo "This makes usage of Vanilla much more convenient, especially on touch-based"
|
||||
echo "devices such as the Nintendo Switch and Steam Deck, however THERE ARE INHERENT"
|
||||
echo "RISKS TO ALLOWING A PROGRAM TO RUN AS ROOT WITHOUT USER INTERVENTION. WE MAKE"
|
||||
echo "NO SAFETY GUARANTEES IF YOU CHOOSE TO CONTINUE WITH THIS PROCESS."
|
||||
echo ""
|
||||
read -p "If you understand the risks and wish to continue, type \"I agree\": " agree
|
||||
|
||||
if [ "${agree,,}" != "i agree" ]
|
||||
then
|
||||
echo "Exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Continuing..."
|
||||
|
||||
while [ 1 ]
|
||||
do
|
||||
read -p "Enter the absolute path of vanilla-pipe (e.g. /usr/bin/vanilla-pipe): " path
|
||||
|
||||
if [ -z "${path}" ]
|
||||
then
|
||||
read -p "Do you wish to exit? [yn] " exit_confirm
|
||||
if [ "${exit_confirm,,}" = "y" ]
|
||||
then
|
||||
exit 1
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "${path}" ]
|
||||
then
|
||||
echo "File \"${path}\" does not exist"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ${path:0:1} != "/" ]
|
||||
then
|
||||
echo "Path \"${path}\" does not appear to be an absolute path"
|
||||
continue
|
||||
fi
|
||||
|
||||
read -p "vanilla-pipe will be located at \"$path\", is that correct? [yn] " confirm
|
||||
if [ "${confirm,,}" = "y" ]
|
||||
then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
POLKIT_ACTION_DST="/usr/share/polkit-1/actions/com.mattkc.vanilla.policy"
|
||||
POLKIT_RULE_DST="/usr/share/polkit-1/rules.d/com.mattkc.vanilla.rules"
|
||||
echo ""
|
||||
|
||||
POLICY_TEMPLATE='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
<vendor>MattKC</vendor>
|
||||
<vendor_url>https://mattkc.com</vendor_url>
|
||||
<action id="com.mattkc.vanilla">
|
||||
<description>Run Vanilla Pipe as root</description>
|
||||
<message>Authentication is required to run Vanilla Pipe as root</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@PIPE_BIN@</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
|
||||
</action>
|
||||
</policyconfig>'
|
||||
|
||||
RULES_TEMPLATE='/**
|
||||
* Allow all users to run vanilla-pipe as root without having to enter a password
|
||||
*
|
||||
* This provides convenience, especially on platforms more suited for touch
|
||||
* controls, however it could be dangerous to allow a program unrestricted
|
||||
* administrator access, so it should be used with caution.
|
||||
*/
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "com.mattkc.vanilla") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});'
|
||||
|
||||
echo "Installing Polkit action to ${POLKIT_ACTION_DST}"
|
||||
echo "$POLICY_TEMPLATE" | sed "s|@PIPE_BIN@|${path}|g" > "${POLKIT_ACTION_DST}"
|
||||
|
||||
echo "Installing Polkit rule to ${POLKIT_RULE_DST}"
|
||||
echo "$RULES_TEMPLATE" > "${POLKIT_RULE_DST}"
|
||||
|
||||
echo ""
|
||||
echo "Installation done. If you wish to undo this, simply remove the two files"
|
||||
echo "listed above."
|
||||
@@ -1087,6 +1087,71 @@ void *vanilla_connect_to_console(void *data)
|
||||
return wpa_setup_environment(args);
|
||||
}
|
||||
|
||||
int uninstall_polkit()
|
||||
{
|
||||
unlink(POLKIT_ACTION_DST);
|
||||
unlink(POLKIT_RULE_DST);
|
||||
}
|
||||
|
||||
int install_polkit()
|
||||
{
|
||||
static const char *ACTION_TEMPLATE =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<!DOCTYPE policyconfig PUBLIC \"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN\" \"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd\">\n"
|
||||
"<policyconfig>\n"
|
||||
" <vendor>MattKC</vendor>\n"
|
||||
" <vendor_url>https://mattkc.com</vendor_url>\n"
|
||||
" <action id=\"com.mattkc.vanilla\">\n"
|
||||
" <description>Run Vanilla Pipe as root</description>\n"
|
||||
" <message>Authentication is required to run Vanilla Pipe as root</message>\n"
|
||||
" <defaults>\n"
|
||||
" <allow_any>auth_admin</allow_any>\n"
|
||||
" <allow_inactive>auth_admin</allow_inactive>\n"
|
||||
" <allow_active>auth_admin</allow_active>\n"
|
||||
" </defaults>\n"
|
||||
" <annotate key=\"org.freedesktop.policykit.exec.path\">%s</annotate>\n"
|
||||
" <annotate key=\"org.freedesktop.policykit.exec.allow_gui\">true</annotate>\n"
|
||||
" </action>\n"
|
||||
"</policyconfig>\n";
|
||||
|
||||
static const char *RULE_TEMPLATE =
|
||||
"/**\n"
|
||||
" * Allow all users to run vanilla-pipe as root without having to enter a password\n"
|
||||
" *\n"
|
||||
" * This provides convenience, especially on platforms more suited for touch\n"
|
||||
" * controls, however it could be dangerous to allow a program unrestricted\n"
|
||||
" * administrator access, so it should be used with caution.\n"
|
||||
" */\n"
|
||||
"polkit.addRule(function(action, subject) {\n"
|
||||
" if (action.id == \"com.mattkc.vanilla\") {\n"
|
||||
" return polkit.Result.YES;\n"
|
||||
" }\n"
|
||||
"});\n";
|
||||
|
||||
// Get current filename
|
||||
char exe[4096];
|
||||
ssize_t link_len = readlink("/proc/self/exe", exe, sizeof(exe));
|
||||
exe[link_len] = 0;
|
||||
|
||||
// If on the Steam Deck, ensure the system partition is writeable
|
||||
run_process_and_read_stdout((const char *[]) {"steamos-readonly", "disable", NULL}, 0, 0);
|
||||
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
|
||||
FILE *action = fopen(POLKIT_ACTION_DST, "w");
|
||||
FILE *rule = fopen(POLKIT_RULE_DST, "w");
|
||||
if (action && rule) {
|
||||
fprintf(action, ACTION_TEMPLATE, exe);
|
||||
fprintf(rule, RULE_TEMPLATE);
|
||||
ret = VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
if (action) fclose(action);
|
||||
if (rule) fclose(rule);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pipe_listen(int local, const char *wireless_interface, const char *log_file)
|
||||
{
|
||||
// Store reference to log file
|
||||
@@ -1167,6 +1232,20 @@ void pipe_listen(int local, const char *wireless_interface, const char *log_file
|
||||
nlprint("FAILED TO SEND BUSY: %i", errno);
|
||||
}
|
||||
}
|
||||
} else if (cmd.control_code == VANILLA_PIPE_CC_INSTALL_POLKIT || cmd.control_code == VANILLA_PIPE_CC_UNINSTALL_POLKIT) {
|
||||
if (cmd.control_code == VANILLA_PIPE_CC_INSTALL_POLKIT) {
|
||||
// Write Polkit rule and action
|
||||
install_polkit();
|
||||
} else {
|
||||
// Delete Polkit rule and action
|
||||
uninstall_polkit();
|
||||
}
|
||||
|
||||
// Acknowledge
|
||||
cmd.control_code = VANILLA_PIPE_CC_BIND_ACK;
|
||||
if (sendto(skt, &cmd, sizeof(cmd.control_code), 0, (const struct sockaddr *) &addr, addr_size) == -1) {
|
||||
nlprint("FAILED TO SEND ACK: %i", errno);
|
||||
}
|
||||
} else if (cmd.control_code == VANILLA_PIPE_CC_UNBIND) {
|
||||
nlprint("RECEIVED UNBIND SIGNAL");
|
||||
interrupt();
|
||||
|
||||
Reference in new issue
Block a user