build-sys: get rid of noinst_HEADERS
[vd_agent.git] / src / systemd-login.c
blob9719c0b998fe63b7831dd3900bbde9e30f9bdee5
1 /* systemd-login.c vdagentd libsystemd-login integration code
3 Copyright 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 <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <syslog.h>
27 #include <systemd/sd-login.h>
28 #include <dbus/dbus.h>
30 struct session_info {
31 int verbose;
32 sd_login_monitor *mon;
33 char *session;
34 struct {
35 DBusConnection *system_connection;
36 char *match_session_signals;
37 } dbus;
38 gboolean session_is_locked;
39 gboolean session_locked_hint;
42 #define LOGIND_INTERFACE "org.freedesktop.login1"
44 #define LOGIND_SESSION_INTERFACE "org.freedesktop.login1.Session"
45 #define LOGIND_SESSION_OBJ_TEMPLATE "/org/freedesktop/login1/session/_3%s"
47 #define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
49 #define SESSION_SIGNAL_LOCK "Lock"
50 #define SESSION_SIGNAL_UNLOCK "Unlock"
52 #define SESSION_PROP_LOCKED_HINT "LockedHint"
54 /* dbus related */
55 static DBusConnection *si_dbus_get_system_bus(void)
57 DBusConnection *connection;
58 DBusError error;
60 dbus_error_init(&error);
61 connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
62 if (connection == NULL || dbus_error_is_set(&error)) {
63 if (dbus_error_is_set(&error)) {
64 syslog(LOG_WARNING, "Unable to connect to system bus: %s",
65 error.message);
66 dbus_error_free(&error);
67 } else {
68 syslog(LOG_WARNING, "Unable to connect to system bus");
70 return NULL;
72 return connection;
75 static void si_dbus_match_remove(struct session_info *si)
77 DBusError error;
78 if (si->dbus.match_session_signals == NULL)
79 return;
81 dbus_error_init(&error);
82 dbus_bus_remove_match(si->dbus.system_connection,
83 si->dbus.match_session_signals,
84 &error);
86 g_free(si->dbus.match_session_signals);
87 si->dbus.match_session_signals = NULL;
90 static void si_dbus_match_rule_update(struct session_info *si)
92 DBusError error;
94 if (si->dbus.system_connection == NULL ||
95 si->session == NULL)
96 return;
98 si_dbus_match_remove(si);
100 si->dbus.match_session_signals =
101 g_strdup_printf ("type='signal',interface='%s',path='"
102 LOGIND_SESSION_OBJ_TEMPLATE"'",
103 LOGIND_SESSION_INTERFACE,
104 si->session);
105 if (si->verbose)
106 syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals);
108 dbus_error_init(&error);
109 dbus_bus_add_match(si->dbus.system_connection,
110 si->dbus.match_session_signals,
111 &error);
112 if (dbus_error_is_set(&error)) {
113 syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
114 error.message);
115 dbus_error_free(&error);
116 g_free(si->dbus.match_session_signals);
117 si->dbus.match_session_signals = NULL;
121 static void
122 si_dbus_read_properties(struct session_info *si)
124 dbus_bool_t locked_hint, ret;
125 DBusMessageIter iter, iter_variant;
126 gint type;
127 DBusError error;
128 DBusMessage *message = NULL;
129 DBusMessage *reply = NULL;
130 gchar *session_object;
131 const gchar *interface, *property;
133 if (si->session == NULL)
134 return;
136 session_object = g_strdup_printf(LOGIND_SESSION_OBJ_TEMPLATE, si->session);
137 message = dbus_message_new_method_call(LOGIND_INTERFACE,
138 session_object,
139 DBUS_PROPERTIES_INTERFACE,
140 "Get");
141 g_free (session_object);
142 if (message == NULL) {
143 syslog(LOG_ERR, "Unable to create dbus message");
144 goto exit;
147 interface = LOGIND_SESSION_INTERFACE;
148 property = SESSION_PROP_LOCKED_HINT;
149 ret = dbus_message_append_args(message,
150 DBUS_TYPE_STRING, &interface,
151 DBUS_TYPE_STRING, &property,
152 DBUS_TYPE_INVALID);
153 if (!ret) {
154 syslog(LOG_ERR, "Unable to request locked-hint");
155 goto exit;
158 dbus_error_init(&error);
159 reply = dbus_connection_send_with_reply_and_block(si->dbus.system_connection,
160 message,
162 &error);
163 if (reply == NULL) {
164 if (dbus_error_is_set(&error)) {
165 syslog(LOG_ERR, "Properties.Get failed (locked-hint) due %s", error.message);
166 dbus_error_free(&error);
167 } else {
168 syslog(LOG_ERR, "Properties.Get failed (locked-hint)");
170 goto exit;
173 dbus_message_iter_init(reply, &iter);
174 type = dbus_message_iter_get_arg_type(&iter);
175 if (type != DBUS_TYPE_VARIANT) {
176 syslog(LOG_ERR, "expected a variant, got a '%c' instead", type);
177 goto exit;
180 dbus_message_iter_recurse(&iter, &iter_variant);
181 type = dbus_message_iter_get_arg_type(&iter_variant);
182 if (type != DBUS_TYPE_BOOLEAN) {
183 syslog(LOG_ERR, "expected a boolean, got a '%c' instead", type);
184 goto exit;
186 dbus_message_iter_get_basic(&iter_variant, &locked_hint);
188 si->session_locked_hint = (locked_hint) ? TRUE : FALSE;
189 exit:
190 if (reply != NULL) {
191 dbus_message_unref(reply);
194 if (message != NULL) {
195 dbus_message_unref(message);
199 static void
200 si_dbus_read_signals(struct session_info *si)
202 DBusMessage *message = NULL;
204 dbus_connection_read_write(si->dbus.system_connection, 0);
205 message = dbus_connection_pop_message(si->dbus.system_connection);
206 while (message != NULL) {
207 const char *member;
209 member = dbus_message_get_member (message);
210 if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
211 si->session_is_locked = TRUE;
212 } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
213 si->session_is_locked = FALSE;
214 } else {
215 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
216 syslog(LOG_WARNING, "(systemd-login) received non signal message");
217 } else if (si->verbose) {
218 syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member);
222 dbus_message_unref(message);
223 dbus_connection_read_write(si->dbus.system_connection, 0);
224 message = dbus_connection_pop_message(si->dbus.system_connection);
228 struct session_info *session_info_create(int verbose)
230 struct session_info *si;
231 int r;
233 si = calloc(1, sizeof(*si));
234 if (!si)
235 return NULL;
237 si->verbose = verbose;
238 si->session_is_locked = FALSE;
240 r = sd_login_monitor_new("session", &si->mon);
241 if (r < 0) {
242 syslog(LOG_ERR, "Error creating login monitor: %s", strerror(-r));
243 free(si);
244 return NULL;
247 si->dbus.system_connection = si_dbus_get_system_bus();
248 return si;
251 void session_info_destroy(struct session_info *si)
253 if (!si)
254 return;
256 si_dbus_match_remove(si);
257 dbus_connection_close(si->dbus.system_connection);
258 sd_login_monitor_unref(si->mon);
259 free(si->session);
260 free(si);
263 int session_info_get_fd(struct session_info *si)
265 return sd_login_monitor_get_fd(si->mon);
268 const char *session_info_get_active_session(struct session_info *si)
270 int r;
271 char *old_session = si->session;
273 si->session = NULL;
274 r = sd_seat_get_active("seat0", &si->session, NULL);
275 /* ENOENT happens when a seat is switching from one session to another */
276 if (r < 0 && r != -ENOENT)
277 syslog(LOG_ERR, "Error getting active session: %s",
278 strerror(-r));
280 if (si->verbose && si->session &&
281 (!old_session || strcmp(old_session, si->session)))
282 syslog(LOG_INFO, "Active session: %s", si->session);
284 sd_login_monitor_flush(si->mon);
285 free(old_session);
287 si_dbus_match_rule_update(si);
288 return si->session;
291 char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
293 int r;
294 char *session = NULL;
296 r = sd_pid_get_session(pid, &session);
297 if (r < 0)
298 syslog(LOG_ERR, "Error getting session for pid %u: %s",
299 pid, strerror(-r));
300 else if (si->verbose)
301 syslog(LOG_INFO, "Session for pid %u: %s", pid, session);
303 return session;
306 gboolean session_info_session_is_locked(struct session_info *si)
308 gboolean locked;
310 g_return_val_if_fail (si != NULL, FALSE);
312 si_dbus_read_signals(si);
313 si_dbus_read_properties(si);
315 locked = (si->session_is_locked || si->session_locked_hint);
316 if (si->verbose) {
317 syslog(LOG_DEBUG, "(systemd-login) session is locked: %s",
318 locked ? "yes" : "no");
320 return locked;
323 /* This function should only be called after session_info_get_active_session
324 * in order to verify if active session belongs to user (non greeter) */
325 gboolean session_info_is_user(struct session_info *si)
327 gchar *class = NULL;
328 gboolean ret;
330 g_return_val_if_fail (si != NULL, TRUE);
331 g_return_val_if_fail (si->session != NULL, TRUE);
333 if (sd_session_get_class(si->session, &class) != 0) {
334 syslog(LOG_WARNING, "Unable to get class from session: %s",
335 si->session);
336 return TRUE;
339 if (si->verbose)
340 syslog(LOG_DEBUG, "(systemd-login) class for %s is %s",
341 si->session, class);
343 ret = (g_strcmp0(class, "user") == 0);
344 g_free(class);
346 return ret;