1/* 2 * 3 * D-Bus helper library 4 * 5 * Copyright (C) 2004-2011 Marcel Holtmann <marcel@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 34int 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 40static 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 63static 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 75static 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 95static 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 108struct authorization_data { 109 void (*function) (dbus_bool_t authorized, void *user_data); 110 void *user_data; 111}; 112 113static 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 132done: 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 145int 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