1 /* Unique - Single Instance Backendlication library
2  * uniquebackend-bacon.c: Unix domain socket implementation of UniqueBackend
3  *
4  * Copyright (C) 2007  Emmanuele Bassi  <ebassi@gnome.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  * Based on libbacon implementation in Totem
22  *      Copyright (C) 2003  Bastien Nocera
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <errno.h>
41 #include <glib/gstdio.h>
42 
43 #include "../uniqueinternals.h"
44 #include "uniquefactory-bacon.h"
45 #include "uniquemessage-bacon.h"
46 #include "uniquebackend-bacon.h"
47 
48 #ifndef UNIX_PATH_MAX
49 #define UNIX_PATH_MAX 108
50 #endif
51 
52 struct _UniqueBackendBacon
53 {
54   UniqueBackend parent_instance;
55 
56   gchar *socket_path;
57   gint socket_fd;
58 
59   GIOChannel *channel;
60   guint source_id;
61 
62   GSList *connections;
63 
64   guint is_server : 1;
65 };
66 
67 struct _UniqueBackendBaconClass
68 {
69   UniqueBackendClass parent_class;
70 };
71 
72 G_DEFINE_TYPE (UniqueBackendBacon, unique_backend_bacon, UNIQUE_TYPE_BACKEND);
73 
74 
75 static gboolean
is_socket(const gchar * path)76 is_socket (const gchar *path)
77 {
78   struct stat stat_buf;
79 
80   if (g_stat (path, &stat_buf) == -1)
81     return FALSE;
82 
83   return (S_ISSOCK (stat_buf.st_mode));
84 }
85 
86 static gboolean
is_socket_owned_by_user(const gchar * path)87 is_socket_owned_by_user (const gchar *path)
88 {
89   struct stat stat_buf;
90 
91   if (g_stat (path, &stat_buf) == -1)
92     return FALSE;
93 
94   return (S_ISSOCK (stat_buf.st_mode) && stat_buf.st_uid == geteuid ());
95 }
96 
97 /* free the return value */
98 static gchar *
find_file_with_pattern(const gchar * path,const gchar * pattern)99 find_file_with_pattern (const gchar *path,
100                         const gchar *pattern)
101 {
102   GDir *dir;
103   gchar *retval;
104   const gchar *file;
105   GPatternSpec *pat;
106 
107   dir = g_dir_open (path, 0, NULL);
108   if (!dir)
109     return NULL;
110 
111   pat = g_pattern_spec_new (pattern);
112   if (!pat)
113     {
114       g_dir_close (dir);
115       return NULL;
116     }
117 
118   retval = NULL;
119   while ((file = g_dir_read_name (dir)) != NULL)
120     {
121       if (g_pattern_match_string (pat, file))
122         {
123           gchar *temp = g_build_filename (path, file, NULL);
124 
125           if (is_socket_owned_by_user (temp))
126             {
127               retval = temp;
128               break;
129             }
130 
131           g_free (temp);
132         }
133     }
134 
135   g_pattern_spec_free (pat);
136   g_dir_close (dir);
137 
138   return retval;
139 }
140 
141 /* free the returned value */
142 static gchar *
find_socket_file(const gchar * name)143 find_socket_file (const gchar *name)
144 {
145   const gchar *token;
146   gchar *basename, *path;
147   gchar *tmpdir;
148 
149   /* socket file name template:
150    *   /tmp/unique/org.gnome.YourApplication.token.process-id
151    */
152   token = g_getenv ("DISPLAY");
153   if (!token || *token == '\0')
154     {
155       g_warning ("The $DISPLAY environment variable is not set. You must "
156                  "set it in order for the application '%s' to run correctly.",
157                  g_get_prgname ());
158       return NULL;
159     }
160 
161   basename = g_strconcat (name, ".", token, ".*", NULL);
162   tmpdir = g_build_path (G_DIR_SEPARATOR_S,
163                          g_get_tmp_dir (),
164                          "unique",
165                          NULL);
166 
167   if (g_mkdir_with_parents (tmpdir, 0777) == -1)
168     {
169       if (errno != EEXIST)
170         {
171           g_warning ("Unable to create socket path `%s': %s",
172                      tmpdir,
173                      g_strerror (errno));
174           return NULL;
175         }
176     }
177 
178   path = find_file_with_pattern (tmpdir, basename);
179   if (path)
180     {
181       g_free (tmpdir);
182       g_free (basename);
183 
184       return path;
185     }
186 
187   g_free (basename);
188 
189   basename = g_strdup_printf ("%s.%s.%d", name, token, getpid ());
190 
191   path = g_build_filename (tmpdir, basename, NULL);
192 
193   g_free (tmpdir);
194   g_free (basename);
195 
196   return path;
197 }
198 
199 static gboolean
server_socket_cb(GIOChannel * source,GIOCondition condition,gpointer data)200 server_socket_cb (GIOChannel   *source,
201                   GIOCondition  condition,
202                   gpointer      data)
203 {
204   UniqueBackendBacon *backend_bacon = data;
205 
206   if (!backend_bacon)
207     return FALSE;
208 
209   if (!backend_bacon->channel)
210     return FALSE;
211 
212   if (condition & G_IO_IN)
213     {
214       UniqueFactoryBacon *factory;
215 
216       factory = g_object_new (UNIQUE_TYPE_FACTORY_BACON, NULL);
217       factory->parent = UNIQUE_BACKEND (backend_bacon)->parent;
218 
219       if (unique_factory_bacon_accept (factory, backend_bacon->socket_fd))
220         backend_bacon->connections = g_slist_prepend (backend_bacon->connections, factory);
221       else
222         {
223           g_warning ("Could not accept the connection");
224           g_object_unref (factory);
225         }
226     }
227 
228   if (condition & G_IO_HUP)
229     g_debug (G_STRLOC ": factory hung up");
230   else if (condition & G_IO_ERR)
231     g_warning ("Server error");
232 
233   return TRUE;
234 }
235 
236 static gboolean
setup_connection(UniqueBackendBacon * backend_bacon)237 setup_connection (UniqueBackendBacon *backend_bacon)
238 {
239   g_assert (backend_bacon->socket_fd != -1);
240   g_assert (backend_bacon->channel == NULL);
241 
242   backend_bacon->channel = g_io_channel_unix_new (backend_bacon->socket_fd);
243   g_io_channel_set_line_term (backend_bacon->channel, "\r\n", 2);
244 
245   backend_bacon->source_id = g_io_add_watch (backend_bacon->channel,
246                                              G_IO_IN | G_IO_ERR | G_IO_HUP,
247                                              server_socket_cb,
248                                              backend_bacon);
249   return (backend_bacon->source_id > 0);
250 }
251 
252 static gboolean
try_client(UniqueBackendBacon * backend)253 try_client (UniqueBackendBacon *backend)
254 {
255   struct sockaddr_un uaddr;
256   size_t path_len;
257   int res;
258 
259   g_assert (backend->socket_path != NULL);
260 
261   path_len = MIN (strlen (backend->socket_path) + 1, UNIX_PATH_MAX);
262 
263   uaddr.sun_family = AF_UNIX;
264   strncpy (uaddr.sun_path, backend->socket_path, path_len);
265 
266   backend->socket_fd = socket (PF_UNIX, SOCK_STREAM, 0);
267 
268   res = connect (backend->socket_fd,
269                  (struct sockaddr *) &uaddr,
270                  sizeof (uaddr));
271 
272   if (res == -1)
273     {
274       backend->socket_fd = -1;
275       return FALSE;
276     }
277 
278   return TRUE;
279 }
280 
281 #define MAX_CONNECTIONS 5
282 
283 static void
create_server(UniqueBackendBacon * backend)284 create_server (UniqueBackendBacon *backend)
285 {
286   struct sockaddr_un uaddr;
287   size_t path_len;
288   int res;
289 
290   g_assert (backend->socket_path != NULL);
291 
292   path_len = MIN (strlen (backend->socket_path) + 1, UNIX_PATH_MAX);
293 
294   uaddr.sun_family = AF_UNIX;
295   strncpy (uaddr.sun_path, backend->socket_path, path_len);
296 
297   backend->socket_fd = socket (PF_UNIX, SOCK_STREAM, 0);
298   res = bind (backend->socket_fd, (struct sockaddr *) &uaddr, sizeof (uaddr));
299   if (res == -1)
300     {
301       backend->socket_fd = -1;
302       return;
303     }
304 
305   /* For security concern, the socket files should be set 700 */
306   g_chmod (backend->socket_path, 0700);
307 
308   listen (backend->socket_fd, MAX_CONNECTIONS);
309   setup_connection (backend);
310 }
311 
312 static void
unique_backend_bacon_close_connection(UniqueBackendBacon * backend)313 unique_backend_bacon_close_connection (UniqueBackendBacon *backend)
314 {
315   if (backend->source_id)
316     {
317       g_source_remove (backend->source_id);
318       backend->source_id = 0;
319     }
320 
321   if (backend->channel)
322     {
323       g_io_channel_shutdown (backend->channel, FALSE, NULL);
324       g_io_channel_unref (backend->channel);
325       backend->channel = NULL;
326     }
327 
328   if (backend->socket_fd != -1)
329     close (backend->socket_fd);
330 
331   if (g_unlink (backend->socket_path) == -1)
332     {
333       if (errno != ENOENT)
334         g_warning ("Unable to remove old socket file: %s",
335                    g_strerror (errno));
336     }
337 
338   g_slist_foreach (backend->connections, (GFunc) g_object_unref, NULL);
339   g_slist_free (backend->connections);
340 }
341 
342 static void
unique_backend_bacon_finalize(GObject * gobject)343 unique_backend_bacon_finalize (GObject *gobject)
344 {
345   UniqueBackendBacon *backend_bacon;
346 
347   backend_bacon = UNIQUE_BACKEND_BACON (gobject);
348 
349   if (backend_bacon->is_server || backend_bacon->connections)
350     unique_backend_bacon_close_connection (backend_bacon);
351 
352   g_free (backend_bacon->socket_path);
353 
354   G_OBJECT_CLASS (unique_backend_bacon_parent_class)->finalize (gobject);
355 }
356 
357 static UniqueResponse
unique_backend_bacon_send_message(UniqueBackend * backend,gint command_id,UniqueMessageData * message,guint time_)358 unique_backend_bacon_send_message (UniqueBackend     *backend,
359                                    gint               command_id,
360                                    UniqueMessageData *message,
361                                    guint              time_)
362 {
363   UniqueBackendBacon *backend_bacon;
364   UniqueResponse response_id;
365   gchar *packed, *response;
366   gsize packed_len;
367   GString *resp_buffer;
368   gsize res, term;
369   gchar buf;
370 
371   backend_bacon = UNIQUE_BACKEND_BACON (backend);
372 
373   if (!try_client (backend_bacon))
374     {
375       g_warning ("Unable to send message: no connection to the "
376                  "running instance found (stale named pipe)");
377 
378       /* force removal of the named pipe */
379       if (g_unlink (backend_bacon->socket_path) == -1)
380         {
381           if (errno != ENOENT)
382             {
383               g_warning ("Unable to remove stale named pipe: %s",
384                          g_strerror (errno));
385             }
386         }
387 
388       if (!try_client (backend_bacon))
389         return UNIQUE_RESPONSE_FAIL;
390     }
391 
392   packed = unique_message_data_pack (backend->parent,
393                                      command_id, message, time_,
394                                      &packed_len);
395   if (write (backend_bacon->socket_fd, packed, packed_len) == -1)
396     {
397       g_warning ("Unable to send message: %s", g_strerror (errno));
398       g_free (packed);
399 
400       return UNIQUE_RESPONSE_FAIL;
401     }
402   else
403     fsync (backend_bacon->socket_fd);
404 
405   g_free (packed);
406 
407   resp_buffer = g_string_new (NULL);
408   buf = term = res = 0;
409 
410   res = read (backend_bacon->socket_fd, &buf, 1);
411   while (res > 0 && buf != '\n')
412     {
413       resp_buffer = g_string_append_c (resp_buffer, buf);
414       term += res;
415 
416       res = read (backend_bacon->socket_fd, &buf, 1);
417       if (res < 0)
418         {
419           g_warning ("Unable to receive the response: %s", g_strerror (errno));
420 
421           close (backend_bacon->socket_fd);
422           backend_bacon->socket_fd = -1;
423 
424           g_string_free (resp_buffer, TRUE);
425 
426           return UNIQUE_RESPONSE_FAIL;
427         }
428     }
429 
430   response = g_string_free (resp_buffer, FALSE);
431   response[term - 1] = '\0';
432 
433   response_id = unique_response_from_string (response);
434 
435   g_free (response);
436 
437   return response_id;
438 }
439 
440 static gboolean
unique_backend_bacon_request_name(UniqueBackend * backend)441 unique_backend_bacon_request_name (UniqueBackend *backend)
442 {
443   UniqueBackendBacon *backend_bacon;
444   const gchar *name;
445 
446   g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), FALSE);
447 
448   name = unique_backend_get_name (backend);
449   g_assert (name != NULL);
450 
451   backend_bacon = UNIQUE_BACKEND_BACON (backend);
452 
453   g_assert (backend_bacon->socket_path == NULL);
454   backend_bacon->socket_path = find_socket_file (name);
455   if (!is_socket (backend_bacon->socket_path))
456     {
457       create_server (backend_bacon);
458       backend_bacon->is_server = TRUE;
459     }
460   else
461     {
462       if (!try_client (backend_bacon))
463         {
464           if (g_unlink (backend_bacon->socket_path) == -1)
465             {
466               if (errno != ENOENT)
467                 g_warning ("Unable to remove stale pipe: %s",
468                            g_strerror (errno));
469             }
470 
471           create_server (backend_bacon);
472           backend_bacon->is_server = TRUE;
473         }
474       else
475         backend_bacon->is_server = FALSE;
476     }
477 
478   return backend_bacon->is_server;
479 }
480 
481 static void
unique_backend_bacon_class_init(UniqueBackendBaconClass * klass)482 unique_backend_bacon_class_init (UniqueBackendBaconClass *klass)
483 {
484   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
485   UniqueBackendClass *backend_class = UNIQUE_BACKEND_CLASS (klass);
486 
487   gobject_class->finalize = unique_backend_bacon_finalize;
488 
489   backend_class->request_name = unique_backend_bacon_request_name;
490   backend_class->send_message = unique_backend_bacon_send_message;
491 }
492 
493 static void
unique_backend_bacon_init(UniqueBackendBacon * backend_bacon)494 unique_backend_bacon_init (UniqueBackendBacon *backend_bacon)
495 {
496   backend_bacon->is_server = FALSE;
497 
498   backend_bacon->socket_fd = -1;
499   backend_bacon->socket_path = NULL;
500 }
501