525 lines
16 KiB
C
525 lines
16 KiB
C
#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:
|
|
if (ps) session_free(ps);
|
|
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;
|
|
}
|