summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/config/default/e.src2
-rw-r--r--data/config/standard/e.src6
-rw-r--r--data/config/tiling/e.src7
-rw-r--r--meson_options.txt4
-rw-r--r--src/bin/e_auth.c57
-rw-r--r--src/bin/e_auth.h1
-rw-r--r--src/bin/e_ckpasswd_main.c207
-rw-r--r--src/bin/e_config.c27
-rw-r--r--src/bin/e_config.h2
-rw-r--r--src/bin/e_module.c1
-rw-r--r--src/bin/meson.build2
-rw-r--r--src/modules/meson.build1
-rw-r--r--src/modules/polkit/auth_ui.c149
-rw-r--r--src/modules/polkit/e-module-polkit.edjbin0 -> 7523 bytes
-rw-r--r--src/modules/polkit/e_mod_main.c17
-rw-r--r--src/modules/polkit/e_mod_main.h32
-rw-r--r--src/modules/polkit/meson.build6
-rw-r--r--src/modules/polkit/module.desktop6
-rw-r--r--src/modules/polkit/polkit.c523
19 files changed, 1019 insertions, 31 deletions
diff --git a/data/config/default/e.src b/data/config/default/e.src
index a2e0e3e2e4..a017effa95 100644
--- a/data/config/default/e.src
+++ b/data/config/default/e.src
@@ -1,5 +1,5 @@
group "E_Config" struct {
- value "config_version" int: 1000028;
+ value "config_version" int: 1000029;
value "config_type" uint: 0; // this profile seems to just be super minimalist
value "show_splash" int: 0;
value "desktop_default_name" string: "%i-%i";
diff --git a/data/config/standard/e.src b/data/config/standard/e.src
index 4c716d877a..bc9fc5dadc 100644
--- a/data/config/standard/e.src
+++ b/data/config/standard/e.src
@@ -1,5 +1,5 @@
group "E_Config" struct {
- value "config_version" int: 1000028;
+ value "config_version" int: 1000029;
value "config_type" uint: 3;
value "show_splash" int: 1;
value "desktop_default_name" string: "%i-%i";
@@ -1015,6 +1015,10 @@ group "E_Config" struct {
value "name" string: "bluez5";
value "enabled" uchar: 1;
}
+ group "E_Config_Module" struct {
+ value "name" string: "polkit";
+ value "enabled" uchar: 1;
+ }
}
group "xkb.used_layouts" list {
group "E_Config_XKB_Layout" struct {
diff --git a/data/config/tiling/e.src b/data/config/tiling/e.src
index 431fce4bdc..2d81e5a6dc 100644
--- a/data/config/tiling/e.src
+++ b/data/config/tiling/e.src
@@ -1,5 +1,5 @@
group "E_Config" struct {
- value "config_version" int: 1000028;
+ value "config_version" int: 1000029;
value "config_type" uint: 3;
value "show_splash" int: 1;
value "desktop_default_name" string: "%i-%i";
@@ -1034,10 +1034,13 @@ group "E_Config" struct {
value "enabled" uchar: 1;
}
group "E_Config_Module" struct {
+ value "name" string: "polkit";
+ value "enabled" uchar: 1;
+ }
+ group "E_Config_Module" struct {
value "name" string: "tiling";
value "enabled" uchar: 1;
}
-
}
group "xkb.used_layouts" list {
group "E_Config_XKB_Layout" struct {
diff --git a/meson_options.txt b/meson_options.txt
index d3457def87..3a077e8a72 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -155,6 +155,10 @@ option('lokker',
type: 'boolean',
value: true,
description: 'enable lokker module: (default=true)')
+option('polkit',
+ type: 'boolean',
+ value: true,
+ description: 'enable polkit module: (default=true)')
option('luncher',
type: 'boolean',
value: true,
diff --git a/src/bin/e_auth.c b/src/bin/e_auth.c
index 00b0e5d843..92670f5d3c 100644
--- a/src/bin/e_auth.c
+++ b/src/bin/e_auth.c
@@ -6,14 +6,17 @@ e_auth_begin(char *passwd)
char buf[PATH_MAX], *p;
Ecore_Exe *exe = NULL;
int ret = 0;
+ size_t pwlen;
- if (strlen(passwd) == 0) goto out;
+ pwlen = strlen(passwd);
+ if (pwlen == 0) goto out;
- snprintf(buf, sizeof(buf), "%s/enlightenment/utils/enlightenment_ckpasswd",
+ snprintf(buf, sizeof(buf),
+ "%s/enlightenment/utils/enlightenment_ckpasswd pw",
e_prefix_lib_get());
-
exe = ecore_exe_pipe_run(buf, ECORE_EXE_PIPE_WRITE, NULL);
- if (ecore_exe_send(exe, passwd, strlen(passwd)) != EINA_TRUE) goto out;
+ if (!exe) goto out;
+ if (ecore_exe_send(exe, passwd, pwlen) != EINA_TRUE) goto out;
ecore_exe_close_stdin(exe);
ret = ecore_exe_pid_get(exe);
@@ -24,12 +27,56 @@ e_auth_begin(char *passwd)
}
exe = NULL;
+
out:
if (exe) ecore_exe_free(exe);
/* security - null out passwd string once we are done with it */
for (p = passwd; *p; p++) *p = 0;
- if (passwd[0] || passwd[3]) fprintf(stderr, "ACK!\n");
+ if (passwd[rand() % pwlen]) fprintf(stderr, "ACK!\n");
+ return ret;
+}
+
+E_API int
+e_auth_polkit_begin(char *passwd, const char *cookie, unsigned int uid)
+{
+ char buf[PATH_MAX], *p;
+ Ecore_Exe *exe = NULL;
+ int ret = 0;
+ size_t pwlen, buflen = 0;
+
+ pwlen = strlen(passwd);
+ if (pwlen == 0) goto out;
+
+ snprintf(buf, sizeof(buf),
+ "%s/enlightenment/utils/enlightenment_ckpasswd pk",
+ e_prefix_lib_get());
+ exe = ecore_exe_pipe_run(buf, ECORE_EXE_PIPE_WRITE, NULL);
+ if (!exe) goto out;
+ snprintf(buf, sizeof(buf), "%s %u %s", cookie, uid, passwd);
+ buflen = strlen(buf);
+ if (ecore_exe_send(exe, buf, buflen) != EINA_TRUE) goto out;
+ ecore_exe_close_stdin(exe);
+ ret = ecore_exe_pid_get(exe);
+ if (ret == -1)
+ {
+ ret = 0;
+ goto out;
+ }
+ exe = NULL;
+
+out:
+ if (exe) ecore_exe_free(exe);
+
+ /* security - null out passwd string once we are done with it */
+ for (p = passwd; *p; p++) *p = 0;
+ if (passwd[rand() % pwlen]) fprintf(stderr, "ACK!\n");
+ /* security - null out buf string once we are done with it */
+ if (buflen > 0)
+ {
+ for (p = buf; *p; p++) *p = 0;
+ if (buf[rand() % buflen]) fprintf(stderr, "ACK!\n");
+ }
return ret;
}
diff --git a/src/bin/e_auth.h b/src/bin/e_auth.h
index 2ca2837634..8728f2900b 100644
--- a/src/bin/e_auth.h
+++ b/src/bin/e_auth.h
@@ -2,6 +2,7 @@
#define E_AUTH_H
E_API int e_auth_begin(char *passwd);
+E_API int e_auth_polkit_begin(char *passwd, const char *cookie, unsigned int uid);
static inline int
e_auth_hash_djb2(const char *key, int len)
diff --git a/src/bin/e_ckpasswd_main.c b/src/bin/e_ckpasswd_main.c
index 31b04e7385..173c5bd487 100644
--- a/src/bin/e_ckpasswd_main.c
+++ b/src/bin/e_ckpasswd_main.c
@@ -15,6 +15,10 @@
#include <alloca.h>
#endif
+#include <Eina.h>
+#include <Ecore.h>
+#include <Eldbus.h>
+
#if defined(__OpenBSD__)
static int
@@ -162,42 +166,192 @@ _check_auth(uid_t uid, const char *pw)
#endif
+static int polkit_auth_ok = -1;
+
+static void
+polkit_agent_response(void *data EINA_UNUSED, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *name, *text;
+
+ ecore_main_loop_quit();
+ if (eldbus_message_error_get(msg, &name, &text))
+ {
+ printf("Could not respond to auth.\n %s:\n %s\n", name, text);
+ return;
+ }
+ polkit_auth_ok = 0;
+ printf("Auth OK\n");
+}
+
+int
+polkit_auth(const char *cookie, unsigned int auth_uid)
+{
+ Eldbus_Connection *c;
+ Eldbus_Object *obj;
+ Eldbus_Proxy *proxy;
+ Eldbus_Message *m;
+ Eldbus_Message_Iter *iter, *subj, *array, *dict, *vari;
+ unsigned int uid;
+
+ eina_init();
+ ecore_init();
+ eldbus_init();
+ c = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
+ if (!c) return -1;
+ obj = eldbus_object_get(c, "org.freedesktop.PolicyKit1",
+ "/org/freedesktop/PolicyKit1/Authority");
+ if (!obj) return -1;
+ proxy = eldbus_proxy_get(obj, "org.freedesktop.PolicyKit1.Authority");
+ if (!proxy) return -1;
+ m = eldbus_proxy_method_call_new(proxy, "AuthenticationAgentResponse2");
+ if (!m) return -1;
+ iter = eldbus_message_iter_get(m);
+ if (!iter) return -1;
+ uid = getuid();
+ if (eldbus_message_iter_arguments_append(iter, "us", auth_uid, cookie))
+ {
+ if (eldbus_message_iter_arguments_append(iter, "(sa{sv})", &subj))
+ {
+ if (eldbus_message_iter_basic_append(subj, 's', "unix-user"))
+ {
+ if (eldbus_message_iter_arguments_append(subj, "a{sv}", &array))
+ {
+ if (eldbus_message_iter_arguments_append(array, "{sv}", &dict))
+ {
+ if (eldbus_message_iter_basic_append(dict, 's', "uid"))
+ {
+ vari = eldbus_message_iter_container_new(dict, 'v', "u");
+ if (vari)
+ {
+ if (eldbus_message_iter_basic_append(vari, 'u', auth_uid))
+ {
+ eldbus_message_iter_container_close(dict, vari);
+ } else return -1;
+ } else return -1;
+ } else return -1;
+ eldbus_message_iter_container_close(array, dict);
+ } else return -1;
+ eldbus_message_iter_container_close(subj, array);
+ } else return -1;
+ } else return -1;
+ eldbus_message_iter_container_close(iter, subj);
+ } else return -1;
+ eldbus_proxy_send(proxy, m, polkit_agent_response, NULL, -1);
+ } else return -1;
+
+ ecore_main_loop_begin();
+
+ eldbus_connection_unref(c);
+ eldbus_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return polkit_auth_ok;
+}
+
int
main(int argc, char **argv)
{
ssize_t rd;
uid_t id;
char pw[4096], *p;
+ int polkit_mode = 0;
+ char polkit_cookie[4096];
+ unsigned int polkit_uid = 0;
- if (argc != 1)
+ if (argc < 2)
{
- int i;
-
- for (i = 1; i < argc; i++)
- fprintf(stderr, "Unknown option %s\n", argv[i]);
- fprintf(stderr,
- "This is an internal tool for Enlightenment\n");
+ fprintf(stderr, "This is an internal tool for Enlightenment\n");
+ fprintf(stderr, "Options: pw | pk\n");
goto err;
}
+ if (!strcmp(argv[1], "pw")) polkit_mode = 0;
+ else if (!strcmp(argv[1], "pk")) polkit_mode = 1;
// get uid who ran this
id = getuid();
// read passwd from stdin
- rd = read(0, pw, sizeof(pw) - 1);
- if (rd < 0)
+ if (polkit_mode == 0)
{
- fprintf(stderr,
- "Error. Can't read passwd on stdin\n");
- goto err;
+ rd = read(0, pw, sizeof(pw) - 1);
+ if (rd < 0)
+ {
+ fprintf(stderr, "Error. Can't read passwd on stdin\n");
+ goto err;
+ }
+ pw[rd] = 0;
+ for (p = pw; *p; p++)
+ {
+ if ((*p == '\r') || (*p == '\n'))
+ {
+ *p = 0;
+ break;
+ }
+ }
}
- pw[rd] = 0;
- for (p = pw; *p; p++)
+ else if (polkit_mode == 1)
{
- if ((*p == '\r') || (*p == '\n'))
+ unsigned int pos = 0;
+
+ // read "cookie-string uid-string password...[\r|\n|EOF]"
+ for (;;) // cookie
{
- *p = 0;
- break;
+ rd = read(0, pw + pos, 1);
+ if (pw[pos] == ' ')
+ {
+ memcpy(polkit_cookie, pw, pos);
+ polkit_cookie[pos] = 0;
+ printf("COOKIE: [%s]\n", polkit_cookie);
+ pos = 0;
+ break;
+ }
+ else
+ {
+ pos++;
+ if (pos > 4000)
+ {
+ fprintf(stderr, "Error. Polkit cookie too long\n");
+ return -10;
+ }
+ }
+ }
+ for (;;) // uid
+ {
+ rd = read(0, pw + pos, 1);
+ if (pw[pos] == ' ')
+ {
+ pw[pos] = 0;
+ polkit_uid = atoi(pw);
+ printf("UID: [%u]\n", polkit_uid);
+ break;
+ }
+ else
+ {
+ pos++;
+ if (pos > 4000)
+ {
+ fprintf(stderr, "Error. Polkit uid too long\n");
+ return -11;
+ }
+ }
+ }
+ // password
+ printf("READPASS...\n");
+ rd = read(0, pw, sizeof(pw) - 1);
+ if (rd < 0)
+ {
+ fprintf(stderr, "Error. Can't read passwd on stdin\n");
+ goto err;
+ }
+ pw[rd] = 0;
+ for (p = pw; *p; p++)
+ {
+ if ((*p == '\r') || (*p == '\n'))
+ {
+ *p = 0;
+ break;
+ }
}
}
@@ -209,9 +363,22 @@ main(int argc, char **argv)
if (setgid(0) != 0)
fprintf(stderr,
"Warning. Can't become group root. If password auth requires root then this will fail\n");
- if (_check_auth(id, pw) == 0) return 0;
+ if (_check_auth(id, pw) == 0)
+ {
+ fprintf(stderr, "Password OK\n");
+ if (polkit_mode == 1)
+ {
+ if (polkit_auth(polkit_cookie, polkit_uid) == 0)
+ {
+ fprintf(stderr, "Polkit AuthenticationAgentResponse2 success\n");
+ return 0;
+ }
+ fprintf(stderr, "Polkit AuthenticationAgentResponse2 failure\n");
+ return -2;
+ }
+ return 0;
+ }
err:
- fprintf(stderr,
- "Password auth fail\n");
+ fprintf(stderr, "Password auth fail\n");
return -1;
}
diff --git a/src/bin/e_config.c b/src/bin/e_config.c
index 5195321a1a..00fe411381 100644
--- a/src/bin/e_config.c
+++ b/src/bin/e_config.c
@@ -1441,6 +1441,7 @@ e_config_load(void)
e_config->window_maximize_animate = 1;
e_config->window_maximize_transition = E_EFX_EFFECT_SPEED_SINUSOIDAL;
e_config->window_maximize_time = 0.15;
+ e_config_save_queue();
}
CONFIG_VERSION_CHECK(22)
{
@@ -1465,6 +1466,7 @@ e_config_load(void)
module->enabled = 1;
e_config->modules = eina_list_append(e_config->modules, module);
}
+ e_config_save_queue();
}
CONFIG_VERSION_CHECK(23)
{
@@ -1487,6 +1489,7 @@ e_config_load(void)
module->enabled = 1;
e_config->modules = eina_list_append(e_config->modules, module);
}
+ e_config_save_queue();
}
CONFIG_VERSION_CHECK(24)
{
@@ -1494,6 +1497,7 @@ e_config_load(void)
if (!elm_config_profile_exists(_e_config_profile))
elm_config_profile_save(_e_config_profile);
+ e_config_save_queue();
}
CONFIG_VERSION_CHECK(25)
{
@@ -1574,6 +1578,29 @@ e_config_load(void)
}
e_config_save_queue();
}
+ CONFIG_VERSION_CHECK(29)
+ {
+ Eina_List *l;
+ E_Config_Module *em, *module;
+ Eina_Bool mod_loaded = EINA_FALSE;
+
+ CONFIG_VERSION_UPDATE_INFO(29);
+
+ EINA_LIST_FOREACH(e_config->modules, l, em)
+ {
+ if (!em->enabled) continue;
+ if (eina_streq(em->name, "polkit"))
+ mod_loaded = EINA_TRUE;
+ }
+ if (!mod_loaded)
+ {
+ module = E_NEW(E_Config_Module, 1);
+ module->name = eina_stringshare_add("polkit");
+ module->enabled = 1;
+ e_config->modules = eina_list_append(e_config->modules, module);
+ }
+ e_config_save_queue();
+ }
}
elm_config_profile_set(_e_config_profile);
if (!e_config->remember_internal_fm_windows)
diff --git a/src/bin/e_config.h b/src/bin/e_config.h
index 0c732502c5..3eeb395fb8 100644
--- a/src/bin/e_config.h
+++ b/src/bin/e_config.h
@@ -46,7 +46,7 @@ typedef enum
/* increment this whenever a new set of config values are added but the users
* config doesn't need to be wiped - simply new values need to be put in
*/
-#define E_CONFIG_FILE_GENERATION 28
+#define E_CONFIG_FILE_GENERATION 29
#define E_CONFIG_FILE_VERSION ((E_CONFIG_FILE_EPOCH * 1000000) + E_CONFIG_FILE_GENERATION)
#define E_CONFIG_BINDINGS_VERSION 0 // DO NOT INCREMENT UNLESS YOU WANT TO WIPE ALL BINDINGS!!!!!
diff --git a/src/bin/e_module.c b/src/bin/e_module.c
index bcc824e7de..92176625e5 100644
--- a/src/bin/e_module.c
+++ b/src/bin/e_module.c
@@ -753,6 +753,7 @@ _e_module_whitelist_check(void)
"ibox",
"layout",
"lokker",
+ "polkit",
"luncher",
"mixer",
"msgbus",
diff --git a/src/bin/meson.build b/src/bin/meson.build
index 138bb6596a..4a0878eb92 100644
--- a/src/bin/meson.build
+++ b/src/bin/meson.build
@@ -34,7 +34,7 @@ deps_e = [
dep_intl
]
-deps_ckpass = [ ]
+deps_ckpass = [ dep_eina, dep_ecore, dep_eldbus ]
if freebsd == true
deps_ckpass += dep_crypt
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 5ace236b39..a244bd320c 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -65,6 +65,7 @@ mods = [
# also standard modules with no icon or desktop file
'xwayland',
'lokker',
+ 'polkit',
'wl_x11',
'wl_wl',
'wl_buffer',
diff --git a/src/modules/polkit/auth_ui.c b/src/modules/polkit/auth_ui.c
new file mode 100644
index 0000000000..88639ebf4b
--- /dev/null
+++ b/src/modules/polkit/auth_ui.c
@@ -0,0 +1,149 @@
+#include "e_mod_main.h"
+
+static Eina_Bool
+_auth_cb_exit(void *data, int type EINA_UNUSED, void *event)
+{
+ Polkit_Session *ps = data;
+ Ecore_Exe_Event_Del *ev = event;
+
+ if (ev->pid != ps->auth_pid) return ECORE_CALLBACK_PASS_ON;
+ ps->auth_pid = 0;
+ if (ps->exe_exit_handler) ecore_event_handler_del(ps->exe_exit_handler);
+ ps->exe_exit_handler = NULL;
+ session_reply(ps);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_cb_del(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj,
+ void *event_info EINA_UNUSED)
+{
+ Polkit_Session *ps = evas_object_data_get(obj, "session");
+ if (!ps) return;
+ if (ps->exe_exit_handler)
+ {
+ ecore_event_handler_del(ps->exe_exit_handler);
+ ps->exe_exit_handler = NULL;
+ }
+ if (ps->win)
+ {
+ ps->win = NULL;
+ session_reply(ps);
+ }
+}
+
+static void
+_cb_ok(void *data EINA_UNUSED, Evas_Object *obj,
+ void *event_info EINA_UNUSED)
+{
+ Polkit_Session *ps = evas_object_data_get(obj, "session");
+ const char *str = elm_object_text_get(obj);
+
+ if (!ps) return;
+ if (ps->exe_exit_handler) return;
+ ps->exe_exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+ _auth_cb_exit, ps);
+ if (str)
+ {
+ char *passwd = strdup(str);
+ if (passwd)
+ {
+ ps->auth_pid = e_auth_polkit_begin(passwd, ps->cookie, ps->target_uid);
+ free(passwd);
+ return;
+ }
+ }
+ evas_object_del(ps->win);
+}
+
+static void
+_cb_cancel(void *data EINA_UNUSED, Evas_Object *obj,
+ void *event_info EINA_UNUSED)
+{
+ Polkit_Session *ps = evas_object_data_get(obj, "session");
+ if (!ps) return;
+ if (ps->exe_exit_handler) return;
+ session_reply(ps);
+}
+
+static void
+_cb_button_ok(void *data, E_Dialog *dia EINA_UNUSED)
+{
+ _cb_ok(NULL, data, NULL);
+}
+
+static void
+_cb_button_cancel(void *data, E_Dialog *dia EINA_UNUSED)
+{
+ _cb_cancel(NULL, data, NULL);
+}
+
+void
+auth_ui(Polkit_Session *ps)
+{
+ E_Dialog *dia;
+ Evas_Object *o, *win, *box, *ent;
+
+ dia = e_dialog_new(NULL, "E", "_polkit_auth");
+ e_dialog_title_set(dia, _("Please enter password"));
+
+ win = dia->win;
+
+ if ((!ps->icon_name) || (!ps->icon_name[0]))
+ e_dialog_icon_set(dia, "enlightenment", 64);
+ else
+ e_dialog_icon_set(dia, ps->icon_name, 64);
+
+ evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _cb_del, NULL);
+ elm_win_autodel_set(win, EINA_TRUE);
+ evas_object_data_set(win, "session", ps);
+
+ box = o = elm_box_add(win);
+ evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+ evas_object_size_hint_align_set(o, -1.0, -1.0);
+ elm_box_horizontal_set(o, EINA_FALSE);
+ e_dialog_content_set(dia, o, 0, 0);
+ evas_object_show(o);
+
+/* XXX: lookup action and display something useful for it in future.
+ o = elm_label_add(win);
+ evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+ evas_object_size_hint_align_set(o, 0.0, 0.0);
+ elm_object_text_set(o, ps->action);
+ elm_box_pack_end(box, o);
+ evas_object_show(o);
+ */
+
+ o = elm_label_add(win);
+ evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+ evas_object_size_hint_align_set(o, 0.0, 0.0);
+ elm_object_text_set(o, ps->message);
+ elm_box_pack_end(box, o);
+ evas_object_show(o);
+
+ ent = o = elm_entry_add(win);
+ evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+ evas_object_size_hint_align_set(o, -1.0, 1.0);
+ elm_entry_single_line_set(ent, EINA_TRUE);
+ elm_entry_scrollable_set(ent, EINA_TRUE);
+ elm_entry_password_set(ent, EINA_TRUE);
+ elm_object_part_text_set(ent, "elm.guide", "Enter Password");
+ evas_object_data_set(ent, "session", ps);
+ evas_object_smart_callback_add(ent, "activated", _cb_ok, NULL);
+ evas_object_smart_callback_add(ent, "aborted", _cb_cancel, NULL);
+ elm_box_pack_end(box, o);
+ evas_object_show(o);
+
+ e_dialog_button_add(dia, _("OK"), NULL, _cb_button_ok, ent);
+ e_dialog_button_add(dia, _("Cancel"), NULL, _cb_button_cancel, ent);
+ e_dialog_button_focus_num(dia, 0);
+
+ elm_object_focus_set(ent, EINA_TRUE);
+
+ ps->win = win;
+ ps->entry = ent;
+
+ elm_win_center(win, 1, 1);
+ e_dialog_show(dia);
+ elm_win_activate(win);
+}
diff --git a/src/modules/polkit/e-module-polkit.edj b/src/modules/polkit/e-module-polkit.edj
new file mode 100644
index 0000000000..807f83df48
--- /dev/null
+++ b/src/modules/polkit/e-module-polkit.edj
Binary files differ
diff --git a/src/modules/polkit/e_mod_main.c b/src/modules/polkit/e_mod_main.c
new file mode 100644
index 0000000000..c7cc07a554
--- /dev/null
+++ b/src/modules/polkit/e_mod_main.c
@@ -0,0 +1,17 @@
+#include "e_mod_main.h"
+
+E_API E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Polkit"};
+
+E_API void *
+e_modapi_init(E_Module *m)
+{
+ e_mod_polkit_register();
+ return m;
+}
+
+E_API int
+e_modapi_shutdown(E_Module *m EINA_UNUSED)
+{
+ e_mod_polkit_unregister();
+ return 1;
+}
diff --git a/src/modules/polkit/e_mod_main.h b/src/modules/polkit/e_mod_main.h
new file mode 100644
index 0000000000..db38fa9c23
--- /dev/null
+++ b/src/modules/polkit/e_mod_main.h
@@ -0,0 +1,32 @@
+#ifndef E_MOD_MAIN_H
+#define E_MOD_MAIN_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e.h"
+
+typedef struct
+{
+ const char *cookie;
+ const char *message;
+ const char *icon_name;
+ const char *action;
+ unsigned int target_uid;
+ int auth_pid;
+ Ecore_Event_Handler *exe_exit_handler;
+ Eldbus_Message *reply;
+ Eldbus_Pending *pend_reply;
+ Evas_Object *win;
+ Evas_Object *entry;
+} Polkit_Session;
+
+void session_reply(Polkit_Session *ps);
+
+void auth_ui(Polkit_Session *ps);
+
+void e_mod_polkit_register(void);
+void e_mod_polkit_unregister(void);
+
+#endif
diff --git a/src/modules/polkit/meson.build b/src/modules/polkit/meson.build
new file mode 100644
index 0000000000..f839f7aa15
--- /dev/null
+++ b/src/modules/polkit/meson.build
@@ -0,0 +1,6 @@
+src = files(
+ 'e_mod_main.c',
+ 'polkit.c',
+ 'auth_ui.c',
+ 'e_mod_main.h'
+ )
diff --git a/src/modules/polkit/module.desktop b/src/modules/polkit/module.desktop
new file mode 100644
index 0000000000..f1189282c7
--- /dev/null
+++ b/src/modules/polkit/module.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=Link
+Name=Polkit
+Comment=This module provides a polkit authentication agent
+Icon=e-module-polkit
+X-Enlightenment-ModuleType=core
diff --git a/src/modules/polkit/polkit.c b/src/modules/polkit/polkit.c
new file mode 100644
index 0000000000..d29b8547e1
--- /dev/null
+++ b/src/modules/polkit/polkit.c
@@ -0,0 +1,523 @@
+#include "e_mod_main.h"
+
+static Eldbus_Connection *pk_conn = NULL;
+static Eldbus_Service_Interface *agent_iface = NULL;
+static Eldbus_Object *pk_obj = NULL;
+static Eldbus_Proxy *pk_proxy = NULL;
+
+static Eldbus_Pending *pend_call = NULL;
+
+static Eldbus_Object *ses_obj = NULL;
+static Eldbus_Object *ses_obj2 = NULL;
+static Eldbus_Proxy *ses_proxy = NULL;
+static Eldbus_Proxy *ses_proxy2 = NULL;
+
+static Eina_Bool agent_request = EINA_FALSE;
+static Eina_Bool agent_ok = EINA_FALSE;
+static const char *session_path = NULL;
+static const char *session_id = NULL;
+static unsigned int session_uid = 0;
+static const char *session_user = NULL;
+
+//////////////////////////////////////////////////////////////////////////////
+
+static Eina_Hash *sessions = NULL;
+
+static void
+_session_free(Polkit_Session *ps)
+{
+ if (ps->reply) eldbus_connection_send(pk_conn, ps->reply, NULL, NULL, -1);
+ ps->reply = NULL;
+ if (ps->pend_reply) eldbus_pending_cancel(ps->pend_reply);
+ ps->pend_reply = NULL;
+ eina_stringshare_del(ps->cookie);
+ ps->cookie = NULL;
+ eina_stringshare_del(ps->message);
+ ps->message = NULL;
+ eina_stringshare_del(ps->icon_name);
+ ps->icon_name = NULL;
+ eina_stringshare_del(ps->action);
+ ps->action = NULL;
+ if (ps->win)
+ {
+ Evas_Object *win = ps->win;
+
+ ps->win = NULL;
+ evas_object_del(win);
+ }
+ free(ps);
+}
+
+static void
+session_init(void)
+{
+ if (sessions) return;
+ sessions = eina_hash_string_superfast_new((void *)_session_free);
+}
+
+static void
+session_shutdown(void)
+{
+ if (sessions) eina_hash_free(sessions);
+ sessions = NULL;
+}
+
+static Polkit_Session *
+session_new(void)
+{
+ return calloc(1, sizeof(Polkit_Session));
+}
+
+static void
+session_free(Polkit_Session *ps)
+{
+ eina_hash_del(sessions, ps->cookie, ps);
+}
+
+static void
+session_register(Polkit_Session *ps)
+{
+ eina_hash_add(sessions, ps->cookie, ps);
+}
+
+static Polkit_Session *
+session_find(const char *cookie)
+{
+ return eina_hash_find(sessions, cookie);
+}
+
+void
+session_reply(Polkit_Session *ps)
+{
+ if (ps->reply)
+ {
+ ps->pend_reply = eldbus_connection_send(pk_conn, ps->reply, NULL, NULL, -1);
+ ps->reply = NULL;
+ }
+ session_free(ps);
+}
+
+void
+session_show(Polkit_Session *ps)
+{
+ auth_ui(ps);
+ // display some auth dialog to enter a password, show ps->message
+ // and ps->action specific ui ps->icon_name
+ // when we get the password call
+ // e_auth_polkit_begin(pass, ps->cookie, ps->target_uid);
+ // when this returns call session_reply(ps);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void
+iterate_dict(void *data, const void *key, Eldbus_Message_Iter *var)
+{
+ Polkit_Session *ps = data;
+ const char *skey = key;
+
+ if (!strcmp(skey, "uid"))
+ {
+ unsigned int uid = 0;
+
+ if (eldbus_message_iter_arguments_get(var, "u", &uid))
+ ps->target_uid = uid;
+ }
+}
+
+static Eldbus_Message *
+cb_agent_begin_authentication(const Eldbus_Service_Interface *iface EINA_UNUSED,
+ const Eldbus_Message *msg)
+{
+ // sssa{ss}sa(sa{sv})
+ const char *action_id = NULL, *message = NULL, *icon_name = NULL,
+ *cookie = NULL;
+ Eldbus_Message_Iter *details = NULL, *ident = NULL, *item = NULL;
+ Polkit_Session *ps, *ps2;
+
+ ps = session_new();
+ if (!ps) goto err;
+ ps->reply = eldbus_message_method_return_new(msg);
+
+ if (!eldbus_message_arguments_get(msg, "sssa{ss}sa(sa{sv})",
+ &action_id, &message, &icon_name,
+ &details, &cookie, &ident))
+ goto err;
+ ps->cookie = eina_stringshare_add(cookie);
+ ps->message = eina_stringshare_add(message);
+ ps->icon_name = eina_stringshare_add(icon_name);
+ ps->action = eina_stringshare_add(action_id);
+ // actions in: /usr/share/polkit-1/actions
+
+/* XXX: Haven't seen details content yet - not sure what to do with it
+ while (eldbus_message_iter_get_and_next(details, 'r', &item))
+ {
+ const char *v1, *v2;
+
+ v1 = NULL;
+ v2 = NULL;
+ eldbus_message_iter_arguments_get(item, "ss", &v1, &v2);
+ }
+ */
+ while (eldbus_message_iter_get_and_next(ident, 'r', &item))
+ {
+ const char *v1;
+ Eldbus_Message_Iter *dict = NULL;
+
+ v1 = NULL;
+ eldbus_message_iter_arguments_get(item, "sa{sv}", &v1, &dict);
+ if (!strcmp(v1, "unix-user"))
+ eldbus_message_iter_dict_iterate(dict, "sv", iterate_dict, ps);
+ else
+ {
+ printf("PK: Unhandled ident type.\n");
+ }
+ }
+ ps2 = session_find(ps->cookie);
+ if (ps2) session_free(ps2);
+ session_register(ps);
+ session_show(ps);
+ return NULL;
+err:
+ return eldbus_message_method_return_new(msg);
+}
+
+static Eldbus_Message *
+cb_agent_cancel_authentication(const Eldbus_Service_Interface *iface EINA_UNUSED,
+ const Eldbus_Message *msg)
+{
+ const char *cookie;
+ Polkit_Session *ps;
+
+ // s
+ if (!eldbus_message_arguments_get(msg, "s", &cookie)) return NULL;
+ ps = session_find(cookie);
+ if (ps) session_free(ps);
+ return eldbus_message_method_return_new(msg);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void
+cb_register(void *data EINA_UNUSED, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *name, *text;
+
+ pend_call = NULL;
+ if (eldbus_message_error_get(msg, &name, &text)) return;
+ agent_request = EINA_FALSE;
+ agent_ok = EINA_TRUE;
+}
+
+static const Eldbus_Method agent_methods[] = {
+ { "BeginAuthentication",
+ ELDBUS_ARGS({ "s", "action_id" },
+ { "s", "message" },
+ { "s", "icon_name" },
+ { "a{ss}", "details" },
+ { "s", "cookie" },
+ { "a(sa{sv})", "identities" }),
+ NULL,
+ cb_agent_begin_authentication, 0
+ },
+ { "CancelAuthentication",
+ ELDBUS_ARGS({ "s", "cookie" }),
+ NULL,
+ cb_agent_cancel_authentication, 0
+ },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+static const Eldbus_Service_Interface_Desc agent_desc = {
+ "org.freedesktop.PolicyKit1.AuthenticationAgent", agent_methods, NULL, NULL, NULL, NULL
+};
+
+static void
+pk_agent_register(void)
+{
+ Eldbus_Message *msg;
+ Eldbus_Message_Iter *iter, *subj, *array, *dict, *vari;
+ const char *locale = NULL;
+
+ agent_request = EINA_TRUE;
+ // set up agent interface
+ agent_iface = eldbus_service_interface_register
+ (pk_conn, "/org/enlightenment/polkit/Agent", &agent_desc);
+
+ // register agent interface with polkit
+ if (!locale) locale = getenv("LC_MESSAGES");
+ if (!locale) locale = getenv("LC_ALL");
+ if (!locale) locale = getenv("LANG");
+ if (!locale) locale = getenv("LANGUAGE");
+ if (!locale) locale = "C";
+
+ pk_obj = eldbus_object_get(pk_conn, "org.freedesktop.PolicyKit1",
+ "/org/freedesktop/PolicyKit1/Authority");
+ if (!pk_obj) return;
+ pk_proxy = eldbus_proxy_get(pk_obj, "org.freedesktop.PolicyKit1.Authority");
+ if (!pk_proxy) return;
+ msg = eldbus_proxy_method_call_new(pk_proxy, "RegisterAuthenticationAgent");
+ // (sa{sv})ss
+ iter = eldbus_message_iter_get(msg);
+ eldbus_message_iter_arguments_append(iter, "(sa{sv})", &subj);
+ eldbus_message_iter_basic_append(subj, 's', "unix-session");
+ eldbus_message_iter_arguments_append(subj, "a{sv}", &array);
+ eldbus_message_iter_arguments_append(array, "{sv}", &dict);
+ eldbus_message_iter_basic_append(dict, 's', "session-id");
+ vari = eldbus_message_iter_container_new(dict, 'v', "s");
+ eldbus_message_iter_basic_append(vari, 's', session_id);
+ eldbus_message_iter_container_close(dict, vari);
+ eldbus_message_iter_container_close(array, dict);
+ eldbus_message_iter_container_close(subj, array);
+ eldbus_message_iter_container_close(iter, subj);
+
+ eldbus_message_iter_basic_append(iter, 's', locale);
+ eldbus_message_iter_basic_append(iter, 's', "/org/enlightenment/polkit/Agent");
+ pend_call = eldbus_proxy_send(pk_proxy, msg, cb_register, NULL, -1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void
+cb_login_prop_entry(void *data EINA_UNUSED, const void *key, Eldbus_Message_Iter *var)
+{
+ const char *skey = key;
+
+ if (!strcmp(skey, "Id"))
+ {
+ const char *val = NULL;
+ if (eldbus_message_iter_arguments_get(var, "s", &val))
+ eina_stringshare_replace(&session_id, val);
+ }
+ else if (!strcmp(skey, "User"))
+ {
+ Eldbus_Message_Iter *iter = NULL;
+
+ eldbus_message_iter_arguments_get(var, "(uo)", &iter);
+ if (iter)
+ {
+ unsigned int uid = 0;
+ const char *val = NULL;
+
+ if (eldbus_message_iter_arguments_get(iter, "uo", &uid, &val))
+ {
+ session_uid = uid;
+ eina_stringshare_replace(&session_user, val);
+ }
+ }
+ }
+}
+
+static void
+cb_login_prop(void *data EINA_UNUSED, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ Eldbus_Message_Iter *array;
+
+ pend_call = NULL;
+ if (eldbus_message_error_get(msg, NULL, NULL)) return;
+ if (eldbus_message_arguments_get(msg, "a{sv}", &array))
+ {
+ eldbus_message_iter_dict_iterate(array, "sv",
+ cb_login_prop_entry, NULL);
+ if ((session_id) && (session_user) && (session_path))
+ pk_agent_register();
+ }
+ if (ses_proxy2) eldbus_proxy_unref(ses_proxy2);
+ ses_proxy2 = NULL;
+ if (ses_proxy) eldbus_proxy_unref(ses_proxy);
+ ses_proxy = NULL;
+ if (ses_obj) eldbus_object_unref(ses_obj);
+ ses_obj = NULL;
+ if (ses_obj2) eldbus_object_unref(ses_obj2);
+ ses_obj2 = NULL;
+}
+
+static void
+cb_login_session(void *data EINA_UNUSED, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ const char *name, *text;
+ const char *s;
+
+ pend_call = NULL;
+ if (eldbus_message_error_get(msg, &name, &text)) return;
+ if (!eldbus_message_arguments_get(msg, "o", &s)) return;
+ eina_stringshare_replace(&session_path, s);
+ ses_obj2 = eldbus_object_get(pk_conn, "org.freedesktop.login1", s);
+ if (!ses_obj2) return;
+ ses_proxy2 = eldbus_proxy_get(ses_obj2, "org.freedesktop.login1.Session");
+ if (!ses_proxy2) return;
+ pend_call = eldbus_proxy_property_get_all(ses_proxy2, cb_login_prop, NULL);
+}
+
+static void
+pk_session_init(void)
+{
+ ses_obj = eldbus_object_get(pk_conn, "org.freedesktop.login1",
+ "/org/freedesktop/login1");
+ if (!ses_obj) return;
+ ses_proxy = eldbus_proxy_get(ses_obj, "org.freedesktop.login1.Manager");
+ if (!ses_proxy) return;
+ pend_call = eldbus_proxy_call(ses_proxy, "GetSessionByPID",
+ cb_login_session, NULL, -1,
+ "u", (unsigned int)getpid());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static Ecore_Timer *owner_gain_timer = NULL;
+
+static Eina_Bool
+cb_name_owner_new(void *data EINA_UNUSED)
+{
+ owner_gain_timer = NULL;
+ pk_session_init();
+ session_init();
+ return EINA_FALSE;
+}
+
+static void
+cb_name_owner_changed(void *data EINA_UNUSED,
+ const char *bus EINA_UNUSED,
+ const char *from EINA_UNUSED,
+ const char *to)
+{
+ static Eina_Bool first = EINA_TRUE;
+
+ if (to[0])
+ {
+ if (owner_gain_timer) ecore_timer_del(owner_gain_timer);
+ // on first start try and re-init quickly because we get a name
+ // owner change even if all is good when we register to listen for it,
+ // so start fast
+ if (first)
+ owner_gain_timer = ecore_timer_add(0.1, cb_name_owner_new, NULL);
+ // but if we gegt a name owner change later it's probably because
+ // bluez was restarted or crashed. a new bz daemon will (or should)
+ // come up. so re-init more slowly here giving the daemon some time
+ // to come up before pestering it.
+ else
+ owner_gain_timer = ecore_timer_add(1.0, cb_name_owner_new, NULL);
+ first = EINA_FALSE;
+ }
+ else
+ {
+ session_shutdown();
+ if (pend_call) eldbus_pending_cancel(pend_call);
+ pend_call = NULL;
+ if (agent_iface) eldbus_service_object_unregister(agent_iface);
+ agent_iface = NULL;
+ if (owner_gain_timer) ecore_timer_del(owner_gain_timer);
+ owner_gain_timer = NULL;
+
+ if (pk_proxy) eldbus_proxy_unref(pk_proxy);
+ pk_proxy = NULL;
+ if (pk_obj) eldbus_object_unref(pk_obj);
+ pk_obj = NULL;
+
+ if (pk_proxy) eldbus_proxy_unref(pk_proxy);
+ pk_proxy = NULL;
+ if (pk_obj) eldbus_object_unref(pk_obj);
+ pk_obj = NULL;
+ if (ses_proxy2) eldbus_proxy_unref(ses_proxy2);
+ ses_proxy2 = NULL;
+ if (ses_proxy) eldbus_proxy_unref(ses_proxy);
+ ses_proxy = NULL;
+ if (ses_obj) eldbus_object_unref(ses_obj);
+ ses_obj = NULL;
+ if (ses_obj2) eldbus_object_unref(ses_obj2);
+ ses_obj2 = NULL;
+ agent_request = EINA_FALSE;
+ agent_ok = EINA_FALSE;
+ eina_stringshare_replace(&session_path, NULL);
+ eina_stringshare_replace(&session_id, NULL);
+ eina_stringshare_replace(&session_user, NULL);
+ session_uid = 0;
+ }
+}
+
+void
+e_mod_polkit_register(void)
+{
+ agent_request = EINA_FALSE;
+ agent_ok = EINA_FALSE;
+ pk_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
+ if (pk_conn)
+ {
+ eldbus_name_owner_changed_callback_add(pk_conn,
+ "org.freedesktop.PolicyKit1",
+ cb_name_owner_changed, NULL,
+ EINA_TRUE);
+ }
+}
+
+void
+e_mod_polkit_unregister(void)
+{
+ Eldbus_Message *msg;
+ Eldbus_Message_Iter *iter, *subj, *array, *dict, *vari;
+
+ if (!pk_conn) return;
+ eldbus_name_owner_changed_callback_del(pk_conn,
+ "org.freedesktop.PolicyKit1",
+ cb_name_owner_changed, NULL);
+ if (pend_call) eldbus_pending_cancel(pend_call);
+ pend_call = NULL;
+
+ if ((agent_request || agent_ok) && (session_id) && (pk_proxy))
+ {
+ msg = eldbus_proxy_method_call_new(pk_proxy,
+ "UnregisterAuthenticationAgent");
+ // (sa{sv})s
+ iter = eldbus_message_iter_get(msg);
+ eldbus_message_iter_arguments_append(iter, "(sa{sv})", &subj);
+ eldbus_message_iter_basic_append(subj, 's', "unix-session");
+ eldbus_message_iter_arguments_append(subj, "a{sv}", &array);
+ eldbus_message_iter_arguments_append(array, "{sv}", &dict);
+ eldbus_message_iter_basic_append(dict, 's', "session-id");
+ vari = eldbus_message_iter_container_new(dict, 'v', "s");
+ eldbus_message_iter_basic_append(vari, 's', session_id);
+ eldbus_message_iter_container_close(dict, vari);
+ eldbus_message_iter_container_close(array, dict);
+ eldbus_message_iter_container_close(subj, array);
+ eldbus_message_iter_container_close(iter, subj);
+ eldbus_message_iter_basic_append(iter, 's', "/org/enlightenment/polkit/Agent");
+ eldbus_proxy_send(pk_proxy, msg, NULL, NULL, -1);
+ }
+
+ session_shutdown();
+
+ if (agent_iface) eldbus_service_object_unregister(agent_iface);
+ agent_iface = NULL;
+ if (owner_gain_timer) ecore_timer_del(owner_gain_timer);
+ owner_gain_timer = NULL;
+
+ if (pk_proxy) eldbus_proxy_unref(pk_proxy);
+ pk_proxy = NULL;
+ if (pk_obj) eldbus_object_unref(pk_obj);
+ pk_obj = NULL;
+
+ if (pk_proxy) eldbus_proxy_unref(pk_proxy);
+ pk_proxy = NULL;
+ if (pk_obj) eldbus_object_unref(pk_obj);
+ pk_obj = NULL;
+ if (ses_proxy2) eldbus_proxy_unref(ses_proxy2);
+ ses_proxy2 = NULL;
+ if (ses_proxy) eldbus_proxy_unref(ses_proxy);
+ ses_proxy = NULL;
+ if (ses_obj) eldbus_object_unref(ses_obj);
+ ses_obj = NULL;
+ if (ses_obj2) eldbus_object_unref(ses_obj2);
+ ses_obj2 = NULL;
+
+ eldbus_connection_unref(pk_conn);
+ pk_conn = NULL;
+
+ agent_request = EINA_FALSE;
+ agent_ok = EINA_FALSE;
+ eina_stringshare_replace(&session_path, NULL);
+ eina_stringshare_replace(&session_id, NULL);
+ eina_stringshare_replace(&session_user, NULL);
+ session_uid = 0;
+}