Home | History | Annotate | Download | only in gdbus
      1 /*
      2  *
      3  *  D-Bus helper library
      4  *
      5  *  Copyright (C) 2004-2011  Marcel Holtmann <marcel (at) holtmann.org>
      6  *
      7  *
      8  *  This program is free software; you can redistribute it and/or modify
      9  *  it under the terms of the GNU General Public License as published by
     10  *  the Free Software Foundation; either version 2 of the License, or
     11  *  (at your option) any later version.
     12  *
     13  *  This program is distributed in the hope that it will be useful,
     14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *  GNU General Public License for more details.
     17  *
     18  *  You should have received a copy of the GNU General Public License
     19  *  along with this program; if not, write to the Free Software
     20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 
     28 #include <errno.h>
     29 
     30 #include <dbus/dbus.h>
     31 
     32 #include <glib.h>
     33 
     34 int polkit_check_authorization(DBusConnection *conn,
     35 				const char *action, gboolean interaction,
     36 				void (*function) (dbus_bool_t authorized,
     37 							void *user_data),
     38 						void *user_data, int timeout);
     39 
     40 static void add_dict_with_string_value(DBusMessageIter *iter,
     41 					const char *key, const char *str)
     42 {
     43 	DBusMessageIter dict, entry, value;
     44 
     45 	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
     46 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
     47 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
     48 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
     49 	dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
     50 								NULL, &entry);
     51 
     52 	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
     53 
     54 	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
     55 					DBUS_TYPE_STRING_AS_STRING, &value);
     56 	dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
     57 	dbus_message_iter_close_container(&entry, &value);
     58 
     59 	dbus_message_iter_close_container(&dict, &entry);
     60 	dbus_message_iter_close_container(iter, &dict);
     61 }
     62 
     63 static void add_empty_string_dict(DBusMessageIter *iter)
     64 {
     65 	DBusMessageIter dict;
     66 
     67 	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
     68 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
     69 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
     70 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
     71 
     72 	dbus_message_iter_close_container(iter, &dict);
     73 }
     74 
     75 static void add_arguments(DBusConnection *conn, DBusMessageIter *iter,
     76 				const char *action, dbus_uint32_t flags)
     77 {
     78 	const char *busname = dbus_bus_get_unique_name(conn);
     79 	const char *kind = "system-bus-name";
     80 	const char *cancel = "";
     81 	DBusMessageIter subject;
     82 
     83 	dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
     84 							NULL, &subject);
     85 	dbus_message_iter_append_basic(&subject, DBUS_TYPE_STRING, &kind);
     86 	add_dict_with_string_value(&subject, "name", busname);
     87 	dbus_message_iter_close_container(iter, &subject);
     88 
     89 	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &action);
     90 	add_empty_string_dict(iter);
     91 	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &flags);
     92 	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cancel);
     93 }
     94 
     95 static dbus_bool_t parse_result(DBusMessageIter *iter)
     96 {
     97 	DBusMessageIter result;
     98 	dbus_bool_t authorized, challenge;
     99 
    100 	dbus_message_iter_recurse(iter, &result);
    101 
    102 	dbus_message_iter_get_basic(&result, &authorized);
    103 	dbus_message_iter_get_basic(&result, &challenge);
    104 
    105 	return authorized;
    106 }
    107 
    108 struct authorization_data {
    109 	void (*function) (dbus_bool_t authorized, void *user_data);
    110 	void *user_data;
    111 };
    112 
    113 static void authorization_reply(DBusPendingCall *call, void *user_data)
    114 {
    115 	struct authorization_data *data = user_data;
    116 	DBusMessage *reply;
    117 	DBusMessageIter iter;
    118 	dbus_bool_t authorized = FALSE;
    119 
    120 	reply = dbus_pending_call_steal_reply(call);
    121 
    122 	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
    123 		goto done;
    124 
    125 	if (dbus_message_has_signature(reply, "(bba{ss})") == FALSE)
    126 		goto done;
    127 
    128 	dbus_message_iter_init(reply, &iter);
    129 
    130 	authorized = parse_result(&iter);
    131 
    132 done:
    133 	if (data->function != NULL)
    134 		data->function(authorized, data->user_data);
    135 
    136 	dbus_message_unref(reply);
    137 
    138 	dbus_pending_call_unref(call);
    139 }
    140 
    141 #define AUTHORITY_DBUS	"org.freedesktop.PolicyKit1"
    142 #define AUTHORITY_INTF	"org.freedesktop.PolicyKit1.Authority"
    143 #define AUTHORITY_PATH	"/org/freedesktop/PolicyKit1/Authority"
    144 
    145 int polkit_check_authorization(DBusConnection *conn,
    146 				const char *action, gboolean interaction,
    147 				void (*function) (dbus_bool_t authorized,
    148 							void *user_data),
    149 						void *user_data, int timeout)
    150 {
    151 	struct authorization_data *data;
    152 	DBusMessage *msg;
    153 	DBusMessageIter iter;
    154 	DBusPendingCall *call;
    155 	dbus_uint32_t flags = 0x00000000;
    156 
    157 	if (conn == NULL)
    158 		return -EINVAL;
    159 
    160 	data = dbus_malloc0(sizeof(*data));
    161 	if (data == NULL)
    162 		return -ENOMEM;
    163 
    164 	msg = dbus_message_new_method_call(AUTHORITY_DBUS, AUTHORITY_PATH,
    165 				AUTHORITY_INTF, "CheckAuthorization");
    166 	if (msg == NULL) {
    167 		dbus_free(data);
    168 		return -ENOMEM;
    169 	}
    170 
    171 	if (interaction == TRUE)
    172 		flags |= 0x00000001;
    173 
    174 	if (action == NULL)
    175 		action = "org.freedesktop.policykit.exec";
    176 
    177 	dbus_message_iter_init_append(msg, &iter);
    178 	add_arguments(conn, &iter, action, flags);
    179 
    180 	if (dbus_connection_send_with_reply(conn, msg,
    181 						&call, timeout) == FALSE) {
    182 		dbus_message_unref(msg);
    183 		dbus_free(data);
    184 		return -EIO;
    185 	}
    186 
    187 	if (call == NULL) {
    188 		dbus_message_unref(msg);
    189 		dbus_free(data);
    190 		return -EIO;
    191 	}
    192 
    193 	data->function = function;
    194 	data->user_data = user_data;
    195 
    196 	dbus_pending_call_set_notify(call, authorization_reply,
    197 							data, dbus_free);
    198 
    199 	dbus_message_unref(msg);
    200 
    201 	return 0;
    202 }
    203