console-kit: do not use empty session
[vd_agent.git] / src / console-kit.c
blob3a72657a1fba72406baf2512117419ce181a3b10
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>
30 struct session_info {
31 DBusConnection *connection;
32 int fd;
33 char *seat;
34 char *active_session;
35 int verbose;
38 #define INTERFACE_CONSOLE_KIT "org.freedesktop.ConsoleKit"
39 #define OBJ_PATH_CONSOLE_KIT "/org/freedesktop/ConsoleKit"
41 #define INTERFACE_CONSOLE_KIT_MANAGER INTERFACE_CONSOLE_KIT ".Manager"
42 #define OBJ_PATH_CONSOLE_KIT_MANAGER OBJ_PATH_CONSOLE_KIT "/Manager"
44 #define INTERFACE_CONSOLE_KIT_SEAT INTERFACE_CONSOLE_KIT ".Seat"
46 static char *console_kit_get_first_seat(struct session_info *info);
47 static char *console_kit_check_active_session_change(struct session_info *info);
49 struct session_info *session_info_create(int verbose)
51 struct session_info *info;
52 DBusError error;
53 char match[1024];
55 info = calloc(1, sizeof(*info));
56 if (!info)
57 return NULL;
59 info->verbose = verbose;
61 dbus_error_init(&error);
62 info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
63 if (info->connection == NULL || dbus_error_is_set(&error)) {
64 if (dbus_error_is_set(&error)) {
65 syslog(LOG_ERR, "Unable to connect to system bus: %s",
66 error.message);
67 dbus_error_free(&error);
68 } else
69 syslog(LOG_ERR, "Unable to connect to system bus");
70 free(info);
71 return NULL;
74 if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) {
75 syslog(LOG_ERR, "Unable to get connection fd");
76 session_info_destroy(info);
77 return NULL;
80 if (!console_kit_get_first_seat(info)) {
81 session_info_destroy(info);
82 return NULL;
85 /* Register for active session changes */
86 snprintf(match, sizeof(match),
87 "type='signal',interface='%s',"
88 "path='%s',member='ActiveSessionChanged'",
89 INTERFACE_CONSOLE_KIT_SEAT, info->seat);
90 dbus_error_init(&error);
91 dbus_bus_add_match(info->connection, match, &error);
92 if (dbus_error_is_set(&error)) {
93 syslog(LOG_ERR, "Match Error (%s)", error.message);
94 session_info_destroy(info);
95 return NULL;
98 return info;
101 void session_info_destroy(struct session_info *info)
103 if (!info)
104 return;
106 dbus_connection_close(info->connection);
107 free(info->seat);
108 free(info->active_session);
109 free(info);
112 int session_info_get_fd(struct session_info *info)
114 return info->fd;
117 static char *console_kit_get_first_seat(struct session_info *info)
119 DBusError error;
120 DBusMessage *message = NULL;
121 DBusMessage *reply = NULL;
122 DBusMessageIter iter, subiter;
123 int type;
124 char *seat = NULL;
127 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
128 OBJ_PATH_CONSOLE_KIT_MANAGER,
129 INTERFACE_CONSOLE_KIT_MANAGER,
130 "GetSeats");
131 if (message == NULL) {
132 syslog(LOG_ERR, "Unable to create dbus message");
133 goto exit;
136 dbus_error_init(&error);
137 reply = dbus_connection_send_with_reply_and_block(info->connection,
138 message,
140 &error);
141 if (reply == NULL || dbus_error_is_set(&error)) {
142 if (dbus_error_is_set(&error)) {
143 syslog(LOG_ERR, "GetSeats failed: %s", error.message);
144 dbus_error_free(&error);
145 } else
146 syslog(LOG_ERR, "GetSeats failed");
147 goto exit;
150 dbus_message_iter_init(reply, &iter);
151 type = dbus_message_iter_get_arg_type(&iter);
152 if (type != DBUS_TYPE_ARRAY) {
153 syslog(LOG_ERR,
154 "expected an array return value, got a '%c' instead", type);
155 goto exit;
158 dbus_message_iter_recurse(&iter, &subiter);
159 type = dbus_message_iter_get_arg_type(&subiter);
160 if (type != DBUS_TYPE_OBJECT_PATH) {
161 syslog(LOG_ERR,
162 "expected an object path element, got a '%c' instead", type);
163 goto exit;
166 dbus_message_iter_get_basic(&subiter, &seat);
167 info->seat = strdup(seat);
169 exit:
170 if (reply != NULL) {
171 dbus_message_unref(reply);
174 if (message != NULL) {
175 dbus_message_unref(message);
178 syslog(LOG_INFO, "(console-kit) seat: %s", info->seat);
179 return info->seat;
182 const char *session_info_get_active_session(struct session_info *info)
184 DBusError error;
185 DBusMessage *message = NULL;
186 DBusMessage *reply = NULL;
187 char *session = NULL;
189 if (!info)
190 return NULL;
192 if (info->active_session)
193 return console_kit_check_active_session_change(info);
195 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
196 info->seat,
197 INTERFACE_CONSOLE_KIT_SEAT,
198 "GetActiveSession");
199 if (message == NULL) {
200 syslog(LOG_ERR, "Unable to create dbus message");
201 goto exit;
204 dbus_error_init(&error);
205 reply = dbus_connection_send_with_reply_and_block(info->connection,
206 message,
208 &error);
209 if (reply == NULL || dbus_error_is_set(&error)) {
210 if (dbus_error_is_set(&error)) {
211 syslog(LOG_ERR, "GetActiveSession failed: %s", error.message);
212 dbus_error_free(&error);
213 } else
214 syslog(LOG_ERR, "GetActiveSession failed");
215 goto exit;
218 dbus_error_init(&error);
219 if (!dbus_message_get_args(reply,
220 &error,
221 DBUS_TYPE_OBJECT_PATH, &session,
222 DBUS_TYPE_INVALID)) {
223 if (dbus_error_is_set(&error)) {
224 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
225 dbus_error_free(&error);
226 } else
227 syslog(LOG_ERR, "error getting ssid from reply");
228 session = NULL;
229 goto exit;
232 info->active_session = strdup(session);
234 exit:
235 if (reply != NULL) {
236 dbus_message_unref(reply);
239 if (message != NULL) {
240 dbus_message_unref(message);
243 /* In case the session was changed while we were running */
244 return console_kit_check_active_session_change(info);
247 char *session_info_session_for_pid(struct session_info *info, uint32_t pid)
249 DBusError error;
250 DBusMessage *message = NULL;
251 DBusMessage *reply = NULL;
252 DBusMessageIter args;
253 char *ssid = NULL;
255 if (!info)
256 return NULL;
258 message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
259 OBJ_PATH_CONSOLE_KIT_MANAGER,
260 INTERFACE_CONSOLE_KIT_MANAGER,
261 "GetSessionForUnixProcess");
262 if (message == NULL) {
263 syslog(LOG_ERR, "Unable to create dbus message");
264 goto exit;
267 dbus_message_iter_init_append(message, &args);
268 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
269 syslog(LOG_ERR, "Unable to append dbus message args");
270 goto exit;
273 dbus_error_init(&error);
274 reply = dbus_connection_send_with_reply_and_block(info->connection,
275 message,
277 &error);
278 if (reply == NULL || dbus_error_is_set(&error)) {
279 if (dbus_error_is_set(&error)) {
280 syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
281 error.message);
282 dbus_error_free(&error);
283 } else
284 syslog(LOG_ERR, "GetSessionForUnixProces failed");
285 goto exit;
288 dbus_error_init(&error);
289 if (!dbus_message_get_args(reply,
290 &error,
291 DBUS_TYPE_OBJECT_PATH, &ssid,
292 DBUS_TYPE_INVALID)) {
293 if (dbus_error_is_set(&error)) {
294 syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
295 dbus_error_free(&error);
296 } else
297 syslog(LOG_ERR, "error getting ssid from reply");
298 ssid = NULL;
299 goto exit;
302 ssid = strdup(ssid);
304 exit:
305 if (reply != NULL) {
306 dbus_message_unref(reply);
309 if (message != NULL) {
310 dbus_message_unref(message);
313 return ssid;
316 static char *console_kit_check_active_session_change(struct session_info *info)
318 DBusMessage *message = NULL;
319 DBusMessageIter iter;
320 char *session;
321 int type;
323 /* non blocking read of the next available message */
324 dbus_connection_read_write(info->connection, 0);
325 while ((message = dbus_connection_pop_message(info->connection))) {
326 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
327 const char *member = dbus_message_get_member (message);
328 if (!strcmp(member, "NameAcquired")) {
329 dbus_message_unref(message);
330 continue;
332 if (strcmp(member, "ActiveSessionChanged")) {
333 syslog(LOG_ERR, "unexpected signal member: %s", member);
334 dbus_message_unref(message);
335 continue;
337 } else {
338 syslog(LOG_ERR, "received non signal message!");
339 dbus_message_unref(message);
340 continue;
343 free(info->active_session);
344 info->active_session = NULL;
346 dbus_message_iter_init(message, &iter);
347 type = dbus_message_iter_get_arg_type(&iter);
348 /* Session should be an object path, but there is a bug in
349 ConsoleKit where it sends a string rather then an object_path
350 accept object_path too in case the bug ever gets fixed */
351 if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_OBJECT_PATH) {
352 syslog(LOG_ERR,
353 "ActiveSessionChanged message has unexpected type: '%c'",
354 type);
355 dbus_message_unref(message);
356 continue;
359 dbus_message_iter_get_basic(&iter, &session);
360 if (session != NULL && session[0] != '\0') {
361 info->active_session = strdup(session);
362 } else {
363 syslog(LOG_WARNING, "(console-kit) received invalid session. "
364 "No active-session at the moment");
366 dbus_message_unref(message);
368 /* non blocking read of the next available message */
369 dbus_connection_read_write(info->connection, 0);
372 if (info->verbose)
373 syslog(LOG_DEBUG, "(console-kit) active-session: '%s'",
374 (info->active_session ? info->active_session : "None"));
375 return info->active_session;