build-sys: move user/system to respective dir
[vd_agent.git] / src / vdagentd / console-kit.c
blob024a2602a1e3bd37fd59b662894bb8d952c25f60
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;
38 gchar *match_session_signals;
39 gboolean session_is_locked;
40 gboolean session_idle_hint;
43 #define INTERFACE_CONSOLE_KIT "org.freedesktop.ConsoleKit"
44 #define OBJ_PATH_CONSOLE_KIT "/org/freedesktop/ConsoleKit"
46 #define INTERFACE_CONSOLE_KIT_MANAGER INTERFACE_CONSOLE_KIT ".Manager"
47 #define OBJ_PATH_CONSOLE_KIT_MANAGER OBJ_PATH_CONSOLE_KIT "/Manager"
49 #define INTERFACE_CONSOLE_KIT_SEAT INTERFACE_CONSOLE_KIT ".Seat"
51 #define INTERFACE_CONSOLE_KIT_SESSION INTERFACE_CONSOLE_KIT ".Session"
52 #define OBJ_PATH_CONSOLE_KIT_SESSION OBJ_PATH_CONSOLE_KIT "/Session"
54 #define SEAT_SIGNAL_ACTIVE_SESSION_CHANGED "ActiveSessionChanged"
56 #define SESSION_SIGNAL_LOCK "Lock"
57 #define SESSION_SIGNAL_UNLOCK "Unlock"
58 #define SESSION_SIGNAL_IDLE_HINT_CHANGED "IdleHintChanged"
60 static char *console_kit_get_first_seat(struct session_info *info);
61 static char *console_kit_check_active_session_change(struct session_info *info);
63 static void si_dbus_match_remove(struct session_info *info)
65 DBusError error;
66 if (info->match_seat_signals != NULL) {
67 dbus_error_init(&error);
68 dbus_bus_remove_match(info->connection,
69 info->match_seat_signals,
70 &error);
71 if (info->verbose)
72 syslog(LOG_DEBUG, "(console-kit) seat match removed: %s",
73 info->match_seat_signals);
74 g_free(info->match_seat_signals);
75 info->match_seat_signals = NULL;
78 if (info->match_session_signals != NULL) {
79 dbus_error_init(&error);
80 dbus_bus_remove_match(info->connection,
81 info->match_session_signals,
82 &error);
84 if (info->verbose)
85 syslog(LOG_DEBUG, "(console-kit) session match removed: %s",
86 info->match_session_signals);
87 g_free(info->match_session_signals);
88 info->match_session_signals = NULL;
92 static void si_dbus_match_rule_update(struct session_info *info)
94 DBusError error;
96 if (info->connection == NULL)
97 return;
99 si_dbus_match_remove(info);
101 /* Seat signals */
102 if (info->seat != NULL) {
103 info->match_seat_signals =
104 g_strdup_printf ("type='signal',interface='%s',path='%s',"
105 "member='ActiveSessionChanged'",
106 INTERFACE_CONSOLE_KIT_SEAT,
107 info->seat);
108 if (info->verbose)
109 syslog(LOG_DEBUG, "(console-kit) seat match: %s",
110 info->match_seat_signals);
112 dbus_error_init(&error);
113 dbus_bus_add_match(info->connection,
114 info->match_seat_signals,
115 &error);
116 if (dbus_error_is_set(&error)) {
117 syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
118 error.message);
119 dbus_error_free(&error);
120 g_free(info->match_seat_signals);
121 info->match_seat_signals = NULL;
125 /* Session signals */
126 if (info->active_session != NULL) {
127 info->match_session_signals =
128 g_strdup_printf ("type='signal',interface='%s',path='%s'",
129 INTERFACE_CONSOLE_KIT_SESSION,
130 info->active_session);
131 if (info->verbose)
132 syslog(LOG_DEBUG, "(console-kit) session match: %s",
133 info->match_session_signals);
135 dbus_error_init(&error);
136 dbus_bus_add_match(info->connection,
137 info->match_session_signals,
138 &error);
139 if (dbus_error_is_set(&error)) {
140 syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
141 error.message);
142 dbus_error_free(&error);
143 g_free(info->match_session_signals);
144 info->match_session_signals = NULL;
149 static void
150 si_dbus_read_signals(struct session_info *info)
152 DBusMessage *message = NULL;
154 dbus_connection_read_write(info->connection, 0);
155 message = dbus_connection_pop_message(info->connection);
156 while (message != NULL) {
157 const char *member;
159 member = dbus_message_get_member (message);
160 if (g_strcmp0(member, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED) == 0) {
161 DBusMessageIter iter;
162 gint type;
163 gchar *session;
165 free(info->active_session);
166 info->active_session = NULL;
168 dbus_message_iter_init(message, &iter);
169 type = dbus_message_iter_get_arg_type(&iter);
170 /* Session should be an object path, but there is a bug in
171 ConsoleKit where it sends a string rather then an object_path
172 accept object_path too in case the bug ever gets fixed */
173 if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
174 dbus_message_iter_get_basic(&iter, &session);
175 if (session != NULL && session[0] != '\0') {
176 info->active_session = g_strdup(session);
177 si_dbus_match_rule_update(info);
178 } else {
179 syslog(LOG_WARNING, "(console-kit) received invalid session. "
180 "No active-session at the moment");
182 } else {
183 syslog(LOG_ERR,
184 "ActiveSessionChanged message has unexpected type: '%c'",
185 type);
187 } else if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
188 info->session_is_locked = TRUE;
189 } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
190 info->session_is_locked = FALSE;
191 } else if (g_strcmp0(member, SESSION_SIGNAL_IDLE_HINT_CHANGED) == 0) {
192 DBusMessageIter iter;
193 gint type;
194 dbus_bool_t idle_hint;
196 dbus_message_iter_init(message, &iter);
197 type = dbus_message_iter_get_arg_type(&iter);
198 if (type == DBUS_TYPE_BOOLEAN) {
199 dbus_message_iter_get_basic(&iter, &idle_hint);
200 info->session_idle_hint = (idle_hint);
201 } else {
202 syslog(LOG_ERR,
203 "(console-kit) IdleHintChanged has unexpected type: '%c'",
204 type);
206 } else {
207 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
208 syslog(LOG_WARNING, "(console-kit) received non signal message");
209 } else if (info->verbose) {
210 syslog(LOG_DEBUG, "(console-kit) Signal not handled: %s", member);
214 dbus_message_unref(message);
215 dbus_connection_read_write(info->connection, 0);
216 message = dbus_connection_pop_message(info->connection);
220 struct session_info *session_info_create(int verbose)
222 struct session_info *info;
223 DBusError error;
225 info = calloc(1, sizeof(*info));
226 if (!info)
227 return NULL;
229 info->verbose = verbose;
230 info->session_is_locked = FALSE;
231 info->session_idle_hint = FALSE;
233 dbus_error_init(&error);
234 info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
235 if (info->connection == NULL || dbus_error_is_set(&error)) {
236 if (dbus_error_is_set(&error)) {
237 syslog(LOG_ERR, "Unable to connect to system bus: %s",
238 error.message);
239 dbus_error_free(&error);
240 } else
241 syslog(LOG_ERR, "Unable to connect to system bus");
242 free(info);
243 return NULL;
246 if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) {
247 syslog(LOG_ERR, "Unable to get connection fd");
248 session_info_destroy(info);
249 return NULL;
252 if (!console_kit_get_first_seat(info)) {
253 session_info_destroy(info);
254 return NULL;
257 si_dbus_match_rule_update(info);
258 return info;
261 void session_info_destroy(struct session_info *info)
263 if (!info)
264 return;
266 si_dbus_match_remove(info);
267 dbus_connection_close(info->connection);
268 free(info->seat);
269 free(info->active_session);
270 free(info);
273 int session_info_get_fd(struct session_info *info)
275 return info->fd;
278 static char *console_kit_get_first_seat(struct session_info *info)
280 DBusError error;
281 DBusMessage *message = NULL;
282 DBusMessage *reply = NULL;
283 DBusMessageIter iter, subiter;
284 int type;
285 char *seat = NULL;
288 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
289 OBJ_PATH_CONSOLE_KIT_MANAGER,
290 INTERFACE_CONSOLE_KIT_MANAGER,
291 "GetSeats");
292 if (message == NULL) {
293 syslog(LOG_ERR, "Unable to create dbus message");
294 goto exit;
297 dbus_error_init(&error);
298 reply = dbus_connection_send_with_reply_and_block(info->connection,
299 message,
301 &error);
302 if (reply == NULL || dbus_error_is_set(&error)) {
303 if (dbus_error_is_set(&error)) {
304 syslog(LOG_ERR, "GetSeats failed: %s", error.message);
305 dbus_error_free(&error);
306 } else
307 syslog(LOG_ERR, "GetSeats failed");
308 goto exit;
311 dbus_message_iter_init(reply, &iter);
312 type = dbus_message_iter_get_arg_type(&iter);
313 if (type != DBUS_TYPE_ARRAY) {
314 syslog(LOG_ERR,
315 "expected an array return value, got a '%c' instead", type);
316 goto exit;
319 dbus_message_iter_recurse(&iter, &subiter);
320 type = dbus_message_iter_get_arg_type(&subiter);
321 if (type != DBUS_TYPE_OBJECT_PATH) {
322 syslog(LOG_ERR,
323 "expected an object path element, got a '%c' instead", type);
324 goto exit;
327 dbus_message_iter_get_basic(&subiter, &seat);
328 info->seat = strdup(seat);
330 exit:
331 if (reply != NULL) {
332 dbus_message_unref(reply);
335 if (message != NULL) {
336 dbus_message_unref(message);
339 syslog(LOG_INFO, "(console-kit) seat: %s", info->seat);
340 return info->seat;
343 const char *session_info_get_active_session(struct session_info *info)
345 DBusError error;
346 DBusMessage *message = NULL;
347 DBusMessage *reply = NULL;
348 char *session = NULL;
350 if (!info)
351 return NULL;
353 if (info->active_session)
354 return console_kit_check_active_session_change(info);
356 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
357 info->seat,
358 INTERFACE_CONSOLE_KIT_SEAT,
359 "GetActiveSession");
360 if (message == NULL) {
361 syslog(LOG_ERR, "Unable to create dbus message");
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, "GetActiveSession failed: %s", error.message);
373 dbus_error_free(&error);
374 } else
375 syslog(LOG_ERR, "GetActiveSession failed");
376 goto exit;
379 dbus_error_init(&error);
380 if (!dbus_message_get_args(reply,
381 &error,
382 DBUS_TYPE_OBJECT_PATH, &session,
383 DBUS_TYPE_INVALID)) {
384 if (dbus_error_is_set(&error)) {
385 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
386 dbus_error_free(&error);
387 } else
388 syslog(LOG_ERR, "error getting ssid from reply");
389 session = NULL;
390 goto exit;
393 info->active_session = strdup(session);
394 si_dbus_match_rule_update(info);
396 exit:
397 if (reply != NULL) {
398 dbus_message_unref(reply);
401 if (message != NULL) {
402 dbus_message_unref(message);
405 /* In case the session was changed while we were running */
406 return console_kit_check_active_session_change(info);
409 char *session_info_session_for_pid(struct session_info *info, uint32_t pid)
411 DBusError error;
412 DBusMessage *message = NULL;
413 DBusMessage *reply = NULL;
414 DBusMessageIter args;
415 char *ssid = NULL;
417 if (!info)
418 return NULL;
420 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
421 OBJ_PATH_CONSOLE_KIT_MANAGER,
422 INTERFACE_CONSOLE_KIT_MANAGER,
423 "GetSessionForUnixProcess");
424 if (message == NULL) {
425 syslog(LOG_ERR, "Unable to create dbus message");
426 goto exit;
429 dbus_message_iter_init_append(message, &args);
430 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
431 syslog(LOG_ERR, "Unable to append dbus message args");
432 goto exit;
435 dbus_error_init(&error);
436 reply = dbus_connection_send_with_reply_and_block(info->connection,
437 message,
439 &error);
440 if (reply == NULL || dbus_error_is_set(&error)) {
441 if (dbus_error_is_set(&error)) {
442 syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
443 error.message);
444 dbus_error_free(&error);
445 } else
446 syslog(LOG_ERR, "GetSessionForUnixProces failed");
447 goto exit;
450 dbus_error_init(&error);
451 if (!dbus_message_get_args(reply,
452 &error,
453 DBUS_TYPE_OBJECT_PATH, &ssid,
454 DBUS_TYPE_INVALID)) {
455 if (dbus_error_is_set(&error)) {
456 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
457 dbus_error_free(&error);
458 } else
459 syslog(LOG_ERR, "error getting ssid from reply");
460 ssid = NULL;
461 goto exit;
464 ssid = strdup(ssid);
466 exit:
467 if (reply != NULL) {
468 dbus_message_unref(reply);
471 if (message != NULL) {
472 dbus_message_unref(message);
475 return ssid;
478 static char *console_kit_check_active_session_change(struct session_info *info)
480 si_dbus_read_signals(info);
481 if (info->verbose)
482 syslog(LOG_DEBUG, "(console-kit) active-session: '%s'",
483 (info->active_session ? info->active_session : "None"));
485 return info->active_session;
488 gboolean session_info_session_is_locked(struct session_info *info)
490 gboolean locked;
492 g_return_val_if_fail (info != NULL, FALSE);
494 /* Not every system does emit Lock and Unlock signals (for instance, such
495 * is the case for RHEL6) but most of the systems seems to emit the
496 * IdleHintChanged. So, we give priority to the Lock signal, if it is Locked
497 * we return that the session is locked, otherwise we double check with the
498 * IdleHint value */
499 si_dbus_read_signals(info);
500 locked = (info->session_is_locked || info->session_idle_hint);
501 if (info->verbose) {
502 syslog(LOG_DEBUG, "(console-kit) session is locked: %s",
503 locked ? "yes" : "no");
505 return locked;
508 /* This function should only be called after session_info_get_active_session
509 * in order to verify if active session belongs to user (non greeter) */
510 gboolean session_info_is_user(struct session_info *info)
512 DBusError error;
513 DBusMessage *message = NULL;
514 DBusMessage *reply = NULL;
515 gchar *session_type = NULL;
516 gboolean ret = TRUE;
518 g_return_val_if_fail (info != NULL, TRUE);
519 g_return_val_if_fail (info->connection != NULL, TRUE);
520 g_return_val_if_fail (info->active_session != NULL, TRUE);
522 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
523 info->active_session,
524 INTERFACE_CONSOLE_KIT_SESSION,
525 "GetSessionType");
526 if (message == NULL) {
527 syslog(LOG_ERR,
528 "(console-kit) Unable to create dbus message for GetSessionType");
529 return TRUE;
532 dbus_error_init(&error);
533 reply = dbus_connection_send_with_reply_and_block(info->connection,
534 message,
536 &error);
537 if (reply == NULL || dbus_error_is_set(&error)) {
538 if (dbus_error_is_set(&error)) {
539 syslog(LOG_ERR, "GetSessionType failed: %s", error.message);
540 dbus_error_free(&error);
541 } else
542 syslog(LOG_ERR, "GetSessionType failed");
543 goto exit;
546 dbus_error_init(&error);
547 if (!dbus_message_get_args(reply,
548 &error,
549 DBUS_TYPE_STRING, &session_type,
550 DBUS_TYPE_INVALID)) {
551 if (dbus_error_is_set(&error)) {
552 syslog(LOG_ERR,
553 "(console-kit) fail to get session-type from reply: %s",
554 error.message);
555 dbus_error_free(&error);
556 } else {
557 syslog(LOG_ERR, "(console-kit) fail to get session-type from reply");
559 session_type = NULL;
560 goto exit;
563 /* Empty session_type means user */
564 if (info->verbose)
565 syslog(LOG_DEBUG, "(console-kit) session-type is '%s'", session_type);
567 ret = (g_strcmp0 (session_type, "LoginWindow") != 0);
569 exit:
570 if (reply != NULL) {
571 dbus_message_unref(reply);
573 if (message != NULL) {
574 dbus_message_unref(message);
576 return ret;