disabled auto start
[platform/adaptation/emulator/spice-vdagent.git] / src / console-kit.c
1 /*  console-kit.c vdagentd ConsoleKit integration code
2
3     Copyright 2010-2012 Red Hat, Inc.
4
5     Red Hat Authors:
6     Hans de Goede <hdegoede@redhat.com>
7
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.
12
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.
17
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/>.
20 */
21
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
30 struct session_info {
31     DBusConnection *connection;
32     int fd;
33     char *seat;
34     char *active_session;
35 };
36
37 static char *console_kit_get_first_seat(struct session_info *ck);
38 static char *console_kit_check_active_session_change(struct session_info *ck);
39
40 struct session_info *session_info_create(int verbose)
41 {
42     struct session_info *ck;
43     DBusError error;
44     char match[1024];
45
46     ck = calloc(1, sizeof(*ck));
47     if (!ck)
48         return NULL;
49
50     dbus_error_init(&error);
51     ck->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
52     if (ck->connection == NULL || dbus_error_is_set(&error)) {
53         if (dbus_error_is_set(&error)) {
54              syslog(LOG_ERR, "Unable to connect to system bus: %s",
55                     error.message);
56              dbus_error_free(&error);
57         } else
58              syslog(LOG_ERR, "Unable to connect to system bus");
59         free(ck);
60         return NULL;
61     }
62     
63     if (!dbus_connection_get_unix_fd(ck->connection, &ck->fd)) {
64         syslog(LOG_ERR, "Unable to get connection fd");
65         session_info_destroy(ck);
66         return NULL;
67     }
68
69     if (!console_kit_get_first_seat(ck)) {
70         session_info_destroy(ck);
71         return NULL;
72     }
73
74     /* Register for active session changes */
75     snprintf(match, sizeof(match),
76              "type='signal',interface='org.freedesktop.ConsoleKit.Seat',"
77              "path='%s',member='ActiveSessionChanged'", ck->seat);
78     dbus_error_init(&error);
79     dbus_bus_add_match(ck->connection, match, &error);
80     if (dbus_error_is_set(&error)) { 
81         syslog(LOG_ERR, "Match Error (%s)", error.message);
82         session_info_destroy(ck);
83         return NULL;
84     }
85
86     return ck;
87 }
88
89 void session_info_destroy(struct session_info *ck)
90 {
91     if (!ck)
92         return;
93
94     dbus_connection_close(ck->connection);
95     free(ck->seat);
96     free(ck->active_session);
97     free(ck);
98 }
99
100 int session_info_get_fd(struct session_info *ck)
101 {
102     return ck->fd;
103 }
104
105 static char *console_kit_get_first_seat(struct session_info *ck)
106 {
107     DBusError error;
108     DBusMessage *message = NULL;
109     DBusMessage *reply = NULL;
110     DBusMessageIter iter, subiter;
111     int type;
112     char *seat = NULL;
113
114     message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
115                                            "/org/freedesktop/ConsoleKit/Manager",
116                                            "org.freedesktop.ConsoleKit.Manager",
117                                            "GetSeats");
118     if (message == NULL) {
119         syslog(LOG_ERR, "Unable to create dbus message");
120         goto exit;
121     }
122
123     dbus_error_init(&error);
124     reply = dbus_connection_send_with_reply_and_block(ck->connection,
125                                                       message,
126                                                       -1,
127                                                       &error);
128     if (reply == NULL || dbus_error_is_set(&error)) {
129         if (dbus_error_is_set(&error)) {
130             syslog(LOG_ERR, "GetSeats failed: %s", error.message);
131             dbus_error_free(&error);
132         } else
133             syslog(LOG_ERR, "GetSeats failed");
134         goto exit;
135     }
136
137     dbus_message_iter_init(reply, &iter);
138     type = dbus_message_iter_get_arg_type(&iter);
139     if (type != DBUS_TYPE_ARRAY) {
140         syslog(LOG_ERR,
141                "expected an array return value, got a '%c' instead", type);
142         goto exit;
143     }
144
145     dbus_message_iter_recurse(&iter, &subiter);
146     type = dbus_message_iter_get_arg_type(&subiter);
147     if (type != DBUS_TYPE_OBJECT_PATH) {
148         syslog(LOG_ERR,
149                "expected an object path element, got a '%c' instead", type);
150         goto exit;
151     }
152
153     dbus_message_iter_get_basic(&subiter, &seat);
154     ck->seat = strdup(seat);
155
156 exit:
157     if (reply != NULL) {
158             dbus_message_unref(reply);
159     }
160
161     if (message != NULL) {
162             dbus_message_unref(message);
163     }
164
165     return ck->seat;
166 }
167
168 const char *session_info_get_active_session(struct session_info *ck)
169 {
170     DBusError error;
171     DBusMessage *message = NULL;
172     DBusMessage *reply = NULL;
173     char *session = NULL;
174
175     if (!ck)
176         return NULL;
177
178     if (ck->active_session)
179         return console_kit_check_active_session_change(ck);
180
181     message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
182                                            ck->seat,
183                                            "org.freedesktop.ConsoleKit.Seat",
184                                            "GetActiveSession");
185     if (message == NULL) {
186         syslog(LOG_ERR, "Unable to create dbus message");
187         goto exit;
188     }
189
190     dbus_error_init(&error);
191     reply = dbus_connection_send_with_reply_and_block(ck->connection,
192                                                       message,
193                                                       -1,
194                                                       &error);
195     if (reply == NULL || dbus_error_is_set(&error)) {
196         if (dbus_error_is_set(&error)) {
197             syslog(LOG_ERR, "GetActiveSession failed: %s", error.message);
198             dbus_error_free(&error);
199         } else
200             syslog(LOG_ERR, "GetActiveSession failed");
201         goto exit;
202     }
203
204     dbus_error_init(&error);
205     if (!dbus_message_get_args(reply,
206                                &error,
207                                DBUS_TYPE_OBJECT_PATH, &session,
208                                DBUS_TYPE_INVALID)) {
209         if (dbus_error_is_set(&error)) {
210             syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
211             dbus_error_free(&error);
212         } else
213             syslog(LOG_ERR, "error getting ssid from reply");
214         session = NULL;
215         goto exit;
216     }
217
218     ck->active_session = strdup(session);
219
220 exit:
221     if (reply != NULL) {
222             dbus_message_unref(reply);
223     }
224
225     if (message != NULL) {
226             dbus_message_unref(message);
227     }
228
229     /* In case the session was changed while we were running */
230     return console_kit_check_active_session_change(ck);
231 }
232
233 char *session_info_session_for_pid(struct session_info *ck, uint32_t pid)
234 {
235     DBusError error;
236     DBusMessage *message = NULL;
237     DBusMessage *reply = NULL;
238     DBusMessageIter args;
239     char *ssid = NULL;
240
241     if (!ck)
242         return NULL;
243
244     message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
245                                            "/org/freedesktop/ConsoleKit/Manager",
246                                            "org.freedesktop.ConsoleKit.Manager",
247                                            "GetSessionForUnixProcess");
248     if (message == NULL) {
249         syslog(LOG_ERR, "Unable to create dbus message");
250         goto exit;
251     }
252
253     dbus_message_iter_init_append(message, &args);
254     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
255         syslog(LOG_ERR, "Unable to append dbus message args");
256         goto exit;
257     }
258
259     dbus_error_init(&error);
260     reply = dbus_connection_send_with_reply_and_block(ck->connection,
261                                                       message,
262                                                       -1,
263                                                       &error);
264     if (reply == NULL || dbus_error_is_set(&error)) {
265         if (dbus_error_is_set(&error)) {
266             syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
267                    error.message);
268             dbus_error_free(&error);
269         } else
270             syslog(LOG_ERR, "GetSessionForUnixProces failed");
271         goto exit;
272     }
273
274     dbus_error_init(&error);
275     if (!dbus_message_get_args(reply,
276                                &error,
277                                DBUS_TYPE_OBJECT_PATH, &ssid,
278                                DBUS_TYPE_INVALID)) {
279         if (dbus_error_is_set(&error)) {
280             syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
281             dbus_error_free(&error);
282         } else
283             syslog(LOG_ERR, "error getting ssid from reply");
284         ssid = NULL;
285         goto exit;
286     }
287
288     ssid = strdup(ssid);
289
290 exit:
291     if (reply != NULL) {
292             dbus_message_unref(reply);
293     }
294
295     if (message != NULL) {
296             dbus_message_unref(message);
297     }
298
299     return ssid;
300 }
301
302 static char *console_kit_check_active_session_change(struct session_info *ck)
303 {
304     DBusMessage *message = NULL;
305     DBusMessageIter iter;
306     char *session;
307     int type;
308
309     /* non blocking read of the next available message */
310     dbus_connection_read_write(ck->connection, 0);
311     while ((message = dbus_connection_pop_message(ck->connection))) {
312         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
313             const char *member = dbus_message_get_member (message);
314             if (!strcmp(member, "NameAcquired")) {
315                 dbus_message_unref(message);
316                 continue;
317             }
318             if (strcmp(member, "ActiveSessionChanged")) {
319                 syslog(LOG_ERR, "unexpected signal member: %s", member);
320                 dbus_message_unref(message);
321                 continue;
322             }
323         } else {
324             syslog(LOG_ERR, "received non signal message!");
325             dbus_message_unref(message);
326             continue;
327         }
328
329         free(ck->active_session);
330         ck->active_session = NULL;
331
332         dbus_message_iter_init(message, &iter);
333         type = dbus_message_iter_get_arg_type(&iter);
334         /* Session should be an object path, but there is a bug in
335            ConsoleKit where it sends a string rather then an object_path
336            accept object_path too in case the bug ever gets fixed */
337         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_OBJECT_PATH) {
338             syslog(LOG_ERR,
339                    "ActiveSessionChanged message has unexpected type: '%c'",
340                    type);
341             dbus_message_unref(message);
342             continue;
343         }
344
345         dbus_message_iter_get_basic(&iter, &session);
346         ck->active_session = strdup(session);
347         dbus_message_unref(message);
348
349         /* non blocking read of the next available message */
350         dbus_connection_read_write(ck->connection, 0);
351     }
352
353     return ck->active_session;
354 }