1 /* console-kit.c vdagentd ConsoleKit integration code
3 Copyright 2010-2012 Red Hat, Inc.
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>
32 DBusConnection
*connection
;
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
)
66 if (info
->match_seat_signals
!= NULL
) {
67 dbus_error_init(&error
);
68 dbus_bus_remove_match(info
->connection
,
69 info
->match_seat_signals
,
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
,
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
)
96 if (info
->connection
== NULL
)
99 si_dbus_match_remove(info
);
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
,
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
,
116 if (dbus_error_is_set(&error
)) {
117 syslog(LOG_WARNING
, "Unable to add dbus rule match: %s",
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
);
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
,
139 if (dbus_error_is_set(&error
)) {
140 syslog(LOG_WARNING
, "Unable to add dbus rule match: %s",
142 dbus_error_free(&error
);
143 g_free(info
->match_session_signals
);
144 info
->match_session_signals
= NULL
;
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
) {
159 member
= dbus_message_get_member (message
);
160 if (g_strcmp0(member
, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED
) == 0) {
161 DBusMessageIter iter
;
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
);
179 syslog(LOG_WARNING
, "(console-kit) received invalid session. "
180 "No active-session at the moment");
184 "ActiveSessionChanged message has unexpected type: '%c'",
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
;
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
);
203 "(console-kit) IdleHintChanged has unexpected type: '%c'",
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
;
225 info
= calloc(1, sizeof(*info
));
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",
239 dbus_error_free(&error
);
241 syslog(LOG_ERR
, "Unable to connect to system bus");
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
);
252 if (!console_kit_get_first_seat(info
)) {
253 session_info_destroy(info
);
257 si_dbus_match_rule_update(info
);
261 void session_info_destroy(struct session_info
*info
)
266 si_dbus_match_remove(info
);
267 dbus_connection_close(info
->connection
);
269 free(info
->active_session
);
273 int session_info_get_fd(struct session_info
*info
)
278 static char *console_kit_get_first_seat(struct session_info
*info
)
281 DBusMessage
*message
= NULL
;
282 DBusMessage
*reply
= NULL
;
283 DBusMessageIter iter
, subiter
;
288 message
= dbus_message_new_method_call(INTERFACE_CONSOLE_KIT
,
289 OBJ_PATH_CONSOLE_KIT_MANAGER
,
290 INTERFACE_CONSOLE_KIT_MANAGER
,
292 if (message
== NULL
) {
293 syslog(LOG_ERR
, "Unable to create dbus message");
297 dbus_error_init(&error
);
298 reply
= dbus_connection_send_with_reply_and_block(info
->connection
,
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
);
307 syslog(LOG_ERR
, "GetSeats failed");
311 dbus_message_iter_init(reply
, &iter
);
312 type
= dbus_message_iter_get_arg_type(&iter
);
313 if (type
!= DBUS_TYPE_ARRAY
) {
315 "expected an array return value, got a '%c' instead", type
);
319 dbus_message_iter_recurse(&iter
, &subiter
);
320 type
= dbus_message_iter_get_arg_type(&subiter
);
321 if (type
!= DBUS_TYPE_OBJECT_PATH
) {
323 "expected an object path element, got a '%c' instead", type
);
327 dbus_message_iter_get_basic(&subiter
, &seat
);
328 info
->seat
= strdup(seat
);
332 dbus_message_unref(reply
);
335 if (message
!= NULL
) {
336 dbus_message_unref(message
);
339 syslog(LOG_INFO
, "(console-kit) seat: %s", info
->seat
);
343 const char *session_info_get_active_session(struct session_info
*info
)
346 DBusMessage
*message
= NULL
;
347 DBusMessage
*reply
= NULL
;
348 char *session
= 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
,
358 INTERFACE_CONSOLE_KIT_SEAT
,
360 if (message
== NULL
) {
361 syslog(LOG_ERR
, "Unable to create dbus message");
365 dbus_error_init(&error
);
366 reply
= dbus_connection_send_with_reply_and_block(info
->connection
,
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
);
375 syslog(LOG_ERR
, "GetActiveSession failed");
379 dbus_error_init(&error
);
380 if (!dbus_message_get_args(reply
,
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
);
388 syslog(LOG_ERR
, "error getting ssid from reply");
393 info
->active_session
= strdup(session
);
394 si_dbus_match_rule_update(info
);
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
)
412 DBusMessage
*message
= NULL
;
413 DBusMessage
*reply
= NULL
;
414 DBusMessageIter args
;
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");
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");
435 dbus_error_init(&error
);
436 reply
= dbus_connection_send_with_reply_and_block(info
->connection
,
440 if (reply
== NULL
|| dbus_error_is_set(&error
)) {
441 if (dbus_error_is_set(&error
)) {
442 syslog(LOG_ERR
, "GetSessionForUnixProcess failed: %s",
444 dbus_error_free(&error
);
446 syslog(LOG_ERR
, "GetSessionForUnixProces failed");
450 dbus_error_init(&error
);
451 if (!dbus_message_get_args(reply
,
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
);
459 syslog(LOG_ERR
, "error getting ssid from reply");
468 dbus_message_unref(reply
);
471 if (message
!= NULL
) {
472 dbus_message_unref(message
);
478 static char *console_kit_check_active_session_change(struct session_info
*info
)
480 si_dbus_read_signals(info
);
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
)
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 use the IdleHint value.
497 * systemd-login uses locked-hint which is not implemented in ConsoleKit,
498 * see https://github.com/ConsoleKit2/ConsoleKit2/issues/89 */
499 si_dbus_read_signals(info
);
500 locked
= info
->session_idle_hint
;
502 syslog(LOG_DEBUG
, "(console-kit) session is locked: %s",
503 locked
? "yes" : "no");
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
)
513 DBusMessage
*message
= NULL
;
514 DBusMessage
*reply
= NULL
;
515 gchar
*session_type
= NULL
;
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
,
526 if (message
== NULL
) {
528 "(console-kit) Unable to create dbus message for GetSessionType");
532 dbus_error_init(&error
);
533 reply
= dbus_connection_send_with_reply_and_block(info
->connection
,
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
);
542 syslog(LOG_ERR
, "GetSessionType failed");
546 dbus_error_init(&error
);
547 if (!dbus_message_get_args(reply
,
549 DBUS_TYPE_STRING
, &session_type
,
550 DBUS_TYPE_INVALID
)) {
551 if (dbus_error_is_set(&error
)) {
553 "(console-kit) fail to get session-type from reply: %s",
555 dbus_error_free(&error
);
557 syslog(LOG_ERR
, "(console-kit) fail to get session-type from reply");
563 /* Empty session_type means user */
565 syslog(LOG_DEBUG
, "(console-kit) session-type is '%s'", session_type
);
567 ret
= (g_strcmp0 (session_type
, "LoginWindow") != 0);
571 dbus_message_unref(reply
);
573 if (message
!= NULL
) {
574 dbus_message_unref(message
);