console-kit: include handler for dbus match
[vd_agent.git] / src / console-kit.c
blobd4eecd7838d439055851a16715bf0f00f9edf27c
1 /* console-kit.c vdagentd ConsoleKit integration code
3 Copyright 2010-2012 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
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 3 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "session-info.h"
23 #include <dbus/dbus.h>
24 #include <stdbool.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <syslog.h>
29 #include <glib.h>
31 struct session_info {
32 DBusConnection *connection;
33 int fd;
34 char *seat;
35 char *active_session;
36 int verbose;
37 gchar *match_seat_signals;
40 #define INTERFACE_CONSOLE_KIT "org.freedesktop.ConsoleKit"
41 #define OBJ_PATH_CONSOLE_KIT "/org/freedesktop/ConsoleKit"
43 #define INTERFACE_CONSOLE_KIT_MANAGER INTERFACE_CONSOLE_KIT ".Manager"
44 #define OBJ_PATH_CONSOLE_KIT_MANAGER OBJ_PATH_CONSOLE_KIT "/Manager"
46 #define INTERFACE_CONSOLE_KIT_SEAT INTERFACE_CONSOLE_KIT ".Seat"
48 #define SEAT_SIGNAL_ACTIVE_SESSION_CHANGED "ActiveSessionChanged"
50 static char *console_kit_get_first_seat(struct session_info *info);
51 static char *console_kit_check_active_session_change(struct session_info *info);
53 static void si_dbus_match_remove(struct session_info *info)
55 DBusError error;
56 if (info->match_seat_signals != NULL) {
57 dbus_error_init(&error);
58 dbus_bus_remove_match(info->connection,
59 info->match_seat_signals,
60 &error);
61 if (info->verbose)
62 syslog(LOG_DEBUG, "(console-kit) seat match removed: %s",
63 info->match_seat_signals);
64 g_free(info->match_seat_signals);
65 info->match_seat_signals = NULL;
69 static void si_dbus_match_rule_update(struct session_info *info)
71 DBusError error;
73 if (info->connection == NULL)
74 return;
76 si_dbus_match_remove(info);
78 /* Seat signals */
79 if (info->seat != NULL) {
80 info->match_seat_signals =
81 g_strdup_printf ("type='signal',interface='%s',path='%s',"
82 "member='ActiveSessionChanged'",
83 INTERFACE_CONSOLE_KIT_SEAT,
84 info->seat);
85 if (info->verbose)
86 syslog(LOG_DEBUG, "(console-kit) seat match: %s",
87 info->match_seat_signals);
89 dbus_error_init(&error);
90 dbus_bus_add_match(info->connection,
91 info->match_seat_signals,
92 &error);
93 if (dbus_error_is_set(&error)) {
94 syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
95 error.message);
96 dbus_error_free(&error);
97 g_free(info->match_seat_signals);
102 static void
103 si_dbus_read_signals(struct session_info *info)
105 DBusMessage *message = NULL;
107 dbus_connection_read_write(info->connection, 0);
108 message = dbus_connection_pop_message(info->connection);
109 while (message != NULL) {
110 const char *member;
112 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
113 syslog(LOG_WARNING, "(console-kit) received non signal message");
114 dbus_message_unref(message);
115 break;
118 member = dbus_message_get_member (message);
119 if (g_strcmp0(member, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED) == 0) {
120 DBusMessageIter iter;
121 gint type;
122 gchar *session;
124 free(info->active_session);
125 info->active_session = NULL;
127 dbus_message_iter_init(message, &iter);
128 type = dbus_message_iter_get_arg_type(&iter);
129 /* Session should be an object path, but there is a bug in
130 ConsoleKit where it sends a string rather then an object_path
131 accept object_path too in case the bug ever gets fixed */
132 if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
133 dbus_message_iter_get_basic(&iter, &session);
134 if (session != NULL && session[0] != '\0') {
135 info->active_session = g_strdup(session);
136 } else {
137 syslog(LOG_WARNING, "(console-kit) received invalid session. "
138 "No active-session at the moment");
140 } else {
141 syslog(LOG_ERR,
142 "ActiveSessionChanged message has unexpected type: '%c'",
143 type);
145 } else if (info->verbose) {
146 syslog(LOG_DEBUG, "(console-kit) Signal not handled: %s", member);
149 dbus_message_unref(message);
150 dbus_connection_read_write(info->connection, 0);
151 message = dbus_connection_pop_message(info->connection);
155 struct session_info *session_info_create(int verbose)
157 struct session_info *info;
158 DBusError error;
160 info = calloc(1, sizeof(*info));
161 if (!info)
162 return NULL;
164 info->verbose = verbose;
166 dbus_error_init(&error);
167 info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
168 if (info->connection == NULL || dbus_error_is_set(&error)) {
169 if (dbus_error_is_set(&error)) {
170 syslog(LOG_ERR, "Unable to connect to system bus: %s",
171 error.message);
172 dbus_error_free(&error);
173 } else
174 syslog(LOG_ERR, "Unable to connect to system bus");
175 free(info);
176 return NULL;
179 if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) {
180 syslog(LOG_ERR, "Unable to get connection fd");
181 session_info_destroy(info);
182 return NULL;
185 if (!console_kit_get_first_seat(info)) {
186 session_info_destroy(info);
187 return NULL;
190 si_dbus_match_rule_update(info);
191 return info;
194 void session_info_destroy(struct session_info *info)
196 if (!info)
197 return;
199 si_dbus_match_remove(info);
200 dbus_connection_close(info->connection);
201 free(info->seat);
202 free(info->active_session);
203 free(info);
206 int session_info_get_fd(struct session_info *info)
208 return info->fd;
211 static char *console_kit_get_first_seat(struct session_info *info)
213 DBusError error;
214 DBusMessage *message = NULL;
215 DBusMessage *reply = NULL;
216 DBusMessageIter iter, subiter;
217 int type;
218 char *seat = NULL;
221 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
222 OBJ_PATH_CONSOLE_KIT_MANAGER,
223 INTERFACE_CONSOLE_KIT_MANAGER,
224 "GetSeats");
225 if (message == NULL) {
226 syslog(LOG_ERR, "Unable to create dbus message");
227 goto exit;
230 dbus_error_init(&error);
231 reply = dbus_connection_send_with_reply_and_block(info->connection,
232 message,
234 &error);
235 if (reply == NULL || dbus_error_is_set(&error)) {
236 if (dbus_error_is_set(&error)) {
237 syslog(LOG_ERR, "GetSeats failed: %s", error.message);
238 dbus_error_free(&error);
239 } else
240 syslog(LOG_ERR, "GetSeats failed");
241 goto exit;
244 dbus_message_iter_init(reply, &iter);
245 type = dbus_message_iter_get_arg_type(&iter);
246 if (type != DBUS_TYPE_ARRAY) {
247 syslog(LOG_ERR,
248 "expected an array return value, got a '%c' instead", type);
249 goto exit;
252 dbus_message_iter_recurse(&iter, &subiter);
253 type = dbus_message_iter_get_arg_type(&subiter);
254 if (type != DBUS_TYPE_OBJECT_PATH) {
255 syslog(LOG_ERR,
256 "expected an object path element, got a '%c' instead", type);
257 goto exit;
260 dbus_message_iter_get_basic(&subiter, &seat);
261 info->seat = strdup(seat);
263 exit:
264 if (reply != NULL) {
265 dbus_message_unref(reply);
268 if (message != NULL) {
269 dbus_message_unref(message);
272 syslog(LOG_INFO, "(console-kit) seat: %s", info->seat);
273 return info->seat;
276 const char *session_info_get_active_session(struct session_info *info)
278 DBusError error;
279 DBusMessage *message = NULL;
280 DBusMessage *reply = NULL;
281 char *session = NULL;
283 if (!info)
284 return NULL;
286 if (info->active_session)
287 return console_kit_check_active_session_change(info);
289 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
290 info->seat,
291 INTERFACE_CONSOLE_KIT_SEAT,
292 "GetActiveSession");
293 if (message == NULL) {
294 syslog(LOG_ERR, "Unable to create dbus message");
295 goto exit;
298 dbus_error_init(&error);
299 reply = dbus_connection_send_with_reply_and_block(info->connection,
300 message,
302 &error);
303 if (reply == NULL || dbus_error_is_set(&error)) {
304 if (dbus_error_is_set(&error)) {
305 syslog(LOG_ERR, "GetActiveSession failed: %s", error.message);
306 dbus_error_free(&error);
307 } else
308 syslog(LOG_ERR, "GetActiveSession failed");
309 goto exit;
312 dbus_error_init(&error);
313 if (!dbus_message_get_args(reply,
314 &error,
315 DBUS_TYPE_OBJECT_PATH, &session,
316 DBUS_TYPE_INVALID)) {
317 if (dbus_error_is_set(&error)) {
318 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
319 dbus_error_free(&error);
320 } else
321 syslog(LOG_ERR, "error getting ssid from reply");
322 session = NULL;
323 goto exit;
326 info->active_session = strdup(session);
328 exit:
329 if (reply != NULL) {
330 dbus_message_unref(reply);
333 if (message != NULL) {
334 dbus_message_unref(message);
337 /* In case the session was changed while we were running */
338 return console_kit_check_active_session_change(info);
341 char *session_info_session_for_pid(struct session_info *info, uint32_t pid)
343 DBusError error;
344 DBusMessage *message = NULL;
345 DBusMessage *reply = NULL;
346 DBusMessageIter args;
347 char *ssid = NULL;
349 if (!info)
350 return NULL;
352 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
353 OBJ_PATH_CONSOLE_KIT_MANAGER,
354 INTERFACE_CONSOLE_KIT_MANAGER,
355 "GetSessionForUnixProcess");
356 if (message == NULL) {
357 syslog(LOG_ERR, "Unable to create dbus message");
358 goto exit;
361 dbus_message_iter_init_append(message, &args);
362 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
363 syslog(LOG_ERR, "Unable to append dbus message args");
364 goto exit;
367 dbus_error_init(&error);
368 reply = dbus_connection_send_with_reply_and_block(info->connection,
369 message,
371 &error);
372 if (reply == NULL || dbus_error_is_set(&error)) {
373 if (dbus_error_is_set(&error)) {
374 syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
375 error.message);
376 dbus_error_free(&error);
377 } else
378 syslog(LOG_ERR, "GetSessionForUnixProces failed");
379 goto exit;
382 dbus_error_init(&error);
383 if (!dbus_message_get_args(reply,
384 &error,
385 DBUS_TYPE_OBJECT_PATH, &ssid,
386 DBUS_TYPE_INVALID)) {
387 if (dbus_error_is_set(&error)) {
388 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
389 dbus_error_free(&error);
390 } else
391 syslog(LOG_ERR, "error getting ssid from reply");
392 ssid = NULL;
393 goto exit;
396 ssid = strdup(ssid);
398 exit:
399 if (reply != NULL) {
400 dbus_message_unref(reply);
403 if (message != NULL) {
404 dbus_message_unref(message);
407 return ssid;
410 static char *console_kit_check_active_session_change(struct session_info *info)
412 si_dbus_read_signals(info);
413 if (info->verbose)
414 syslog(LOG_DEBUG, "(console-kit) active-session: '%s'",
415 (info->active_session ? info->active_session : "None"));
417 return info->active_session;