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