1 /* $Id$ */
2 /*-
3 * Copyright (c) 2004-2005 Benedikt Meurer <benny@xfce.org>
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA.
20 *
21 * Most parts of this file where taken from gnome-session.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #endif
34
35 #ifdef HAVE_SIGNAL_H
36 #include <signal.h>
37 #endif
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50
51 #ifdef HAVE_ERRNO_H
52 #include <errno.h>
53 #endif
54
55 #include <X11/Xatom.h>
56 #include <X11/Xlib.h>
57
58 #include <gdk/gdkx.h>
59
60 #include <libxfce4util/libxfce4util.h>
61
62 #include <xfce4-session/xfsm-compat-gnome.h>
63
64 #define GNOME_KEYRING_DAEMON "gnome-keyring-daemon"
65
66
67 static gboolean gnome_compat_started = FALSE;
68 static int keyring_lifetime_pipe[2];
69 static pid_t gnome_keyring_daemon_pid = 0;
70 static Window gnome_smproxy_window = None;
71
72 static void
child_setup(gpointer user_data)73 child_setup (gpointer user_data)
74 {
75 gint open_max;
76 gint fd;
77 char *fd_str;
78 int ret;
79
80 open_max = sysconf (_SC_OPEN_MAX);
81 for (fd = 3; fd < open_max; fd++)
82 {
83 if (fd != keyring_lifetime_pipe[0])
84 {
85 ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
86 /* We end up trying to close a lot of non-existant FDs here */
87 if (ret == -1 && errno != EBADF)
88 {
89 perror ("child_setup: fcntl (fd, F_SETFD, FD_CLOEXEC) failed");
90 }
91 }
92 }
93
94 fd_str = g_strdup_printf ("%d", keyring_lifetime_pipe[0]);
95 g_setenv ("GNOME_KEYRING_LIFETIME_FD", fd_str, TRUE);
96 g_free (fd_str);
97 }
98
99
100 static void
gnome_keyring_daemon_startup(void)101 gnome_keyring_daemon_startup (void)
102 {
103 GError *error = NULL;
104 gchar *sout;
105 gchar **lines;
106 gsize lineno;
107 gint status;
108 glong pid;
109 gchar *end;
110 gchar *argv[3];
111 gchar *p;
112 gchar *name;
113 const gchar *value;
114
115 /* Pipe to slave keyring lifetime to */
116 if (pipe (keyring_lifetime_pipe))
117 {
118 g_warning ("Failed to set up pipe for gnome-keyring: %s", strerror (errno));
119 return;
120 }
121
122 error = NULL;
123 argv[0] = GNOME_KEYRING_DAEMON;
124 argv[1] = "--start";
125 argv[2] = NULL;
126 g_spawn_sync (NULL, argv, NULL,
127 G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
128 child_setup, NULL,
129 &sout, NULL, &status, &error);
130
131 close (keyring_lifetime_pipe[0]);
132 /* We leave keyring_lifetime_pipe[1] open for the lifetime of the session,
133 in order to slave the keyring daemon lifecycle to the session. */
134
135 if (error != NULL)
136 {
137 g_printerr ("Failed to run gnome-keyring-daemon: %s\n",
138 error->message);
139 g_error_free (error);
140 }
141 else
142 {
143 if (WIFEXITED (status) && WEXITSTATUS (status) == 0 && sout != NULL)
144 {
145 lines = g_strsplit (sout, "\n", 0);
146
147 for (lineno = 0; lines[lineno] != NULL; lineno++)
148 {
149 p = strchr (lines[lineno], '=');
150 if (p == NULL)
151 continue;
152
153 name = g_strndup (lines[lineno], p - lines[lineno]);
154 value = p + 1;
155
156 g_setenv (name, value, TRUE);
157
158 if (g_strcmp0 (name, "GNOME_KEYRING_PID") == 0)
159 {
160 pid = strtol (value, &end, 10);
161 if (end != value)
162 gnome_keyring_daemon_pid = pid;
163 }
164
165 g_free (name);
166 }
167
168 g_strfreev (lines);
169 }
170 else
171 {
172 /* daemon failed for some reason */
173 g_printerr ("gnome-keyring-daemon failed to start correctly, "
174 "exit code: %d\n", WEXITSTATUS (status));
175 }
176
177 g_free (sout);
178 }
179 }
180
181 static void
gnome_keyring_daemon_shutdown(void)182 gnome_keyring_daemon_shutdown (void)
183 {
184 if (gnome_keyring_daemon_pid != 0)
185 {
186 kill (gnome_keyring_daemon_pid, SIGTERM);
187 gnome_keyring_daemon_pid = 0;
188 }
189 }
190
191
192
193 static void
xfsm_compat_gnome_smproxy_startup(void)194 xfsm_compat_gnome_smproxy_startup (void)
195 {
196 Atom gnome_sm_proxy;
197 Display *dpy;
198 Window root;
199
200 gdk_error_trap_push ();
201
202 /* Set GNOME_SM_PROXY property, since some apps (like OOo) seem to require
203 * it to behave properly. Thanks to Jasper/Francois for reporting this.
204 * This has another advantage, since it prevents people from running
205 * gnome-smproxy in xfce4, which would cause trouble otherwise.
206 */
207 dpy = gdk_x11_get_default_xdisplay ();
208 root = RootWindow (dpy, 0);
209
210 if (gnome_smproxy_window != None)
211 XDestroyWindow (dpy, gnome_smproxy_window);
212
213 gnome_sm_proxy = XInternAtom (dpy, "GNOME_SM_PROXY", False);
214 gnome_smproxy_window = XCreateSimpleWindow (dpy, root, 1, 1, 1, 1, 0, 0, 0);
215
216 XChangeProperty (dpy, gnome_smproxy_window, gnome_sm_proxy,
217 XA_CARDINAL, 32, PropModeReplace,
218 (unsigned char *) (void *) &gnome_smproxy_window, 1);
219 XChangeProperty (dpy, root, gnome_sm_proxy,
220 XA_CARDINAL, 32, PropModeReplace,
221 (unsigned char *) (void *) &gnome_smproxy_window, 1);
222
223 XSync (dpy, False);
224
225 gdk_error_trap_pop_ignored ();
226 }
227
228
229 static void
xfsm_compat_gnome_smproxy_shutdown(void)230 xfsm_compat_gnome_smproxy_shutdown (void)
231 {
232 gdk_error_trap_push ();
233
234 if (gnome_smproxy_window != None)
235 {
236 XDestroyWindow (gdk_x11_get_default_xdisplay (), gnome_smproxy_window);
237 XSync (gdk_x11_get_default_xdisplay (), False);
238 gnome_smproxy_window = None;
239 }
240
241 gdk_error_trap_pop_ignored ();
242 }
243
244
245 void
xfsm_compat_gnome_startup(void)246 xfsm_compat_gnome_startup (void)
247 {
248 if (G_UNLIKELY (gnome_compat_started))
249 return;
250
251 xfsm_compat_gnome_smproxy_startup ();
252
253 /* fire up the keyring daemon */
254 gnome_keyring_daemon_startup ();
255
256 gnome_compat_started = TRUE;
257 }
258
259
260 void
xfsm_compat_gnome_shutdown(void)261 xfsm_compat_gnome_shutdown (void)
262 {
263 if (G_UNLIKELY (!gnome_compat_started))
264 return;
265
266 /* shutdown the keyring daemon */
267 gnome_keyring_daemon_shutdown ();
268
269 xfsm_compat_gnome_smproxy_shutdown ();
270
271 gnome_compat_started = FALSE;
272 }
273