console-kit: Ignore unrequested messages from dbus
[vd_agent.git] / src / console-kit.c
blobc7e60df0d14eb0381e19dbaa315f12963cf7e962
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 member = dbus_message_get_member (message);
113 if (g_strcmp0(member, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED) == 0) {
114 DBusMessageIter iter;
115 gint type;
116 gchar *session;
118 free(info->active_session);
119 info->active_session = NULL;
121 dbus_message_iter_init(message, &iter);
122 type = dbus_message_iter_get_arg_type(&iter);
123 /* Session should be an object path, but there is a bug in
124 ConsoleKit where it sends a string rather then an object_path
125 accept object_path too in case the bug ever gets fixed */
126 if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
127 dbus_message_iter_get_basic(&iter, &session);
128 if (session != NULL && session[0] != '\0') {
129 info->active_session = g_strdup(session);
130 } else {
131 syslog(LOG_WARNING, "(console-kit) received invalid session. "
132 "No active-session at the moment");
134 } else {
135 syslog(LOG_ERR,
136 "ActiveSessionChanged message has unexpected type: '%c'",
137 type);
139 } else {
140 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
141 syslog(LOG_WARNING, "(console-kit) received non signal message");
142 } else if (info->verbose) {
143 syslog(LOG_DEBUG, "(console-kit) Signal not handled: %s", member);
147 dbus_message_unref(message);
148 dbus_connection_read_write(info->connection, 0);
149 message = dbus_connection_pop_message(info->connection);
153 struct session_info *session_info_create(int verbose)
155 struct session_info *info;
156 DBusError error;
158 info = calloc(1, sizeof(*info));
159 if (!info)
160 return NULL;
162 info->verbose = verbose;
164 dbus_error_init(&error);
165 info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
166 if (info->connection == NULL || dbus_error_is_set(&error)) {
167 if (dbus_error_is_set(&error)) {
168 syslog(LOG_ERR, "Unable to connect to system bus: %s",
169 error.message);
170 dbus_error_free(&error);
171 } else
172 syslog(LOG_ERR, "Unable to connect to system bus");
173 free(info);
174 return NULL;
177 if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) {
178 syslog(LOG_ERR, "Unable to get connection fd");
179 session_info_destroy(info);
180 return NULL;
183 if (!console_kit_get_first_seat(info)) {
184 session_info_destroy(info);
185 return NULL;
188 si_dbus_match_rule_update(info);
189 return info;
192 void session_info_destroy(struct session_info *info)
194 if (!info)
195 return;
197 si_dbus_match_remove(info);
198 dbus_connection_close(info->connection);
199 free(info->seat);
200 free(info->active_session);
201 free(info);
204 int session_info_get_fd(struct session_info *info)
206 return info->fd;
209 static char *console_kit_get_first_seat(struct session_info *info)
211 DBusError error;
212 DBusMessage *message = NULL;
213 DBusMessage *reply = NULL;
214 DBusMessageIter iter, subiter;
215 int type;
216 char *seat = NULL;
219 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
220 OBJ_PATH_CONSOLE_KIT_MANAGER,
221 INTERFACE_CONSOLE_KIT_MANAGER,
222 "GetSeats");
223 if (message == NULL) {
224 syslog(LOG_ERR, "Unable to create dbus message");
225 goto exit;
228 dbus_error_init(&error);
229 reply = dbus_connection_send_with_reply_and_block(info->connection,
230 message,
232 &error);
233 if (reply == NULL || dbus_error_is_set(&error)) {
234 if (dbus_error_is_set(&error)) {
235 syslog(LOG_ERR, "GetSeats failed: %s", error.message);
236 dbus_error_free(&error);
237 } else
238 syslog(LOG_ERR, "GetSeats failed");
239 goto exit;
242 dbus_message_iter_init(reply, &iter);
243 type = dbus_message_iter_get_arg_type(&iter);
244 if (type != DBUS_TYPE_ARRAY) {
245 syslog(LOG_ERR,
246 "expected an array return value, got a '%c' instead", type);
247 goto exit;
250 dbus_message_iter_recurse(&iter, &subiter);
251 type = dbus_message_iter_get_arg_type(&subiter);
252 if (type != DBUS_TYPE_OBJECT_PATH) {
253 syslog(LOG_ERR,
254 "expected an object path element, got a '%c' instead", type);
255 goto exit;
258 dbus_message_iter_get_basic(&subiter, &seat);
259 info->seat = strdup(seat);
261 exit:
262 if (reply != NULL) {
263 dbus_message_unref(reply);
266 if (message != NULL) {
267 dbus_message_unref(message);
270 syslog(LOG_INFO, "(console-kit) seat: %s", info->seat);
271 return info->seat;
274 const char *session_info_get_active_session(struct session_info *info)
276 DBusError error;
277 DBusMessage *message = NULL;
278 DBusMessage *reply = NULL;
279 char *session = NULL;
281 if (!info)
282 return NULL;
284 if (info->active_session)
285 return console_kit_check_active_session_change(info);
287 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
288 info->seat,
289 INTERFACE_CONSOLE_KIT_SEAT,
290 "GetActiveSession");
291 if (message == NULL) {
292 syslog(LOG_ERR, "Unable to create dbus message");
293 goto exit;
296 dbus_error_init(&error);
297 reply = dbus_connection_send_with_reply_and_block(info->connection,
298 message,
300 &error);
301 if (reply == NULL || dbus_error_is_set(&error)) {
302 if (dbus_error_is_set(&error)) {
303 syslog(LOG_ERR, "GetActiveSession failed: %s", error.message);
304 dbus_error_free(&error);
305 } else
306 syslog(LOG_ERR, "GetActiveSession failed");
307 goto exit;
310 dbus_error_init(&error);
311 if (!dbus_message_get_args(reply,
312 &error,
313 DBUS_TYPE_OBJECT_PATH, &session,
314 DBUS_TYPE_INVALID)) {
315 if (dbus_error_is_set(&error)) {
316 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
317 dbus_error_free(&error);
318 } else
319 syslog(LOG_ERR, "error getting ssid from reply");
320 session = NULL;
321 goto exit;
324 info->active_session = strdup(session);
326 exit:
327 if (reply != NULL) {
328 dbus_message_unref(reply);
331 if (message != NULL) {
332 dbus_message_unref(message);
335 /* In case the session was changed while we were running */
336 return console_kit_check_active_session_change(info);
339 char *session_info_session_for_pid(struct session_info *info, uint32_t pid)
341 DBusError error;
342 DBusMessage *message = NULL;
343 DBusMessage *reply = NULL;
344 DBusMessageIter args;
345 char *ssid = NULL;
347 if (!info)
348 return NULL;
350 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
351 OBJ_PATH_CONSOLE_KIT_MANAGER,
352 INTERFACE_CONSOLE_KIT_MANAGER,
353 "GetSessionForUnixProcess");
354 if (message == NULL) {
355 syslog(LOG_ERR, "Unable to create dbus message");
356 goto exit;
359 dbus_message_iter_init_append(message, &args);
360 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
361 syslog(LOG_ERR, "Unable to append dbus message args");
362 goto exit;
365 dbus_error_init(&error);
366 reply = dbus_connection_send_with_reply_and_block(info->connection,
367 message,
369 &error);
370 if (reply == NULL || dbus_error_is_set(&error)) {
371 if (dbus_error_is_set(&error)) {
372 syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
373 error.message);
374 dbus_error_free(&error);
375 } else
376 syslog(LOG_ERR, "GetSessionForUnixProces failed");
377 goto exit;
380 dbus_error_init(&error);
381 if (!dbus_message_get_args(reply,
382 &error,
383 DBUS_TYPE_OBJECT_PATH, &ssid,
384 DBUS_TYPE_INVALID)) {
385 if (dbus_error_is_set(&error)) {
386 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
387 dbus_error_free(&error);
388 } else
389 syslog(LOG_ERR, "error getting ssid from reply");
390 ssid = NULL;
391 goto exit;
394 ssid = strdup(ssid);
396 exit:
397 if (reply != NULL) {
398 dbus_message_unref(reply);
401 if (message != NULL) {
402 dbus_message_unref(message);
405 return ssid;
408 static char *console_kit_check_active_session_change(struct session_info *info)
410 si_dbus_read_signals(info);
411 if (info->verbose)
412 syslog(LOG_DEBUG, "(console-kit) active-session: '%s'",
413 (info->active_session ? info->active_session : "None"));
415 return info->active_session;