session-info: check for a locked session
[vd_agent.git] / src / systemd-login.c
blobe86b7f2ca9773e1a9dfe6e5c41a12a1f2b4bcab7
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;
41 #define LOGIND_SESSION_INTERFACE "org.freedesktop.login1.Session"
42 #define LOGIND_SESSION_OBJ_TEMPLATE "'/org/freedesktop/login1/session/_3%s'"
44 #define SESSION_SIGNAL_LOCK "Lock"
45 #define SESSION_SIGNAL_UNLOCK "Unlock"
47 /* dbus related */
48 static DBusConnection *si_dbus_get_system_bus(void)
50 DBusConnection *connection;
51 DBusError error;
53 dbus_error_init(&error);
54 connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
55 if (connection == NULL || dbus_error_is_set(&error)) {
56 if (dbus_error_is_set(&error)) {
57 syslog(LOG_WARNING, "Unable to connect to system bus: %s",
58 error.message);
59 dbus_error_free(&error);
60 } else {
61 syslog(LOG_WARNING, "Unable to connect to system bus");
63 return NULL;
65 return connection;
68 static void si_dbus_match_remove(struct session_info *si)
70 DBusError error;
71 if (si->dbus.match_session_signals == NULL)
72 return;
74 dbus_error_init(&error);
75 dbus_bus_remove_match(si->dbus.system_connection,
76 si->dbus.match_session_signals,
77 &error);
79 g_free(si->dbus.match_session_signals);
80 si->dbus.match_session_signals = NULL;
83 static void si_dbus_match_rule_update(struct session_info *si)
85 DBusError error;
87 if (si->dbus.system_connection == NULL ||
88 si->session == NULL)
89 return;
91 si_dbus_match_remove(si);
93 si->dbus.match_session_signals =
94 g_strdup_printf ("type='signal',interface='%s',path="
95 LOGIND_SESSION_OBJ_TEMPLATE,
96 LOGIND_SESSION_INTERFACE,
97 si->session);
98 if (si->verbose)
99 syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals);
101 dbus_error_init(&error);
102 dbus_bus_add_match(si->dbus.system_connection,
103 si->dbus.match_session_signals,
104 &error);
105 if (dbus_error_is_set(&error)) {
106 syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
107 error.message);
108 dbus_error_free(&error);
109 g_free(si->dbus.match_session_signals);
110 si->dbus.match_session_signals = NULL;
114 static void
115 si_dbus_read_signals(struct session_info *si)
117 DBusMessage *message = NULL;
119 dbus_connection_read_write(si->dbus.system_connection, 0);
120 message = dbus_connection_pop_message(si->dbus.system_connection);
121 while (message != NULL) {
122 const char *member;
124 member = dbus_message_get_member (message);
125 if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
126 si->session_is_locked = TRUE;
127 } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
128 si->session_is_locked = FALSE;
129 } else {
130 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
131 syslog(LOG_WARNING, "(systemd-login) received non signal message");
132 } else if (si->verbose) {
133 syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member);
137 dbus_message_unref(message);
138 dbus_connection_read_write(si->dbus.system_connection, 0);
139 message = dbus_connection_pop_message(si->dbus.system_connection);
143 struct session_info *session_info_create(int verbose)
145 struct session_info *si;
146 int r;
148 si = calloc(1, sizeof(*si));
149 if (!si)
150 return NULL;
152 si->verbose = verbose;
153 si->session_is_locked = FALSE;
155 r = sd_login_monitor_new("session", &si->mon);
156 if (r < 0) {
157 syslog(LOG_ERR, "Error creating login monitor: %s", strerror(-r));
158 free(si);
159 return NULL;
162 si->dbus.system_connection = si_dbus_get_system_bus();
163 return si;
166 void session_info_destroy(struct session_info *si)
168 if (!si)
169 return;
171 si_dbus_match_remove(si);
172 dbus_connection_close(si->dbus.system_connection);
173 sd_login_monitor_unref(si->mon);
174 free(si->session);
175 free(si);
178 int session_info_get_fd(struct session_info *si)
180 return sd_login_monitor_get_fd(si->mon);
183 const char *session_info_get_active_session(struct session_info *si)
185 int r;
186 char *old_session = si->session;
188 si->session = NULL;
189 r = sd_seat_get_active("seat0", &si->session, NULL);
190 /* ENOENT happens when a seat is switching from one session to another */
191 if (r < 0 && r != -ENOENT)
192 syslog(LOG_ERR, "Error getting active session: %s",
193 strerror(-r));
195 if (si->verbose && si->session &&
196 (!old_session || strcmp(old_session, si->session)))
197 syslog(LOG_INFO, "Active session: %s", si->session);
199 sd_login_monitor_flush(si->mon);
200 free(old_session);
202 si_dbus_match_rule_update(si);
203 return si->session;
206 char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
208 int r;
209 char *session = NULL;
211 r = sd_pid_get_session(pid, &session);
212 if (r < 0)
213 syslog(LOG_ERR, "Error getting session for pid %u: %s",
214 pid, strerror(-r));
215 else if (si->verbose)
216 syslog(LOG_INFO, "Session for pid %u: %s", pid, session);
218 return session;
221 gboolean session_info_session_is_locked(struct session_info *si)
223 g_return_val_if_fail (si != NULL, FALSE);
225 /* We could also rely on IdleHint property from Session which seems to work
226 * well in rhel7 but it wasn't working well in my own system (F23). I'm
227 * convinced for now that Lock/Unlock signals should be enough but that
228 * means Lock/Unlock being done by logind. That might take a while.
229 * Check: https://bugzilla.gnome.org/show_bug.cgi?id=764773 */
231 si_dbus_read_signals(si);
232 return si->session_is_locked;