Cleanup of nonce code
[platform/upstream/dbus.git] / dbus / dbus-server-socket.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-server-socket.c Server implementation for sockets
3  *
4  * Copyright (C) 2002, 2003, 2004, 2006  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
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 2 of the License, or
11  * (at your option) any later version.
12  *
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.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-server-socket.h"
26 #include "dbus-transport-socket.h"
27 #include "dbus-connection-internal.h"
28 #include "dbus-string.h"
29
30 /**
31  * @defgroup DBusServerSocket DBusServer implementations for SOCKET
32  * @ingroup  DBusInternals
33  * @brief Implementation details of DBusServer on SOCKET
34  *
35  * @{
36  */
37 /**
38  * 
39  * Opaque object representing a Socket server implementation.
40  */
41 typedef struct DBusServerSocket DBusServerSocket;
42
43 /**
44  * Implementation details of DBusServerSocket. All members
45  * are private.
46  */
47 struct DBusServerSocket
48 {
49   DBusServer base;   /**< Parent class members. */
50   int n_fds;         /**< Number of active file handles */
51   int *fds;          /**< File descriptor or -1 if disconnected. */
52   DBusWatch **watch; /**< File descriptor watch. */
53   char *socket_name; /**< Name of domain socket, to unlink if appropriate */
54   DBusString noncefile; /**< Nonce file used to authenticate clients */
55 };
56
57 static void
58 socket_finalize (DBusServer *server)
59 {
60   DBusServerSocket *socket_server = (DBusServerSocket*) server;
61   int i;
62   
63   _dbus_server_finalize_base (server);
64
65   for (i = 0 ; i < socket_server->n_fds ; i++)
66     if (socket_server->watch[i])
67       {
68         _dbus_watch_unref (socket_server->watch[i]);
69         socket_server->watch[i] = NULL;
70       }
71   
72   dbus_free (socket_server->fds);
73   dbus_free (socket_server->watch);
74   dbus_free (socket_server->socket_name);
75   if (_dbus_string_get_length(&socket_server->noncefile) > 0)
76   {
77     _dbus_delete_file(&socket_server->noncefile, NULL);
78   }
79   _dbus_string_free (&socket_server->noncefile);
80   dbus_free (server);
81 }
82
83 /* Return value is just for memory, not other failures. */
84 static dbus_bool_t
85 handle_new_client_fd_and_unlock (DBusServer *server,
86                                  int         client_fd)
87 {
88   DBusConnection *connection;
89   DBusTransport *transport;
90   DBusNewConnectionFunction new_connection_function;
91   DBusServerSocket* socket_server;
92   void *new_connection_data;
93   
94   socket_server = (DBusServerSocket*)server;
95   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
96
97   HAVE_LOCK_CHECK (server);
98   
99   if (!_dbus_set_fd_nonblocking (client_fd, NULL))
100     {
101       SERVER_UNLOCK (server);
102       return TRUE;
103     }
104   
105   transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL);
106   if (transport == NULL)
107     {
108       _dbus_close_socket (client_fd, NULL);
109       SERVER_UNLOCK (server);
110       return FALSE;
111     }
112
113   if (!_dbus_transport_set_auth_mechanisms (transport,
114                                             (const char **) server->auth_mechanisms))
115     {
116       _dbus_transport_unref (transport);
117       SERVER_UNLOCK (server);
118       return FALSE;
119     }
120   
121   /* note that client_fd is now owned by the transport, and will be
122    * closed on transport disconnection/finalization
123    */
124   
125   connection = _dbus_connection_new_for_transport (transport);
126   _dbus_transport_unref (transport);
127   transport = NULL; /* now under the connection lock */
128   
129   if (connection == NULL)
130     {
131       SERVER_UNLOCK (server);
132       return FALSE;
133     }
134   
135   /* See if someone wants to handle this new connection, self-referencing
136    * for paranoia.
137    */
138   new_connection_function = server->new_connection_function;
139   new_connection_data = server->new_connection_data;
140
141   _dbus_server_ref_unlocked (server);
142   SERVER_UNLOCK (server);
143   
144   if (new_connection_function)
145     {
146       (* new_connection_function) (server, connection,
147                                    new_connection_data);
148     }
149   dbus_server_unref (server);
150   
151   /* If no one grabbed a reference, the connection will die. */
152   _dbus_connection_close_if_only_one_ref (connection);
153   dbus_connection_unref (connection);
154
155   return TRUE;
156 }
157
158 static dbus_bool_t
159 socket_handle_watch (DBusWatch    *watch,
160                    unsigned int  flags,
161                    void         *data)
162 {
163   DBusServer *server = data;
164 #ifndef DBUS_DISABLE_ASSERT
165   DBusServerSocket *socket_server = data;
166   int i;
167   dbus_bool_t found = FALSE;
168 #endif
169
170   SERVER_LOCK (server);
171   
172 #ifndef DBUS_DISABLE_ASSERT
173   for (i = 0 ; i < socket_server->n_fds ; i++)
174     {
175       if (socket_server->watch[i] == watch)
176         found = TRUE;
177     }
178   _dbus_assert (found);
179 #endif
180
181   _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
182   
183   if (flags & DBUS_WATCH_READABLE)
184     {
185       int client_fd;
186       int listen_fd;
187       
188       listen_fd = dbus_watch_get_socket (watch);
189
190       client_fd = _dbus_accept_with_noncefile (listen_fd, &socket_server->noncefile);
191       
192       if (client_fd < 0)
193         {
194           /* EINTR handled for us */
195           
196           if (_dbus_get_is_errno_eagain_or_ewouldblock ())
197             _dbus_verbose ("No client available to accept after all\n");
198           else
199             _dbus_verbose ("Failed to accept a client connection: %s\n",
200                            _dbus_strerror_from_errno ());
201
202           SERVER_UNLOCK (server);
203         }
204       else
205         {
206           if (!handle_new_client_fd_and_unlock (server, client_fd))
207             _dbus_verbose ("Rejected client connection due to lack of memory\n");
208         }
209     }
210
211   if (flags & DBUS_WATCH_ERROR)
212     _dbus_verbose ("Error on server listening socket\n");
213
214   if (flags & DBUS_WATCH_HANGUP)
215     _dbus_verbose ("Hangup on server listening socket\n");
216
217   return TRUE;
218 }
219   
220 static void
221 socket_disconnect (DBusServer *server)
222 {
223   DBusServerSocket *socket_server = (DBusServerSocket*) server;
224   int i;
225
226   HAVE_LOCK_CHECK (server);
227   
228   for (i = 0 ; i < socket_server->n_fds ; i++)
229     {
230       if (socket_server->watch[i])
231         {
232           _dbus_server_remove_watch (server,
233                                      socket_server->watch[i]);
234           _dbus_watch_unref (socket_server->watch[i]);
235           socket_server->watch[i] = NULL;
236         }
237
238       _dbus_close_socket (socket_server->fds[i], NULL);
239       socket_server->fds[i] = -1;
240     }
241
242   if (socket_server->socket_name != NULL)
243     {
244       DBusString tmp;
245       _dbus_string_init_const (&tmp, socket_server->socket_name);
246       _dbus_delete_file (&tmp, NULL);
247     }
248
249   HAVE_LOCK_CHECK (server);
250 }
251
252 static const DBusServerVTable socket_vtable = {
253   socket_finalize,
254   socket_disconnect
255 };
256
257 /**
258  * Creates a new server listening on the given file descriptor.  The
259  * file descriptor should be nonblocking (use
260  * _dbus_set_fd_nonblocking() to make it so). The file descriptor
261  * should be listening for connections, that is, listen() should have
262  * been successfully invoked on it. The server will use accept() to
263  * accept new client connections.
264  *
265  * @param fds list of file descriptors.
266  * @param n_fds number of file descriptors
267  * @param address the server's address
268  * @param noncefile the noncefile to use, NULL if without nonce
269  * @returns the new server, or #NULL if no memory.
270  * 
271  */
272 DBusServer*
273 _dbus_server_new_for_socket (int              *fds,
274                              int               n_fds,
275                              const DBusString *address,
276                              const DBusString *noncefile)
277 {
278   DBusServerSocket *socket_server;
279   DBusServer *server;
280   int i;
281   
282   socket_server = dbus_new0 (DBusServerSocket, 1);
283   if (socket_server == NULL)
284     return NULL;
285
286   socket_server->fds = dbus_new (int, n_fds);
287   if (!socket_server->fds)
288     goto failed_0;
289
290   socket_server->watch = dbus_new0 (DBusWatch *, n_fds);
291   if (!socket_server->watch)
292     goto failed_1;
293
294   for (i = 0 ; i < n_fds ; i++)
295     {
296       DBusWatch *watch;
297
298       watch = _dbus_watch_new (fds[i],
299                                DBUS_WATCH_READABLE,
300                                TRUE,
301                                socket_handle_watch, socket_server,
302                                NULL);
303       if (watch == NULL)
304         goto failed_2;
305
306       socket_server->n_fds++;
307       socket_server->fds[i] = fds[i];
308       socket_server->watch[i] = watch;
309     }
310
311   if (!_dbus_server_init_base (&socket_server->base,
312                                &socket_vtable, address))
313     goto failed_2;
314
315   if (!_dbus_string_init (&socket_server->noncefile))
316     goto failed_2;
317
318   if (noncefile && !_dbus_string_copy (noncefile, 0, &socket_server->noncefile, 0))
319     goto failed_3;
320
321   server = (DBusServer*)socket_server;
322
323   SERVER_LOCK (server);
324   
325   for (i = 0 ; i < n_fds ; i++)
326     {
327       if (!_dbus_server_add_watch (&socket_server->base,
328                                    socket_server->watch[i]))
329         {
330           int j;
331           for (j = 0 ; j < i ; j++)
332             _dbus_server_remove_watch (server,
333                                        socket_server->watch[j]);
334
335           SERVER_UNLOCK (server);
336           _dbus_server_finalize_base (&socket_server->base);
337           goto failed_2;
338         }
339     }
340
341   SERVER_UNLOCK (server);
342   
343   return (DBusServer*) socket_server;
344
345  failed_3:
346   _dbus_string_free (&socket_server->noncefile);
347  failed_2:
348   for (i = 0 ; i < n_fds ; i++)
349     {
350       if (socket_server->watch[i] != NULL)
351         {
352           _dbus_watch_unref (socket_server->watch[i]);
353           socket_server->watch[i] = NULL;
354         }
355     }
356   dbus_free (socket_server->watch);
357
358  failed_1:
359   dbus_free (socket_server->fds);
360
361  failed_0:
362   dbus_free (socket_server);
363   return NULL;
364 }
365
366 /**
367  * Creates a new server listening on TCP.
368  * If host is NULL, it will default to localhost.
369  * If bind is NULL, it will default to the value for the host
370  * parameter, and if that is NULL, then localhost
371  * If bind is a hostname, it will be resolved and will listen
372  * on all returned addresses.
373  * If family is NULL, hostname resolution will try all address
374  * families, otherwise it can be ipv4 or ipv6 to restrict the
375  * addresses considered.
376  *
377  * @param host the hostname to report for the listen address
378  * @param bind the hostname to listen on
379  * @param port the port to listen on or 0 to let the OS choose
380  * @param family 
381  * @param error location to store reason for failure.
382  * @returns the new server, or #NULL on failure.
383  */
384 DBusServer*
385 _dbus_server_new_for_tcp_socket (const char     *host,
386                                  const char     *bind,
387                                  const char     *port,
388                                  const char     *family,
389                                  DBusError      *error,
390                                  dbus_bool_t    use_nonce)
391 {
392   DBusServer *server;
393   int *listen_fds = NULL;
394   int nlisten_fds = 0, i;
395   DBusString address;
396   DBusString host_str;
397   DBusString port_str;
398   DBusString noncefile;
399   
400   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
401
402   if (!_dbus_string_init (&address))
403     {
404       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
405       return NULL;
406     }
407
408   if (!_dbus_string_init (&port_str))
409     {
410       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
411       goto failed_0;
412     }
413
414   if (host == NULL)
415     host = "localhost";
416
417   if (port == NULL)
418     port = "0";
419
420   if (bind == NULL)
421     bind = host;
422   else if (strcmp (bind, "*") == 0)
423     bind = NULL;
424
425   nlisten_fds =_dbus_listen_tcp_socket (bind, port, family,
426                                         &port_str,
427                                         &listen_fds, error);
428   if (nlisten_fds <= 0)
429     {
430       _DBUS_ASSERT_ERROR_IS_SET(error);
431       goto failed_1;
432     }
433
434   _dbus_string_init_const (&host_str, host);
435   if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") ||
436       !_dbus_address_append_escaped (&address, &host_str) ||
437       !_dbus_string_append (&address, ",port=") ||
438       !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str)))
439     {
440       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
441       goto failed_2;
442     }
443   if (family &&
444       (!_dbus_string_append (&address, ",family=") ||
445        !_dbus_string_append (&address, family)))
446     {
447       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
448       goto failed_2;
449     }
450   
451   if (!_dbus_string_init (&noncefile))
452     {
453       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
454       goto failed_2;
455     }
456
457   if (use_nonce)
458     {
459       if (!_dbus_generate_noncefilename (&noncefile))
460         {
461           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
462           goto failed_2;
463         }
464
465         if (_dbus_string_get_length(&noncefile) == 0 ||
466           !_dbus_string_append (&address, ",noncefile=") ||
467           !_dbus_address_append_escaped (&address, &noncefile))
468         {
469           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
470           goto failed_2;
471         }
472
473       if (!_dbus_generate_and_write_nonce (&noncefile, error))
474         {
475           goto failed_2;
476         }
477     }
478
479   server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, &noncefile);
480   if (server == NULL)
481     {
482       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
483       goto failed_2;
484     }
485
486   _dbus_string_free (&port_str);
487   _dbus_string_free (&address);
488   dbus_free(listen_fds);
489
490   return server;
491
492  failed_2:
493   for (i = 0 ; i < nlisten_fds ; i++)
494     _dbus_close_socket (listen_fds[i], NULL);
495   dbus_free(listen_fds);
496   _dbus_string_free (&noncefile);
497
498  failed_1:
499   _dbus_string_free (&port_str);
500
501  failed_0:
502   _dbus_string_free (&address);
503
504   return NULL;
505 }
506
507 /**
508  * Tries to interpret the address entry for various socket-related
509  * addresses (well, currently only tcp and nonce-tcp).
510  * 
511  * Sets error if the result is not OK.
512  * 
513  * @param entry an address entry
514  * @param server_p a new DBusServer, or #NULL on failure.
515  * @param error location to store rationale for failure on bad address
516  * @returns the outcome
517  * 
518  */
519 DBusServerListenResult
520 _dbus_server_listen_socket (DBusAddressEntry *entry,
521                             DBusServer      **server_p,
522                             DBusError        *error)
523 {
524   const char *method;
525
526   *server_p = NULL;
527   
528   method = dbus_address_entry_get_method (entry);
529   
530   if (strcmp (method, "tcp") == 0 || strcmp (method, "nonce-tcp") == 0)
531     {
532       const char *host;
533       const char *port;
534       const char *bind;
535       const char *family;
536
537       host = dbus_address_entry_get_value (entry, "host");
538       bind = dbus_address_entry_get_value (entry, "bind");
539       port = dbus_address_entry_get_value (entry, "port");
540       family = dbus_address_entry_get_value (entry, "family");
541
542       *server_p = _dbus_server_new_for_tcp_socket (host, bind, port,
543                                                    family, error, strcmp (method, "nonce-tcp") == 0 ? TRUE : FALSE);
544
545       if (*server_p)
546         {
547           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
548           return DBUS_SERVER_LISTEN_OK;
549         }
550       else
551         {
552           _DBUS_ASSERT_ERROR_IS_SET(error);
553           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
554         }
555     }
556   else
557     {
558       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
559       return DBUS_SERVER_LISTEN_NOT_HANDLED;
560     }
561 }
562
563 /**
564  * This is a bad hack since it's really unix domain socket
565  * specific. Also, the function weirdly adopts ownership
566  * of the passed-in string.
567  * 
568  * @param server a socket server
569  * @param filename socket filename to report/delete
570  * 
571  */
572 void
573 _dbus_server_socket_own_filename (DBusServer *server,
574                                   char       *filename)
575 {
576   DBusServerSocket *socket_server = (DBusServerSocket*) server;
577
578   socket_server->socket_name = filename;
579 }
580
581
582 /** @} */
583